Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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
1 change: 1 addition & 0 deletions apps/student/src/androidTest/assets/test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is a test file for assignment submission.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@
*/
package com.instructure.student.ui.interaction

import android.net.Uri
import androidx.compose.ui.platform.ComposeView
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.withId
import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils
import com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck
import com.instructure.canvas.espresso.FeatureCategory
Expand All @@ -31,6 +35,7 @@ import com.instructure.canvas.espresso.mockcanvas.addAssignmentsToGroups
import com.instructure.canvas.espresso.mockcanvas.addSubmissionForAssignment
import com.instructure.canvas.espresso.mockcanvas.fakes.FakeCustomGradeStatusesManager
import com.instructure.canvas.espresso.mockcanvas.init
import com.instructure.canvas.espresso.refresh
import com.instructure.canvasapi2.di.graphql.CustomGradeStatusModule
import com.instructure.canvasapi2.managers.graphql.CustomGradeStatusesManager
import com.instructure.canvasapi2.models.Assignment
Expand All @@ -49,6 +54,7 @@ import dagger.hilt.android.testing.UninstallModules
import org.hamcrest.Matchers
import org.junit.Assert.assertNotNull
import org.junit.Test
import java.io.File
import java.util.Calendar

@HiltAndroidTest
Expand All @@ -63,9 +69,7 @@ class AssignmentDetailsInteractionTest : StudentComposeTest() {

@Test
@TestMetaData(Priority.MANDATORY, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, SecondaryFeatureCategory.SUBMISSIONS_ONLINE_URL)
fun testSubmission_submitAssignment() {
// TODO - Test submitting for each submission type
// For now, I'm going to just test one submission type
fun testSubmission_submitOnlineURL() {
val data = MockCanvas.init(
studentCount = 1,
courseCount = 1
Expand All @@ -89,6 +93,266 @@ class AssignmentDetailsInteractionTest : StudentComposeTest() {
assignmentDetailsPage.assertStatusSubmitted()
}

@Test
@TestMetaData(Priority.MANDATORY, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, SecondaryFeatureCategory.SUBMISSIONS_TEXT_ENTRY)
fun testSubmission_submitTextEntry() {
val data = MockCanvas.init(
studentCount = 1,
courseCount = 1
)

val course = data.courses.values.first()
val student = data.students[0]
val token = data.tokenFor(student)!!
val assignment = data.addAssignment(courseId = course.id, submissionTypeList = listOf(Assignment.SubmissionType.ONLINE_TEXT_ENTRY))
data.addSubmissionForAssignment(
assignmentId = assignment.id,
userId = data.users.values.first().id,
type = Assignment.SubmissionType.ONLINE_TEXT_ENTRY.apiString
)
tokenLogin(data.domain, token, student)
routeTo("courses/${course.id}/assignments", data.domain)

assignmentListPage.clickAssignment(assignment)
assignmentDetailsPage.clickSubmit()
textSubmissionUploadPage.typeText("This is my test submission text.")
textSubmissionUploadPage.clickOnSubmitButton()
assignmentDetailsPage.assertStatusSubmitted()
}

@Test
@TestMetaData(Priority.MANDATORY, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, SecondaryFeatureCategory.SUBMISSIONS_FILE_UPLOAD)
fun testSubmission_submitFileUpload() {
val data = MockCanvas.init(
studentCount = 1,
courseCount = 1
)

val course = data.courses.values.first()
val student = data.students[0]
val token = data.tokenFor(student)!!
val assignment = data.addAssignment(courseId = course.id, submissionTypeList = listOf(Assignment.SubmissionType.ONLINE_UPLOAD))
data.addSubmissionForAssignment(
assignmentId = assignment.id,
userId = data.users.values.first().id,
type = Assignment.SubmissionType.ONLINE_UPLOAD.apiString
)
tokenLogin(data.domain, token, student)
routeTo("courses/${course.id}/assignments", data.domain)

val fileName = "test.txt"
androidx.test.espresso.intent.Intents.init()
try {
stubFilePickerIntent(fileName)
setupFileOnDevice(fileName)

assignmentListPage.clickAssignment(assignment)
assignmentDetailsPage.clickSubmit()
pickerSubmissionUploadPage.chooseDevice()
pickerSubmissionUploadPage.waitForSubmitButtonToAppear()
pickerSubmissionUploadPage.assertFileDisplayed(fileName)
pickerSubmissionUploadPage.submit()
assignmentDetailsPage.assertStatusSubmitted()
} finally {
androidx.test.espresso.intent.Intents.release()
}
}

@Test
@TestMetaData(Priority.MANDATORY, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, SecondaryFeatureCategory.SUBMISSIONS_MEDIA_RECORDING)
fun testSubmission_submitMediaRecordingChooseMediaFile() {
val data = MockCanvas.init(
studentCount = 1,
courseCount = 1
)

val course = data.courses.values.first()
val student = data.students[0]
val token = data.tokenFor(student)!!
val assignment = data.addAssignment(courseId = course.id, submissionTypeList = listOf(Assignment.SubmissionType.MEDIA_RECORDING))
data.addSubmissionForAssignment(
assignmentId = assignment.id,
userId = data.users.values.first().id,
type = Assignment.SubmissionType.MEDIA_RECORDING.apiString
)
tokenLogin(data.domain, token, student)
routeTo("courses/${course.id}/assignments", data.domain)

val activity = activityRule.activity

androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().uiAutomation.grantRuntimePermission(
activity.packageName,
android.Manifest.permission.CAMERA
)
androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().uiAutomation.grantRuntimePermission(
activity.packageName,
android.Manifest.permission.RECORD_AUDIO
)

val fileName = "test_video.mp4"
copyAssetFileToExternalCache(activity, fileName)

val resultData = android.content.Intent()
val dir = activity.externalCacheDir
val file = File(dir?.path, fileName)
val uri = Uri.fromFile(file)
resultData.data = uri
val activityResult = android.app.Instrumentation.ActivityResult(android.app.Activity.RESULT_OK, resultData)

androidx.test.espresso.intent.Intents.init()
try {
androidx.test.espresso.intent.Intents.intending(
Matchers.anyOf(
androidx.test.espresso.intent.matcher.IntentMatchers.hasAction(android.content.Intent.ACTION_GET_CONTENT),
androidx.test.espresso.intent.matcher.IntentMatchers.hasAction(android.content.Intent.ACTION_PICK),
androidx.test.espresso.intent.matcher.IntentMatchers.hasAction(android.content.Intent.ACTION_OPEN_DOCUMENT)
)
).respondWith(activityResult)

assignmentListPage.clickAssignment(assignment)
assignmentDetailsPage.clickSubmit()

onView(withId(R.id.submissionEntryMediaFile)).perform(click())

pickerSubmissionUploadPage.waitForSubmitButtonToAppear()
pickerSubmissionUploadPage.assertFileDisplayed(fileName)
pickerSubmissionUploadPage.submit()
assignmentDetailsPage.assertStatusSubmitted()
} finally {
androidx.test.espresso.intent.Intents.release()
}
}

@Test
@TestMetaData(Priority.MANDATORY, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, SecondaryFeatureCategory.SUBMISSIONS_MEDIA_RECORDING)
fun testSubmission_submitMediaRecordingRecordVideo() {
val data = MockCanvas.init(
studentCount = 1,
courseCount = 1
)

val course = data.courses.values.first()
val student = data.students[0]
val token = data.tokenFor(student)!!
val assignment = data.addAssignment(courseId = course.id, submissionTypeList = listOf(Assignment.SubmissionType.MEDIA_RECORDING))
data.addSubmissionForAssignment(
assignmentId = assignment.id,
userId = data.users.values.first().id,
type = Assignment.SubmissionType.MEDIA_RECORDING.apiString
)
tokenLogin(data.domain, token, student)
routeTo("courses/${course.id}/assignments", data.domain)

val activity = activityRule.activity

androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().uiAutomation.grantRuntimePermission(
activity.packageName,
android.Manifest.permission.CAMERA
)
androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().uiAutomation.grantRuntimePermission(
activity.packageName,
android.Manifest.permission.RECORD_AUDIO
)

val testVideoFile = "test_video.mp4"
copyAssetFileToExternalCache(activity, testVideoFile)

var capturedVideoUri: Uri? = null

androidx.test.espresso.intent.Intents.init()
androidx.test.espresso.intent.Intents.intending(
Matchers.allOf(
androidx.test.espresso.intent.matcher.IntentMatchers.hasAction(android.provider.MediaStore.ACTION_VIDEO_CAPTURE),
androidx.test.espresso.intent.matcher.IntentMatchers.hasExtraWithKey(android.provider.MediaStore.EXTRA_OUTPUT)
)
).respondWithFunction { intent ->
val outputUri = intent.extras?.get(android.provider.MediaStore.EXTRA_OUTPUT) as? Uri
capturedVideoUri = outputUri
if (outputUri != null) {
val context = androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().targetContext
val dir = context.externalCacheDir
val sampleFile = File(dir, testVideoFile)
if (outputUri.scheme == "file") {
val destFile = File(outputUri.path!!)
destFile.parentFile?.mkdirs()
sampleFile.copyTo(destFile, overwrite = true)
} else if (outputUri.scheme == "content") {
context.contentResolver.openOutputStream(outputUri)?.use { outputStream ->
sampleFile.inputStream().use { inputStream ->
inputStream.copyTo(outputStream)
}
}
}
}
android.app.Instrumentation.ActivityResult(android.app.Activity.RESULT_OK, android.content.Intent())
}

assignmentListPage.clickAssignment(assignment)
assignmentDetailsPage.clickSubmit()
onView(withId(R.id.submissionEntryVideo)).perform(click())

androidx.test.espresso.intent.Intents.release()

pickerSubmissionUploadPage.waitForSubmitButtonToAppear()

val fileName = File(capturedVideoUri!!.path!!).name
pickerSubmissionUploadPage.assertFileDisplayed(fileName)
pickerSubmissionUploadPage.submit()

assignmentDetailsPage.assertStatusSubmitted()
}

@Test
@TestMetaData(Priority.MANDATORY, FeatureCategory.SUBMISSIONS, TestCategory.INTERACTION, SecondaryFeatureCategory.SUBMISSIONS_MEDIA_RECORDING)
fun testSubmission_submitMediaRecordingRecordAudio() {
val data = MockCanvas.init(
studentCount = 1,
courseCount = 1
)

val course = data.courses.values.first()
val student = data.students[0]
val token = data.tokenFor(student)!!
val assignment = data.addAssignment(courseId = course.id, submissionTypeList = listOf(Assignment.SubmissionType.MEDIA_RECORDING))
data.addSubmissionForAssignment(
assignmentId = assignment.id,
userId = data.users.values.first().id,
type = Assignment.SubmissionType.MEDIA_RECORDING.apiString
)
tokenLogin(data.domain, token, student)
routeTo("courses/${course.id}/assignments", data.domain)

val activity = activityRule.activity

androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().uiAutomation.grantRuntimePermission(
activity.packageName,
android.Manifest.permission.RECORD_AUDIO
)

val testAudioFileName = "test_audio.mp3"
copyAssetFileToExternalCache(activity, testAudioFileName)

val context = androidx.test.platform.app.InstrumentationRegistry.getInstrumentation().targetContext
val recordingFile = File(context.externalCacheDir, "audio.amr")
val testAudioFile = File(context.externalCacheDir, testAudioFileName)
testAudioFile.copyTo(recordingFile, overwrite = true)

assignmentListPage.clickAssignment(assignment)
assignmentDetailsPage.clickSubmit()
onView(withId(R.id.submissionEntryAudio)).perform(click())

device.findObject(androidx.test.uiautomator.UiSelector().resourceIdMatches(".*recordAudioButton")).click()

testAudioFile.copyTo(recordingFile, overwrite = true)

device.findObject(androidx.test.uiautomator.UiSelector().resourceIdMatches(".*stopButton")).click()

device.findObject(androidx.test.uiautomator.UiSelector().resourceIdMatches(".*sendAudioButton")).click()

refresh()
assignmentDetailsPage.assertStatusSubmitted()
}

@Test
@TestMetaData(Priority.MANDATORY, FeatureCategory.ASSIGNMENTS, TestCategory.INTERACTION)
fun testSubmissionStatus_NotSubmitted() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ enum class FeatureCategory {

enum class SecondaryFeatureCategory {
NONE, LOGIN_K5,
SUBMISSIONS_TEXT_ENTRY, SUBMISSIONS_ANNOTATIONS, SUBMISSIONS_ONLINE_URL, SUBMISSIONS_MULTIPLE_TYPE,
SUBMISSIONS_TEXT_ENTRY, SUBMISSIONS_ANNOTATIONS, SUBMISSIONS_ONLINE_URL, SUBMISSIONS_MULTIPLE_TYPE, SUBMISSIONS_FILE_UPLOAD, SUBMISSIONS_MEDIA_RECORDING,
ASSIGNMENT_COMMENTS, ASSIGNMENT_QUIZZES, ASSIGNMENT_DISCUSSIONS, HOMEROOM, K5_GRADES, IMPORTANT_DATES, RESOURCES, SCHEDULE,
GROUPS_DASHBOARD, GROUPS_FILES, GROUPS_ANNOUNCEMENTS, GROUPS_DISCUSSIONS, GROUPS_PAGES, GROUPS_PEOPLE,
EVENTS_DISCUSSIONS, EVENTS_QUIZZES, EVENTS_ASSIGNMENTS, EVENTS_NOTIFICATIONS, SETTINGS_EMAIL_NOTIFICATIONS,
Expand Down
Loading