From 3019a63cf2f91318bfc53ac0bf622e60c39a38ba Mon Sep 17 00:00:00 2001 From: Bianca Severino Date: Wed, 8 Dec 2021 09:16:16 -0500 Subject: [PATCH] fix: log worker errors for startProctoredExam (#53) --- src/data/redux.test.jsx | 56 +++++++++++++++++++++++++++++++++++++++++ src/data/thunks.js | 22 ++++++++++++---- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/src/data/redux.test.jsx b/src/data/redux.test.jsx index 6b0dce2a..6a12beab 100644 --- a/src/data/redux.test.jsx +++ b/src/data/redux.test.jsx @@ -16,6 +16,20 @@ const BASE_API_URL = '/api/edx_proctoring/v1/proctored_exam/attempt'; const { loggingService } = initializeMockApp(); const axiosMock = new MockAdapter(getAuthenticatedHttpClient()); +let windowSpy; + +// Mock for worker failure +const mockPromise = jest.fn(() => ( + new Promise((resolve, reject) => { + reject(Error('test error')); + }) +)); +jest.mock('./messages/handlers', () => ({ + ...jest.requireActual('./messages/handlers'), + createWorker: jest.fn(), + workerPromiseForEventNames: jest.fn(() => mockPromise), +})); + describe('Data layer integration tests', () => { const exam = Factory.build('exam', { attempt: Factory.build('attempt') }); const { course_id: courseId, content_id: contentId, attempt } = exam; @@ -25,10 +39,17 @@ describe('Data layer integration tests', () => { let store; beforeEach(async () => { + windowSpy = jest.spyOn(window, 'window', 'get'); axiosMock.reset(); loggingService.logError.mockReset(); + loggingService.logInfo.mockReset(); store = await initializeTestStore(); }); + + afterEach(() => { + windowSpy.mockRestore(); + }); + describe('Test getVerificationData', () => { const getVerificationDataUrl = `${getConfig().LMS_BASE_URL}/verify_student/status/`; @@ -498,6 +519,41 @@ describe('Data layer integration tests', () => { expect(loggingService.logError).toHaveBeenCalled(); }); + + it('Should log an error on worker failure', async () => { + windowSpy.mockImplementation(() => ({ + Worker: jest.fn(), + URL: { createObjectURL: jest.fn() }, + })); + + const createdWorkerAttempt = Factory.build( + 'attempt', { attempt_status: ExamStatus.CREATED, desktop_application_js_url: 'http://proctortest.com' }, + ); + const startedWorkerAttempt = Factory.build( + 'attempt', { attempt_status: ExamStatus.STARTED, desktop_application_js_url: 'http://proctortest.com' }, + ); + const createdWorkerExam = Factory.build('exam', { attempt: createdWorkerAttempt }); + const startedWorkerExam = Factory.build('exam', { attempt: startedWorkerAttempt }); + const continueWorkerAttemptUrl = `${getConfig().LMS_BASE_URL}${BASE_API_URL}/${createdWorkerAttempt.attempt_id}`; + + axiosMock.onGet(fetchExamAttemptsDataUrl).replyOnce( + 200, { exam: createdWorkerExam, active_attempt: createdWorkerAttempt }, + ); + axiosMock.onGet(fetchExamAttemptsDataUrl).reply( + 200, { exam: startedWorkerExam, active_attempt: startedWorkerAttempt }, + ); + axiosMock.onPost(continueWorkerAttemptUrl).reply(200, { exam_attempt_id: startedWorkerAttempt.attempt_id }); + + await executeThunk(thunks.getExamAttemptsData(courseId, contentId), store.dispatch); + await executeThunk(thunks.startProctoredExam(), store.dispatch, store.getState); + expect(loggingService.logInfo).toHaveBeenCalledWith( + Error('test error'), { + attemptId: createdWorkerAttempt.attempt_id, + courseId: createdWorkerAttempt.course_id, + examId: createdWorkerExam.id, + }, + ); + }); }); describe('Test skipProctoringExam', () => { diff --git a/src/data/thunks.js b/src/data/thunks.js index 2674d97e..4f2d54e4 100644 --- a/src/data/thunks.js +++ b/src/data/thunks.js @@ -1,4 +1,4 @@ -import { logError } from '@edx/frontend-platform/logging'; +import { logError, logInfo } from '@edx/frontend-platform/logging'; import { fetchExamAttemptsData, createExamAttempt, @@ -150,10 +150,22 @@ export function startProctoredExam() { .then(() => updateAttemptAfter( exam.course_id, exam.content_id, continueAttempt(attempt.attempt_id), )(dispatch)) - .catch(() => handleAPIError( - { message: 'Something has gone wrong starting your exam. Please double-check that the application is running.' }, - dispatch, - )); + .catch(error => { + if (error) { + logInfo( + error, + { + attemptId: attempt.attempt_id, + courseId: attempt.course_id, + examId: exam.id, + }, + ); + } + handleAPIError( + { message: 'Something has gone wrong starting your exam. Please double-check that the application is running.' }, + dispatch, + ); + }); } else { await updateAttemptAfter( exam.course_id, exam.content_id, continueAttempt(attempt.attempt_id),