Skip to content

Commit

Permalink
fix: pollAttempt call on download page (#113)
Browse files Browse the repository at this point in the history
* fix: pollAttempt call on download page

* feat: review cleanup

* fix: string format
  • Loading branch information
zacharis278 authored Aug 7, 2023
1 parent f6228ed commit 8b0f15c
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/data/__snapshots__/redux.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ Object {
"in_timed_exam": true,
"software_download_url": "",
"taking_as_proctored": false,
"time_remaining_seconds": 1739.9,
"time_remaining_seconds": 1799.9,
"total_time": "30 minutes",
}
`;
Expand Down
26 changes: 21 additions & 5 deletions src/data/api.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
import { getConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { logError } from '@edx/frontend-platform/logging';
import { ExamAction } from '../constants';
import { generateHumanizedTime } from '../helpers';

const BASE_API_URL = '/api/edx_proctoring/v1/proctored_exam/attempt';

async function fetchActiveAttempt() {
// fetch 'active' (timer is running) attempt if it exists
const activeAttemptUrl = new URL(`${getConfig().EXAMS_BASE_URL}/api/v1/exams/attempt/latest`);
const activeAttemptResponse = await getAuthenticatedHttpClient().get(activeAttemptUrl.href);
return activeAttemptResponse.data;
}

async function fetchLatestExamAttempt(sequenceId) {
// the calls the same endpoint as fetchActiveAttempt but it behaves slightly different
// with an exam's section specified. The attempt for that requested exam is always returned
// even if it is not 'active' (timer is not running)
const attemptUrl = new URL(`${getConfig().EXAMS_BASE_URL}/api/v1/exams/attempt/latest`);
attemptUrl.searchParams.append('content_id', sequenceId);
const response = await getAuthenticatedHttpClient().get(attemptUrl.href);
return response.data;
}

export async function fetchExamAttemptsData(courseId, sequenceId) {
let data;
if (!getConfig().EXAMS_BASE_URL) {
Expand Down Expand Up @@ -56,22 +68,26 @@ export async function fetchLatestAttempt(courseId) {
return data;
}

export async function pollExamAttempt(url) {
export async function pollExamAttempt(pollUrl, sequenceId) {
let data;
if (!getConfig().EXAMS_BASE_URL) {
if (pollUrl) {
const edxProctoringURL = new URL(
`${getConfig().LMS_BASE_URL}${url}`,
`${getConfig().LMS_BASE_URL}${pollUrl}`,
);
const urlResponse = await getAuthenticatedHttpClient().get(edxProctoringURL.href);
data = urlResponse.data;
} else {
data = await fetchActiveAttempt();
} else if (sequenceId && getConfig().EXAMS_BASE_URL) {
data = await fetchLatestExamAttempt(sequenceId);

// Update dictionaries returned by edx-exams to have correct status key for legacy compatibility
if (data.attempt_status) {
data.status = data.attempt_status;
delete data.attempt_status;
}
} else {
// sites configured with only edx-proctoring must have pollUrl set
// sites configured with edx-exams expect sequenceId if pollUrl is not set
logError(`pollExamAttempt recieved unexpected parameters pollUrl=${pollUrl} sequenceId=${sequenceId}`);
}
return data;
}
Expand Down
30 changes: 30 additions & 0 deletions src/data/redux.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import MockAdapter from 'axios-mock-adapter';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { getConfig, mergeConfig } from '@edx/frontend-platform';

import * as api from './api';
import * as thunks from './thunks';

import executeThunk from '../utils';
Expand Down Expand Up @@ -958,6 +959,35 @@ describe('Data layer integration tests', () => {
const state = store.getState();
expect(state.examState.activeAttempt).toMatchSnapshot();
});

describe('pollAttempt api called directly', () => {
// in the download view we call this function directly withough invoking the wrapping thunk
it('should call pollUrl if one is provided', async () => {
const pollExamAttemptUrl = `${getConfig().LMS_BASE_URL}${attempt.exam_started_poll_url}`;
axiosMock.onGet(pollExamAttemptUrl).reply(200, {
time_remaining_seconds: 1739.9,
accessibility_time_string: 'you have 29 minutes remaining',
attempt_status: ExamStatus.STARTED,
});
await api.pollExamAttempt(attempt.exam_started_poll_url);
expect(axiosMock.history.get[0].url).toEqual(pollExamAttemptUrl);
});
it('should call the latest attempt for a sequence if a sequence id is provided instead of a pollUrl', async () => {
const sequenceId = 'block-v1:edX+Test+123';
const expectedUrl = `${getConfig().EXAMS_BASE_URL}/api/v1/exams/attempt/latest?content_id=${encodeURIComponent(sequenceId)}`;
axiosMock.onGet(expectedUrl).reply(200, {
time_remaining_seconds: 1739.9,
status: ExamStatus.STARTED,
});
await api.pollExamAttempt(null, sequenceId);
expect(axiosMock.history.get[0].url).toEqual(expectedUrl);
});
test('pollUrl is required if edx-exams in not enabled, an error should be logged', async () => {
mergeConfig({ EXAMS_BASE_URL: null });
api.pollExamAttempt(null, null);
expect(loggingService.logError).toHaveBeenCalled();
});
});
});

describe('Test pingAttempt', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const DownloadSoftwareProctoredExamInstructions = ({ intl, skipProctoredExam })
? `${getConfig().EXAMS_BASE_URL}/lti/start_proctoring/${attemptId}` : downloadUrl;

const handleDownloadClick = () => {
pollExamAttempt(`${pollUrl}?sourceid=instructions`)
pollExamAttempt(pollUrl, sequenceId)
.then((data) => {
if (data.status === ExamStatus.READY_TO_START) {
setSystemCheckStatus('success');
Expand All @@ -66,7 +66,7 @@ const DownloadSoftwareProctoredExamInstructions = ({ intl, skipProctoredExam })
};

const handleStartExamClick = () => {
pollExamAttempt(`${pollUrl}?sourceid=instructions`)
pollExamAttempt(pollUrl, sequenceId)
.then((data) => (
data.status === ExamStatus.READY_TO_START
? getExamAttemptsData(courseId, sequenceId)
Expand Down

0 comments on commit 8b0f15c

Please sign in to comment.