Skip to content

Commit

Permalink
feat: add LTI launch for submitting exam (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
alangsto authored Apr 21, 2023
1 parent 34b88df commit 9353840
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/data/slice.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const examSlice = createSlice({
ping_interval: null,
attempt_code: '',
external_id: '',
use_legacy_attempt_api: true,
},
type: '',
},
Expand Down
43 changes: 41 additions & 2 deletions src/instructions/proctored_exam/ProctoredExamInstructions.test.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import '@testing-library/jest-dom';
import { Factory } from 'rosie';
import React from 'react';
import { fireEvent } from '@testing-library/dom';
import { fireEvent, waitFor } from '@testing-library/dom';
import Instructions from '../index';
import { store, getExamAttemptsData } from '../../data';
import { submitExam } from '../../data/thunks';
import { render, screen } from '../../setupTest';
import { initializeMockApp, render, screen } from '../../setupTest';
import ExamStateProvider from '../../core/ExamStateProvider';
import {
ExamType,
Expand All @@ -27,6 +27,11 @@ store.subscribe = jest.fn();
store.dispatch = jest.fn();

describe('SequenceExamWrapper', () => {
beforeEach(() => {
initializeMockApp();
jest.clearAllMocks();
});

it('Start exam instructions can be successfully rendered', () => {
store.getState = () => ({
examState: Factory.build('examState', {
Expand Down Expand Up @@ -164,6 +169,7 @@ describe('SequenceExamWrapper', () => {
it('Shows correct instructions when attempt status is ready_to_submit ', () => {
const attempt = Factory.build('attempt', {
attempt_status: ExamStatus.READY_TO_SUBMIT,
use_legacy_attempt_api: true,
});
store.getState = () => ({
examState: Factory.build('examState', {
Expand All @@ -190,6 +196,39 @@ describe('SequenceExamWrapper', () => {
expect(submitExam).toHaveBeenCalled();
});

it('Initiates an LTI launch in a new window when the user clicks the submit button', async () => {
const windowSpy = jest.spyOn(window, 'open');
windowSpy.mockImplementation(() => ({}));
const attempt = Factory.build('attempt', {
attempt_status: ExamStatus.READY_TO_SUBMIT,
use_legacy_attempt_api: false,
attempt_id: 1,
});
store.getState = () => ({
examState: Factory.build('examState', {
activeAttempt: attempt,
exam: Factory.build('exam', {
is_proctored: true,
type: ExamType.PROCTORED,
attempt,
}),
}),
});

const { queryByTestId } = render(
<ExamStateProvider>
<Instructions>
<div>Sequence</div>
</Instructions>
</ExamStateProvider>,
{ store },
);

expect(queryByTestId('proctored-exam-instructions-title')).toHaveTextContent('Are you sure you want to end your proctored exam?');
fireEvent.click(queryByTestId('end-exam-button'));
await waitFor(() => { expect(windowSpy).toHaveBeenCalledWith('http://localhost:18740/lti/end_assessment/1', '_blank'); });
});

it('Instructions are shown when attempt status is verified', () => {
store.getState = () => ({
examState: Factory.build('examState', {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useContext } from 'react';
import { getConfig } from '@edx/frontend-platform';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { Button } from '@edx/paragon';
import ExamStateContext from '../../context';
Expand All @@ -11,8 +12,18 @@ const SubmitProctoredExamInstructions = () => {
exam,
activeAttempt,
} = state;
const { type: examType } = exam || {};
const { type: examType, attempt } = exam || {};
const { exam_display_name: examName } = activeAttempt;
const examHasLtiProvider = !attempt.use_legacy_attempt_api;
const submitLtiAttemptUrl = `${getConfig().EXAMS_BASE_URL}/lti/end_assessment/${attempt.attempt_id}`;

const handleSubmitClick = () => {
if (examHasLtiProvider) {
window.open(submitLtiAttemptUrl, '_blank');
} else {
submitExam();
}
};

return (
<>
Expand Down Expand Up @@ -48,7 +59,7 @@ const SubmitProctoredExamInstructions = () => {
/>
</p>
)}
<Button variant="primary" onClick={submitExam} className="mr-2" data-testid="end-exam-button">
<Button variant="primary" onClick={handleSubmitClick} className="mr-2" data-testid="end-exam-button">
<FormattedMessage
id="exam.SubmitProctoredExamInstructions.submit"
defaultMessage="Yes, end my proctored exam"
Expand Down

0 comments on commit 9353840

Please sign in to comment.