From 39a6340984a0d8caa2de05da7714d4ffde5faefc Mon Sep 17 00:00:00 2001 From: alangsto <46360176+alangsto@users.noreply.github.com> Date: Wed, 31 May 2023 12:47:40 -0400 Subject: [PATCH] feat: add end_exam message for proctorio (#109) --- src/data/messages/proctorio.js | 9 +++++++-- src/data/redux.test.jsx | 15 +++++++++++++++ src/data/thunks.js | 6 +++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/data/messages/proctorio.js b/src/data/messages/proctorio.js index 1ae29ca6..7bc30fd7 100644 --- a/src/data/messages/proctorio.js +++ b/src/data/messages/proctorio.js @@ -5,11 +5,16 @@ * vendor-specific integrations long term. As of now these events * will trigger on ANY lti integration, not just Proctorio. */ -function notifyStartExam() { +export function notifyStartExam() { window.top.postMessage( ['exam_state_change', 'exam_take'], '*', // this isn't emitting secure data so any origin is fine ); } -export default notifyStartExam; +export function notifyEndExam() { + window.top.postMessage( + ['exam_state_change', 'exam_end'], + '*', // this isn't emitting secure data so any origin is fine + ); +} diff --git a/src/data/redux.test.jsx b/src/data/redux.test.jsx index 60157be7..5dde4ebe 100644 --- a/src/data/redux.test.jsx +++ b/src/data/redux.test.jsx @@ -581,6 +581,21 @@ describe('Data layer integration tests', () => { await executeThunk(thunks.submitExam(), store.dispatch, store.getState); expect(axiosMock.history.put[0].url).toEqual(updateAttemptStatusLegacyUrl); }); + + it('Should notify top window on LTI exam end', async () => { + const mockPostMessage = jest.fn(); + windowSpy.mockImplementation(() => ({ + top: { + postMessage: mockPostMessage, + }, + })); + + await initWithExamAttempt(); + axiosMock.onGet(fetchExamAttemptsDataUrl).reply(200, { exam: submittedExam }); + axiosMock.onPut(`${createUpdateAttemptURL}/${attempt.attempt_id}`).reply(200, { exam_attempt_id: submittedAttempt.attempt_id }); + await executeThunk(thunks.submitExam(), store.dispatch, store.getState); + expect(mockPostMessage).toHaveBeenCalledWith(['exam_state_change', 'exam_end'], '*'); + }); }); describe('Test expireExam', () => { diff --git a/src/data/thunks.js b/src/data/thunks.js index cde37f38..6a4d2358 100644 --- a/src/data/thunks.js +++ b/src/data/thunks.js @@ -31,7 +31,7 @@ import { import { ExamStatus } from '../constants'; import { workerPromiseForEventNames, pingApplication } from './messages/handlers'; import actionToMessageTypesMap from './messages/constants'; -import notifyStartExam from './messages/proctorio'; +import { notifyEndExam, notifyStartExam } from './messages/proctorio'; function handleAPIError(error, dispatch) { const { message, detail } = error; @@ -364,6 +364,7 @@ export function submitExam() { const { exam, activeAttempt } = getState().examState; const { desktop_application_js_url: workerUrl, external_id: attemptExternalId } = activeAttempt || {}; const useWorker = window.Worker && activeAttempt && workerUrl; + const examHasLtiProvider = !exam.useLegacyAttemptApi; const handleBackendProviderSubmission = () => { // if a backend provider is being used during the exam @@ -375,6 +376,9 @@ export function submitExam() { dispatch, )); } + if (examHasLtiProvider) { + notifyEndExam(); + } }; if (!activeAttempt) {