Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package com.instructure.teacher.ui.e2e.classic
import android.os.Environment
import android.util.Log
import androidx.test.espresso.Espresso
import androidx.test.uiautomator.UiSelector
import com.instructure.canvas.espresso.FeatureCategory
import com.instructure.canvas.espresso.Priority
import com.instructure.canvas.espresso.TestCategory
Expand Down Expand Up @@ -151,13 +152,74 @@ class FilesE2ETest: TeacherComposeTest() {
Log.d(ASSERTION_TAG, "Assert that the '${submissionUploadInfo.fileName}' file has selected.")
speedGraderPage.assertSelectedAttachmentItemDisplayed(submissionUploadInfo.fileName)

//TODO: Re-enable this and refactor when comments will be ready.
/*Log.d(STEP_TAG, "Select 'Comments' tab")
speedGraderPage.selectCommentsTab()
Log.d(ASSERTION_TAG, "Assert that Comments label is displayed with value '1' because only 1 comment was seeded.")
speedGraderPage.assertCommentsLabelDisplayed(1)

Log.d(ASSERTION_TAG, "Assert that '${commentUploadInfo.fileName}' comment attachment is displayed.")
speedGraderPage.assertCommentAttachmentDisplayedCommon(commentUploadInfo.fileName, student.shortName)
*/
speedGraderPage.assertCommentAttachmentDisplayed(commentUploadInfo.fileName)

Log.d(PREPARATION_TAG, "Create a PDF file for comment attachment test.")
val pdfFileName = "test_comment_${System.currentTimeMillis()}.pdf"
val pdfFile = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), pdfFileName)
pdfFile.createNewFile()

Log.d(PREPARATION_TAG, "Write content to PDF file '${pdfFile.name}'.")
android.graphics.pdf.PdfDocument().apply {
val pageInfo = android.graphics.pdf.PdfDocument.PageInfo.Builder(300, 300, 1).create()
val page = startPage(pageInfo)
val canvas = page.canvas
val paint = android.graphics.Paint()
paint.color = android.graphics.Color.BLACK
paint.textSize = 12f
canvas.drawText("Test PDF Comment Attachment", 10f, 25f, paint)
finishPage(page)
writeTo(java.io.FileOutputStream(pdfFile))
close()
}

Log.d(STEP_TAG, "Click on comment attachment button.")
speedGraderPage.clickCommentAttachmentButton()

Log.d(STEP_TAG, "Select 'Choose Files' from attachment type dialog.")
speedGraderPage.clickChooseFilesOption()

Log.d(STEP_TAG, "Select 'Device' as file source.")
fileChooserPage.chooseDevice()

Log.d(STEP_TAG, "Select the PDF file from Android file picker using UIAutomator.")
val pdfFileObject = device.findObject(UiSelector().textContains(pdfFileName))
if (pdfFileObject.exists()) {
Log.d(STEP_TAG, "Found PDF file with exact name, clicking...")
pdfFileObject.click()
} else {
Log.d(STEP_TAG, "PDF file not immediately visible, trying to navigate to Downloads...")
val showRootsButton = device.findObject(UiSelector().descriptionContains("Show roots"))
if (showRootsButton.exists()) {
showRootsButton.click()
}

val downloadsItem = device.findObject(UiSelector().textContains("Downloads"))
if (downloadsItem.exists()) {
downloadsItem.click()
}

val pdfFileObject2 = device.findObject(UiSelector().textContains(pdfFileName))
if (pdfFileObject2.exists()) {
pdfFileObject2.click()
}
}
device.waitForIdle()

Log.d(STEP_TAG, "Click 'UPLOAD' button.")
fileChooserPage.clickUpload()
Thread.sleep(5000) // Wait for upload to complete and comment to be sent

Log.d(ASSERTION_TAG, "Assert that PDF comment attachment '${pdfFile.name}' is displayed.")
speedGraderPage.assertCommentAttachmentDisplayed(pdfFile.name)

Log.d(ASSERTION_TAG, "Assert that Comments label is displayed with value '2' because a new comment was added.")
speedGraderPage.assertCommentsLabelDisplayed(2)

Log.d(STEP_TAG, "Navigate back to Dashboard Page.")
pressBackButton(5)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright (C) 2025 - present Instructure, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.instructure.teacher.ui.pages.classic

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.hasSibling
import androidx.test.espresso.matcher.ViewMatchers.withChild
import com.instructure.canvas.espresso.containsTextCaseInsensitive
import com.instructure.espresso.OnViewWithId
import com.instructure.espresso.WaitForViewWithId
import com.instructure.espresso.assertDisplayed
import com.instructure.espresso.assertHasText
import com.instructure.espresso.click
import com.instructure.espresso.matchers.WaitForViewMatcher.waitForViewToBeClickable
import com.instructure.espresso.page.BasePage
import com.instructure.espresso.page.plus
import com.instructure.espresso.page.withDescendant
import com.instructure.espresso.page.withId
import com.instructure.espresso.page.withParent
import com.instructure.espresso.page.withText
import com.instructure.espresso.scrollTo
import com.instructure.teacher.R

