diff --git a/apps/student/src/main/java/com/instructure/student/features/assignments/details/datasource/AssignmentDetailsNetworkDataSource.kt b/apps/student/src/main/java/com/instructure/student/features/assignments/details/datasource/AssignmentDetailsNetworkDataSource.kt index 22352cb3aa..5a3da42077 100644 --- a/apps/student/src/main/java/com/instructure/student/features/assignments/details/datasource/AssignmentDetailsNetworkDataSource.kt +++ b/apps/student/src/main/java/com/instructure/student/features/assignments/details/datasource/AssignmentDetailsNetworkDataSource.kt @@ -63,9 +63,9 @@ class AssignmentDetailsNetworkDataSource( return quizInterface.getQuiz(courseId, quizId, params).dataOrThrow } - override suspend fun getExternalToolLaunchUrl(courseId: Long, externalToolId: Long, assignmentId: Long, forceNetwork: Boolean): LTITool { + override suspend fun getExternalToolLaunchUrl(courseId: Long, externalToolId: Long, assignmentId: Long, forceNetwork: Boolean): LTITool? { val params = RestParams(isForceReadFromNetwork = forceNetwork) - return assignmentInterface.getExternalToolLaunchUrl(courseId, externalToolId, assignmentId, restParams = params).dataOrThrow + return assignmentInterface.getExternalToolLaunchUrl(courseId, externalToolId, assignmentId, restParams = params).dataOrNull } override suspend fun getLtiFromAuthenticationUrl(url: String, forceNetwork: Boolean): LTITool { diff --git a/apps/student/src/test/java/com/instructure/student/features/offline/assignmentdetails/AssignmentDetailsNetworkDataSourceTest.kt b/apps/student/src/test/java/com/instructure/student/features/offline/assignmentdetails/AssignmentDetailsNetworkDataSourceTest.kt index 682483dcc8..9726cf4650 100644 --- a/apps/student/src/test/java/com/instructure/student/features/offline/assignmentdetails/AssignmentDetailsNetworkDataSourceTest.kt +++ b/apps/student/src/test/java/com/instructure/student/features/offline/assignmentdetails/AssignmentDetailsNetworkDataSourceTest.kt @@ -134,11 +134,13 @@ class AssignmentDetailsNetworkDataSourceTest { Assert.assertEquals(expected, assignmentResult) } - @Test(expected = IllegalStateException::class) - fun `Get LTI by launch url failure throws exception`() = runTest { + @Test + fun `Get LTI by launch url failure returns null`() = runTest { coEvery { assignmentInterface.getExternalToolLaunchUrl(any(), any(), any(), any(), any()) } returns DataResult.Fail() - dataSource.getExternalToolLaunchUrl(1, 1, 1, true) + val result = dataSource.getExternalToolLaunchUrl(1, 1, 1, true) + + Assert.assertNull(result) } @Test diff --git a/libs/pandautils/src/main/java/com/instructure/pandautils/features/assignments/details/AssignmentDetailsViewModel.kt b/libs/pandautils/src/main/java/com/instructure/pandautils/features/assignments/details/AssignmentDetailsViewModel.kt index e3e45ba6ff..92e0bc587f 100644 --- a/libs/pandautils/src/main/java/com/instructure/pandautils/features/assignments/details/AssignmentDetailsViewModel.kt +++ b/libs/pandautils/src/main/java/com/instructure/pandautils/features/assignments/details/AssignmentDetailsViewModel.kt @@ -684,9 +684,11 @@ class AssignmentDetailsViewModel @Inject constructor( SubmissionType.STUDENT_ANNOTATION -> postAction(AssignmentDetailAction.NavigateToAnnotationSubmissionScreen(assignment)) SubmissionType.MEDIA_RECORDING -> postAction(AssignmentDetailAction.ShowMediaDialog(assignment)) SubmissionType.EXTERNAL_TOOL, SubmissionType.BASIC_LTI_LAUNCH -> { - externalLTITool.let { + if (externalLTITool != null) { Analytics.logEvent(AnalyticsEventConstants.ASSIGNMENT_LAUNCHLTI_SELECTED) - postAction(AssignmentDetailAction.NavigateToLtiLaunchScreen(assignment.name.orEmpty(), it, assignment.ltiToolType().openInternally)) + postAction(AssignmentDetailAction.NavigateToLtiLaunchScreen(assignment.name.orEmpty(), externalLTITool, assignment.ltiToolType().openInternally)) + } else { + postAction(AssignmentDetailAction.ShowToast(resources.getString(R.string.generalUnexpectedError))) } } else -> Unit diff --git a/libs/pandautils/src/test/java/com/instructure/pandautils/features/assignments/details/AssignmentDetailsViewModelTest.kt b/libs/pandautils/src/test/java/com/instructure/pandautils/features/assignments/details/AssignmentDetailsViewModelTest.kt index 245422d21f..6143c1eccd 100644 --- a/libs/pandautils/src/test/java/com/instructure/pandautils/features/assignments/details/AssignmentDetailsViewModelTest.kt +++ b/libs/pandautils/src/test/java/com/instructure/pandautils/features/assignments/details/AssignmentDetailsViewModelTest.kt @@ -36,6 +36,7 @@ import com.instructure.canvasapi2.models.Course import com.instructure.canvasapi2.models.CourseSettings import com.instructure.canvasapi2.models.DiscussionTopicHeader import com.instructure.canvasapi2.models.Enrollment +import com.instructure.canvasapi2.models.ExternalToolAttributes import com.instructure.canvasapi2.models.LockInfo import com.instructure.canvasapi2.models.Quiz import com.instructure.canvasapi2.models.SubAssignmentSubmission @@ -670,12 +671,15 @@ class AssignmentDetailsViewModelTest { } @Test - fun `Submit button click - external tool`() { + fun `Submit button click - external tool with valid LTI tool`() { val course = Course(enrollments = mutableListOf(Enrollment(type = Enrollment.EnrollmentType.Student))) coEvery { assignmentDetailsRepository.getCourseWithGrade(any(), any()) } returns course val assignment = Assignment(submissionTypesRaw = listOf("external_tool")) - coEvery { assignmentDetailsRepository.getAssignment(any(), any(), any(), any()) } returns assignment + coEvery { assignmentDetailsRepository.getAssignment(any(), any(), any(), any()) } returns assignment.copy( + externalToolAttributes = ExternalToolAttributes(contentId = 1L) + ) + coEvery { assignmentDetailsRepository.getExternalToolLaunchUrl(any(), any(), any(), any()) } returns mockk(relaxed = true) val viewModel = getViewModel() viewModel.onSubmitButtonClicked() @@ -683,6 +687,26 @@ class AssignmentDetailsViewModelTest { assertTrue(viewModel.events.value?.peekContent() is AssignmentDetailAction.NavigateToLtiLaunchScreen) } + @Test + fun `Submit button click - external tool with null LTI tool shows error`() { + val errorMessage = "An unexpected error occurred." + every { resources.getString(R.string.generalUnexpectedError) } returns errorMessage + + val course = Course(enrollments = mutableListOf(Enrollment(type = Enrollment.EnrollmentType.Student))) + coEvery { assignmentDetailsRepository.getCourseWithGrade(any(), any()) } returns course + + val assignment = Assignment(submissionTypesRaw = listOf("external_tool")) + coEvery { assignmentDetailsRepository.getAssignment(any(), any(), any(), any()) } returns assignment + coEvery { assignmentDetailsRepository.getExternalToolLaunchUrl(any(), any(), any(), any()) } returns null + + val viewModel = getViewModel() + viewModel.onSubmitButtonClicked() + + val action = viewModel.events.value?.peekContent() + assertTrue(action is AssignmentDetailAction.ShowToast) + assertEquals(errorMessage, (action as AssignmentDetailAction.ShowToast).message) + } + @Test fun `Create viewData with points when quantitative data is not restricted`() { coEvery { assignmentDetailsRepository.getCourseWithGrade(any(), any()) } returns Course(