diff --git a/src/constants.js b/src/constants.js index df3084e3..7767722f 100644 --- a/src/constants.js +++ b/src/constants.js @@ -9,6 +9,8 @@ export const ExamStatus = Object.freeze({ TIMED_OUT: 'timed_out', VERIFIED: 'verified', REJECTED: 'rejected', + ERROR: 'error', + READY_TO_RESUME: 'ready_to_resume', }); export const IS_STARTED_STATUS = (status) => [ExamStatus.STARTED, ExamStatus.READY_TO_SUBMIT].includes(status); diff --git a/src/instructions/Instructions.test.jsx b/src/instructions/Instructions.test.jsx index 1c20cf54..0419ea82 100644 --- a/src/instructions/Instructions.test.jsx +++ b/src/instructions/Instructions.test.jsx @@ -2,7 +2,7 @@ import '@testing-library/jest-dom'; import React from 'react'; import Instructions from './index'; import { store, getExamAttemptsData, startExam } from '../data'; -import { render } from '../setupTest'; +import { render, screen } from '../setupTest'; import { ExamStateProvider } from '../index'; jest.mock('../data', () => ({ @@ -147,4 +147,74 @@ describe('SequenceExamWrapper', () => { expect(getByTestId('pending-prerequisites')).toBeInTheDocument(); }); + + it('Instructions for error status', () => { + store.getState = () => ({ + examState: { + isLoading: false, + proctoringSettings: { + link_urls: '', + }, + verification: { + status: 'none', + can_verify: true, + }, + activeAttempt: { + attempt_status: 'error', + }, + exam: { + time_limit_mins: 30, + attempt: { + attempt_status: 'error', + }, + }, + }, + }); + + render( + + +
Sequence
+
+
, + { store }, + ); + expect(screen.getByText('Error with proctored exam')).toBeInTheDocument(); + }); + + it('Instructions for ready to resume status', () => { + store.getState = () => ({ + examState: { + isLoading: false, + proctoringSettings: { + link_urls: '', + platform_name: 'Platform Name', + }, + verification: { + status: 'none', + can_verify: true, + }, + activeAttempt: { + attempt_status: 'ready_to_resume', + }, + exam: { + time_limit_mins: 30, + attempt: { + attempt_status: 'ready_to_resume', + }, + }, + }, + }); + + render( + + +
Sequence
+
+
, + { store }, + ); + expect(screen.getByText('Your exam is ready to be resumed.')).toBeInTheDocument(); + expect(screen.getByTestId('start-exam-button')).toHaveTextContent('Continue to my proctored exam.'); + }); }); diff --git a/src/instructions/index.jsx b/src/instructions/index.jsx index d54a5ae8..701ed496 100644 --- a/src/instructions/index.jsx +++ b/src/instructions/index.jsx @@ -4,6 +4,7 @@ import StartExamInstructions from './StartExamInstructions'; import SubmitExamInstructions from './SubmitExamInstructions'; import SubmittedExamInstructions from './SubmittedExamInstructions'; import { + ErrorProctoredExamInstructions, EntranceProctoredExamInstructions, VerificationProctoredExamInstructions, SubmitProctoredExamInstructions, @@ -61,6 +62,10 @@ const Instructions = ({ children }) => { return ; case attempt.attempt_status === ExamStatus.REJECTED: return ; + case attempt.attempt_status === ExamStatus.ERROR: + return ; + case attempt.attempt_status === ExamStatus.READY_TO_RESUME: + return ; default: return children; } diff --git a/src/instructions/proctored_exam/EntranceProctoredExamInstructions.jsx b/src/instructions/proctored_exam/EntranceProctoredExamInstructions.jsx index e6508732..36903085 100644 --- a/src/instructions/proctored_exam/EntranceProctoredExamInstructions.jsx +++ b/src/instructions/proctored_exam/EntranceProctoredExamInstructions.jsx @@ -1,22 +1,45 @@ import React, { useContext } from 'react'; import { FormattedMessage } from '@edx/frontend-platform/i18n'; import { Button, Container } from '@edx/paragon'; +import { ExamStatus } from '../../constants'; import ExamStateContext from '../../context'; import Footer from './Footer'; const EntranceProctoredExamInstructions = () => { const state = useContext(ExamStateContext); - const { startProctoringExam } = state; + const { exam, startProctoringExam } = state; + const { attempt } = exam || {}; + const { total_time: totalTime = 0 } = attempt; return (
-
- -
+ { exam.attempt.attempt_status === ExamStatus.READY_TO_RESUME ? ( +
+
+ +
+

+ +

+
+ ) : ( +

+

+ +
+

+ )}

{ + const state = useContext(ExamStateContext); + const { + link_urls: linkUrls, + platform_name: platformName, + proctoring_escalation_email: proctoringEscalationEmail, + } = state.proctoringSettings || {}; + const contactUsUrl = linkUrls && linkUrls.contact_us; + + const renderBody = () => { + if (proctoringEscalationEmail) { + return ( + {proctoringEscalationEmail} }} + /> + ); + } + + return ( + {platformName} Support }} + /> + ); + }; + + return ( +

+ +
+ +
+

+ {renderBody()} +

+
+
+ ); +}; + +export default ErrorProctoredExamInstructions; diff --git a/src/instructions/proctored_exam/index.js b/src/instructions/proctored_exam/index.js index 53cc3c74..dae107cc 100644 --- a/src/instructions/proctored_exam/index.js +++ b/src/instructions/proctored_exam/index.js @@ -1,3 +1,4 @@ +export { default as ErrorProctoredExamInstructions } from './ErrorProctoredExamInstructions'; export { default as EntranceProctoredExamInstructions } from './EntranceProctoredExamInstructions'; export { default as RejectedProctoredExamInstructions } from './RejectedProctoredExamInstructions'; export { default as SubmitProctoredExamInstructions } from './SubmitProctoredExamInstructions';