class FileChooserPage : BasePage() {
private val cameraButton by OnViewWithId(R.id.fromCamera)
private val galleryButton by OnViewWithId(R.id.fromGallery)
private val deviceButton by OnViewWithId(R.id.fromDevice)
private val chooseFileTitle by OnViewWithId(R.id.chooseFileTitle)
private val chooseFileSubtitle by OnViewWithId(R.id.chooseFileSubtitle)
private val fileChooserTitle by WaitForViewWithId(R.id.alertTitle)

fun assertFileChooserDetails() {
chooseFileTitle.assertDisplayed().assertHasText(R.string.chooseFile)
chooseFileSubtitle.assertDisplayed().assertHasText(R.string.chooseFileForUploadSubtext)
cameraButton.assertDisplayed()
galleryButton.assertDisplayed()
deviceButton.assertDisplayed()
}

fun chooseCamera() {
cameraButton.scrollTo().click()
}

fun chooseGallery() {
galleryButton.scrollTo().click()
}

fun chooseDevice() {
deviceButton.scrollTo().click()
}

fun clickUpload() {
onView(withText(R.string.upload)).click()
}

fun clickTurnIn() {
onView(withText(R.string.turnIn)).click()
}

fun clickCancel() {
onView(withText(R.string.cancel)).click()
}

fun removeFile(filename: String) {
val fileItemMatcher = withId(R.id.fileItem) + withDescendant(withId(R.id.fileName) + containsTextCaseInsensitive(filename))

val removeMatcher = withId(R.id.removeFile) + ViewMatchers.isDescendantOfA(fileItemMatcher)
waitForViewToBeClickable(removeMatcher).scrollTo().click()
}

fun assertDialogTitle(title: String) {
fileChooserTitle.assertHasText(title)
}

fun assertFileDisplayed(filename: String) {
val fileNameMatcher = withId(R.id.fileName) + withText(filename)
onView(fileNameMatcher).assertDisplayed()
onView(withId(R.id.fileSize) + hasSibling(fileNameMatcher)).assertDisplayed()
onView(withId(R.id.fileIcon) + withParent(withId(R.id.iconWrapper) + hasSibling(withId(R.id.content) + withChild(fileNameMatcher)))).assertDisplayed()
onView(withId(R.id.removeFile) + hasSibling(withId(R.id.content) + withChild(fileNameMatcher))).assertDisplayed()
}

fun assertFileNotDisplayed(filename: String) {
onView(withId(R.id.fileName) + withText(filename)).check(doesNotExist())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,17 @@ class SpeedGraderPage(private val composeTestRule: ComposeTestRule) : BasePage()
fun clickCommentAttachmentButton() {
composeTestRule
.onNodeWithTag("commentAttachmentButton")
.performScrollTo()
.performClick()
composeTestRule.waitForIdle()
}

/**
* Clicks the "Choose Files" option in the attachment type selection dialog.
*/
fun clickChooseFilesOption() {
composeTestRule
.onNodeWithText(getStringFromResource(R.string.choose_files))
.performClick()
composeTestRule.waitForIdle()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import com.instructure.teacher.ui.pages.classic.EditPageDetailsPage
import com.instructure.teacher.ui.pages.classic.EditProfileSettingsPage
import com.instructure.teacher.ui.pages.classic.EditQuizDetailsPage
import com.instructure.teacher.ui.pages.classic.EditSyllabusPage
import com.instructure.teacher.ui.pages.classic.FileChooserPage
import com.instructure.teacher.ui.pages.classic.FileListPage
import com.instructure.teacher.ui.pages.classic.HelpPage
import com.instructure.teacher.ui.pages.classic.LeftSideNavigationDrawerPage
Expand Down Expand Up @@ -147,6 +148,7 @@ abstract class TeacherTest : CanvasTest() {
val webViewLoginPage = WebViewLoginPage()
val fileListPage = FileListPage(Searchable(R.id.search, R.id.queryInput, R.id.clearButton, R.id.backButton))
val updateFilePermissionsPage = UpdateFilePermissionsPage()
val fileChooserPage = FileChooserPage()

@Before
fun setupWorkerFactory() {
Expand Down
Loading