diff --git a/package-lock.json b/package-lock.json
index d9c200880..689fb4ee8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3483,12 +3483,12 @@
}
},
"@edx/frontend-platform": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-1.8.0.tgz",
- "integrity": "sha512-R4LGBKaSBWC9xxG3eTN78zw5CkBes4xQgazt78ApgenxzIoun+y0tdWyc/8PpjbKmyj0nACpsfARyeQy4rnGKA==",
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@edx/frontend-platform/-/frontend-platform-1.9.0.tgz",
+ "integrity": "sha512-fcXEJ+acdVAYmNXXY0Edrk47N2A+BNxcHUUO4v/n+JK2JYdYKyVCFgJI6Y7QamzW02+SYTJs0IZbls1OrRk1iw==",
"requires": {
"@cospired/i18n-iso-languages": "2.1.2",
- "axios": "0.18.1",
+ "axios": "0.21.1",
"axios-cache-adapter": "^2.5.0",
"form-urlencoded": "4.1.4",
"glob": "7.1.6",
@@ -3504,17 +3504,6 @@
"pubsub-js": "1.7.0",
"react-intl": "2.9.0",
"universal-cookie": "4.0.4"
- },
- "dependencies": {
- "axios": {
- "version": "0.18.1",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz",
- "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==",
- "requires": {
- "follow-redirects": "1.5.10",
- "is-buffer": "^2.0.2"
- }
- }
}
},
"@edx/paragon": {
@@ -6548,7 +6537,6 @@
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
- "dev": true,
"requires": {
"follow-redirects": "^1.10.0"
},
@@ -6556,18 +6544,17 @@
"follow-redirects": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz",
- "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==",
- "dev": true
+ "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg=="
}
}
},
"axios-cache-adapter": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/axios-cache-adapter/-/axios-cache-adapter-2.5.0.tgz",
- "integrity": "sha512-YcMPdMoqmSLoZx7A5YD/PdYGuX6/Y9M2tHBhaIXvXrPeGgNnbW7nb3+uArWlT53WGHLfclnu2voMmS7jGXVg6A==",
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/axios-cache-adapter/-/axios-cache-adapter-2.7.3.tgz",
+ "integrity": "sha512-A+ZKJ9lhpjthOEp4Z3QR/a9xC4du1ALaAsejgRGrH9ef6kSDxdFrhRpulqsh9khsEnwXxGfgpUuDp1YXMNMEiQ==",
"requires": {
"cache-control-esm": "1.0.0",
- "lodash": "^4.17.11"
+ "md5": "^2.2.1"
}
},
"axios-mock-adapter": {
@@ -8011,6 +7998,11 @@
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
"dev": true
},
+ "charenc": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
+ "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
+ },
"check-types": {
"version": "8.0.3",
"resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz",
@@ -8659,6 +8651,11 @@
}
}
},
+ "crypt": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
+ "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
+ },
"crypto-browserify": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
@@ -9070,6 +9067,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "dev": true,
"requires": {
"ms": "2.0.0"
}
@@ -11296,6 +11294,7 @@
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
+ "dev": true,
"requires": {
"debug": "=3.1.0"
}
@@ -13088,9 +13087,10 @@
}
},
"is-buffer": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
- "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A=="
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
+ "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
+ "dev": true
},
"is-callable": {
"version": "1.2.0",
@@ -17849,6 +17849,23 @@
"css-mediaquery": "^0.1.2"
}
},
+ "md5": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
+ "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
+ "requires": {
+ "charenc": "0.0.2",
+ "crypt": "0.0.2",
+ "is-buffer": "~1.1.6"
+ },
+ "dependencies": {
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
+ }
+ }
+ },
"md5.js": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@@ -18306,7 +18323,8 @@
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
},
"multicast-dns": {
"version": "6.2.3",
diff --git a/package.json b/package.json
index 7662e5eae..b9e42dd6d 100644
--- a/package.json
+++ b/package.json
@@ -36,7 +36,7 @@
"dependencies": {
"@edx/brand": "npm:@edx/brand-openedx@1.1.0",
"@edx/frontend-component-footer": "10.0.11",
- "@edx/frontend-platform": "1.8.0",
+ "@edx/frontend-platform": "1.9.0",
"@edx/paragon": "13.13.5",
"@fortawesome/fontawesome-svg-core": "1.2.28",
"@fortawesome/free-brands-svg-icons": "5.11.2",
@@ -64,7 +64,6 @@
"devDependencies": {
"@edx/frontend-build": "5.6.9",
"@testing-library/react": "10.4.7",
- "axios": "0.21.1",
"axios-mock-adapter": "1.18.1",
"codecov": "3.7.1",
"es-check": "5.1.0",
diff --git a/src/proctored-exam-settings/ProctoredExamSettings.jsx b/src/proctored-exam-settings/ProctoredExamSettings.jsx
index 7a6a35fb0..d7eb93824 100644
--- a/src/proctored-exam-settings/ProctoredExamSettings.jsx
+++ b/src/proctored-exam-settings/ProctoredExamSettings.jsx
@@ -510,8 +510,8 @@ function ProctoredExamSettings({ courseId, intl }) {
setCreateZendeskTickets(proctoredExamSettings.create_zendesk_tickets);
},
).catch(
- errorDetails => {
- if (errorDetails.customAttributes.httpErrorStatus === 403) {
+ error => {
+ if (error.response.status === 403) {
setLoadingPermissionError(true);
} else {
setLoadingConnectionError(true);
diff --git a/src/proctored-exam-settings/ProctoredExamSettings.test.jsx b/src/proctored-exam-settings/ProctoredExamSettings.test.jsx
index 9f0c85ae8..0ebea741f 100644
--- a/src/proctored-exam-settings/ProctoredExamSettings.test.jsx
+++ b/src/proctored-exam-settings/ProctoredExamSettings.test.jsx
@@ -3,7 +3,10 @@ import {
render, screen, cleanup, waitFor, waitForElementToBeRemoved, fireEvent, act,
} from '@testing-library/react';
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
-import * as auth from '@edx/frontend-platform/auth';
+// import * as auth from '@edx/frontend-platform/auth';
+import MockAdapter from 'axios-mock-adapter';
+import { initializeMockApp } from '@edx/frontend-platform';
+import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import ProctoredExamSettings from './ProctoredExamSettings';
import StudioApiService from '../data/services/StudioApiService';
@@ -18,282 +21,295 @@ const intlWrapper = children => (
{children}
);
+let axiosMock;
-describe('ProctoredExamSettings field dependency tests', () => {
- beforeEach(async () => {
- auth.getAuthenticatedHttpClient = jest.fn(() => ({
- get: async () => ({
- data: {
- proctored_exam_settings: {
- enable_proctored_exams: true,
- allow_proctoring_opt_out: false,
- proctoring_provider: 'mockproc',
- proctoring_escalation_email: 'test@example.com',
- create_zendesk_tickets: true,
- },
- available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
- course_start_date: '2070-01-01T00:00:00Z',
- },
- }),
- }));
-
- auth.getAuthenticatedUser = jest.fn(() => ({ userId: 3, administrator: true }));
- await act(async () => render(intlWrapper()));
- });
-
+describe('ProctoredExamSettings', () => {
afterEach(() => {
cleanup();
});
- it('updates zendesk ticket field if proctortrack is provider', async () => {
- await waitFor(() => {
- screen.getByDisplayValue('mockproc');
- });
- const selectElement = screen.getByDisplayValue('mockproc');
- await act(async () => {
- fireEvent.change(selectElement, { target: { value: 'proctortrack' } });
- });
- const zendeskTicketInput = screen.getByTestId('createZendeskTicketsNo');
- expect(zendeskTicketInput.checked).toEqual(true);
- });
-
- it('updates zendesk ticket field if software_secure is provider', async () => {
- await waitFor(() => {
- screen.getByDisplayValue('mockproc');
- });
- const selectElement = screen.getByDisplayValue('mockproc');
- await act(async () => {
- fireEvent.change(selectElement, { target: { value: 'software_secure' } });
- });
- const zendeskTicketInput = screen.getByTestId('createZendeskTicketsYes');
- expect(zendeskTicketInput.checked).toEqual(true);
- });
-
- it('does not update zendesk ticket field for any other provider', async () => {
- await waitFor(() => {
- screen.getByDisplayValue('mockproc');
- });
- const selectElement = screen.getByDisplayValue('mockproc');
- await act(async () => {
- fireEvent.change(selectElement, { target: { value: 'mockproc' } });
- });
- const zendeskTicketInput = screen.getByTestId('createZendeskTicketsYes');
- expect(zendeskTicketInput.checked).toEqual(true);
- });
-
- it('Hides all other fields when enabledProctorExam is false when first loaded', async () => {
- cleanup();
- auth.getAuthenticatedHttpClient = jest.fn(() => ({
- get: async () => ({
- data: {
- proctored_exam_settings: {
- enable_proctored_exams: false,
- allow_proctoring_opt_out: false,
- proctoring_provider: 'mockproc',
- proctoring_escalation_email: 'test@example.com',
- create_zendesk_tickets: true,
- },
- available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
- course_start_date: '2070-01-01T00:00:00Z',
+ describe('Field dependencies', () => {
+ beforeEach(async () => {
+ initializeMockApp({
+ authenticatedUser: {
+ userId: 3,
+ username: 'abc123',
+ administrator: true,
+ roles: [],
},
- }),
- }));
+ });
- await act(async () => render(intlWrapper()));
- await waitFor(() => {
- screen.getByLabelText('Enable Proctored Exams');
- });
- const enabledProctoredExamCheck = screen.getByLabelText('Enable Proctored Exams');
- expect(enabledProctoredExamCheck.checked).toEqual(false);
- expect(screen.queryByText('Allow Opting Out of Proctored Exams')).toBeNull();
- expect(screen.queryByDisplayValue('mockproc')).toBeNull();
- expect(screen.queryByTestId('escalationEmail')).toBeNull();
- expect(screen.queryByTestId('createZendeskTicketsYes')).toBeNull();
- expect(screen.queryByTestId('createZendeskTicketsNo')).toBeNull();
- });
+ axiosMock = new MockAdapter(getAuthenticatedHttpClient());
- it('Hides all other fields when enableProctoredExams toggled to false', async () => {
- await waitFor(() => {
- screen.getByLabelText('Enable Proctored Exams');
- });
- expect(screen.queryByText('Allow Opting Out of Proctored Exams')).toBeDefined();
- expect(screen.queryByDisplayValue('mockproc')).toBeDefined();
- expect(screen.queryByTestId('escalationEmail')).toBeDefined();
- expect(screen.queryByTestId('createZendeskTicketsYes')).toBeDefined();
- expect(screen.queryByTestId('createZendeskTicketsNo')).toBeDefined();
-
- let enabledProctorExamCheck = screen.getByLabelText('Enable Proctored Exams');
- expect(enabledProctorExamCheck.checked).toEqual(true);
- await act(async () => {
- fireEvent.click(enabledProctorExamCheck, { target: { value: false } });
- });
- enabledProctorExamCheck = screen.getByLabelText('Enable Proctored Exams');
- expect(enabledProctorExamCheck.checked).toEqual(false);
- expect(screen.queryByText('Allow Opting Out of Proctored Exams')).toBeNull();
- expect(screen.queryByDisplayValue('mockproc')).toBeNull();
- expect(screen.queryByTestId('escalationEmail')).toBeNull();
- expect(screen.queryByTestId('createZendeskTicketsYes')).toBeNull();
- expect(screen.queryByTestId('createZendeskTicketsNo')).toBeNull();
- });
-});
-
-describe('ProctoredExamSettings validation with invalid escalation email', () => {
- beforeEach(async () => {
- auth.getAuthenticatedHttpClient = jest.fn(() => ({
- get: async () => ({
- data: {
- proctored_exam_settings: {
- enable_proctored_exams: true,
- allow_proctoring_opt_out: false,
- proctoring_provider: 'proctortrack',
- proctoring_escalation_email: 'test@example.com',
- create_zendesk_tickets: true,
- },
- available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
- course_start_date: '2070-01-01T00:00:00Z',
+ axiosMock.onGet(
+ StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
+ ).reply(200, {
+ proctored_exam_settings: {
+ enable_proctored_exams: true,
+ allow_proctoring_opt_out: false,
+ proctoring_provider: 'mockproc',
+ proctoring_escalation_email: 'test@example.com',
+ create_zendesk_tickets: true,
},
- }),
- post: async () => {},
- }));
+ available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
+ course_start_date: '2070-01-01T00:00:00Z',
+ });
- auth.getAuthenticatedUser = jest.fn(() => ({ userId: 3, administrator: false }));
- await act(async () => render(intlWrapper()));
+ await act(async () => render(intlWrapper()));
+ });
+
+ it('Updates Zendesk ticket field if proctortrack is provider', async () => {
+ await waitFor(() => {
+ screen.getByDisplayValue('mockproc');
+ });
+ const selectElement = screen.getByDisplayValue('mockproc');
+ await act(async () => {
+ fireEvent.change(selectElement, { target: { value: 'proctortrack' } });
+ });
+ const zendeskTicketInput = screen.getByTestId('createZendeskTicketsNo');
+ expect(zendeskTicketInput.checked).toEqual(true);
+ });
+
+ it('Updates Zendesk ticket field if software_secure is provider', async () => {
+ await waitFor(() => {
+ screen.getByDisplayValue('mockproc');
+ });
+ const selectElement = screen.getByDisplayValue('mockproc');
+ await act(async () => {
+ fireEvent.change(selectElement, { target: { value: 'software_secure' } });
+ });
+ const zendeskTicketInput = screen.getByTestId('createZendeskTicketsYes');
+ expect(zendeskTicketInput.checked).toEqual(true);
+ });
+
+ it('Does not update zendesk ticket field for any other provider', async () => {
+ await waitFor(() => {
+ screen.getByDisplayValue('mockproc');
+ });
+ const selectElement = screen.getByDisplayValue('mockproc');
+ await act(async () => {
+ fireEvent.change(selectElement, { target: { value: 'mockproc' } });
+ });
+ const zendeskTicketInput = screen.getByTestId('createZendeskTicketsYes');
+ expect(zendeskTicketInput.checked).toEqual(true);
+ });
+
+ it('Hides all other fields when enabledProctorExam is false when first loaded', async () => {
+ cleanup();
+ // Overrides the handler defined in beforeEach.
+ axiosMock.onGet(
+ StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
+ ).reply(200, {
+ proctored_exam_settings: {
+ enable_proctored_exams: false,
+ allow_proctoring_opt_out: false,
+ proctoring_provider: 'mockproc',
+ proctoring_escalation_email: 'test@example.com',
+ create_zendesk_tickets: true,
+ },
+ available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
+ course_start_date: '2070-01-01T00:00:00Z',
+ });
+
+ await act(async () => render(intlWrapper()));
+ await waitFor(() => {
+ screen.getByLabelText('Enable Proctored Exams');
+ });
+ const enabledProctoredExamCheck = screen.getByLabelText('Enable Proctored Exams');
+ expect(enabledProctoredExamCheck.checked).toEqual(false);
+ expect(screen.queryByText('Allow Opting Out of Proctored Exams')).toBeNull();
+ expect(screen.queryByDisplayValue('mockproc')).toBeNull();
+ expect(screen.queryByTestId('escalationEmail')).toBeNull();
+ expect(screen.queryByTestId('createZendeskTicketsYes')).toBeNull();
+ expect(screen.queryByTestId('createZendeskTicketsNo')).toBeNull();
+ });
+
+ it('Hides all other fields when enableProctoredExams toggled to false', async () => {
+ await waitFor(() => {
+ screen.getByLabelText('Enable Proctored Exams');
+ });
+ expect(screen.queryByText('Allow Opting Out of Proctored Exams')).toBeDefined();
+ expect(screen.queryByDisplayValue('mockproc')).toBeDefined();
+ expect(screen.queryByTestId('escalationEmail')).toBeDefined();
+ expect(screen.queryByTestId('createZendeskTicketsYes')).toBeDefined();
+ expect(screen.queryByTestId('createZendeskTicketsNo')).toBeDefined();
+
+ let enabledProctorExamCheck = screen.getByLabelText('Enable Proctored Exams');
+ expect(enabledProctorExamCheck.checked).toEqual(true);
+ await act(async () => {
+ fireEvent.click(enabledProctorExamCheck, { target: { value: false } });
+ });
+ enabledProctorExamCheck = screen.getByLabelText('Enable Proctored Exams');
+ expect(enabledProctorExamCheck.checked).toEqual(false);
+ expect(screen.queryByText('Allow Opting Out of Proctored Exams')).toBeNull();
+ expect(screen.queryByDisplayValue('mockproc')).toBeNull();
+ expect(screen.queryByTestId('escalationEmail')).toBeNull();
+ expect(screen.queryByTestId('createZendeskTicketsYes')).toBeNull();
+ expect(screen.queryByTestId('createZendeskTicketsNo')).toBeNull();
+ });
});
- afterEach(() => {
- cleanup();
+ describe('Validation with invalid escalation email', () => {
+ beforeEach(async () => {
+ initializeMockApp({
+ authenticatedUser: {
+ userId: 3,
+ username: 'abc123',
+ administrator: false,
+ roles: [],
+ },
+ });
+
+ axiosMock = new MockAdapter(getAuthenticatedHttpClient());
+
+ axiosMock.onGet(
+ StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
+ ).reply(200, {
+ proctored_exam_settings: {
+ enable_proctored_exams: true,
+ allow_proctoring_opt_out: false,
+ proctoring_provider: 'proctortrack',
+ proctoring_escalation_email: 'test@example.com',
+ create_zendesk_tickets: true,
+ },
+ available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
+ course_start_date: '2070-01-01T00:00:00Z',
+ });
+
+ axiosMock.onPost(
+ StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
+ ).reply(200, {});
+
+ await act(async () => render(intlWrapper()));
+ });
+
+ it('Creates an alert when no proctoring escalation email is provided with proctortrack selected', async () => {
+ await waitFor(() => {
+ screen.getByDisplayValue('proctortrack');
+ });
+ const selectEscalationEmailElement = screen.getByDisplayValue('test@example.com');
+ await act(async () => {
+ fireEvent.change(selectEscalationEmailElement, { target: { value: '' } });
+ });
+ const selectButton = screen.getByTestId('submissionButton');
+ await act(async () => {
+ fireEvent.click(selectButton);
+ });
+
+ // verify alert content and focus management
+ const escalationEmailError = screen.getByTestId('proctortrackEscalationEmailError');
+ expect(escalationEmailError.textContent).not.toBeNull();
+ expect(document.activeElement).toEqual(escalationEmailError);
+
+ // verify alert link links to offending input
+ const errorLink = screen.getByTestId('proctorTrackEscalationEmailErrorLink');
+ await act(async () => {
+ fireEvent.click(errorLink);
+ });
+ const escalationEmailInput = screen.getByTestId('escalationEmail');
+ expect(document.activeElement).toEqual(escalationEmailInput);
+ });
+
+ it('Creates an alert when invalid proctoring escalation email is provided with proctortrack selected', async () => {
+ await waitFor(() => {
+ screen.getByDisplayValue('proctortrack');
+ });
+ const selectEscalationEmailElement = screen.getByDisplayValue('test@example.com');
+ await act(async () => {
+ fireEvent.change(selectEscalationEmailElement, { target: { value: 'foo.bar' } });
+ });
+ const selectButton = screen.getByTestId('submissionButton');
+ await act(async () => {
+ fireEvent.click(selectButton);
+ });
+
+ // verify alert content and focus management
+ const escalationEmailError = screen.getByTestId('proctortrackEscalationEmailError');
+ expect(document.activeElement).toEqual(escalationEmailError);
+ expect(escalationEmailError.textContent).not.toBeNull();
+ expect(document.activeElement).toEqual(escalationEmailError);
+
+ // verify alert link links to offending input
+ const errorLink = screen.getByTestId('proctorTrackEscalationEmailErrorLink');
+ await act(async () => {
+ fireEvent.click(errorLink);
+ });
+ const escalationEmailInput = screen.getByTestId('escalationEmail');
+ expect(document.activeElement).toEqual(escalationEmailInput);
+ });
+
+ it('Has no error when valid proctoring escalation email is provided with proctortrack selected', async () => {
+ await waitFor(() => {
+ screen.getByDisplayValue('proctortrack');
+ });
+ const selectEscalationEmailElement = screen.getByDisplayValue('test@example.com');
+ await act(async () => {
+ fireEvent.change(selectEscalationEmailElement, { target: { value: 'foo@bar.com' } });
+ });
+ const selectButton = screen.getByTestId('submissionButton');
+ await act(async () => {
+ fireEvent.click(selectButton);
+ });
+
+ // verify there is no escalation email alert, and focus has been set on save success alert
+ expect(screen.queryByTestId('proctortrackEscalationEmailError')).toBeNull();
+
+ const errorAlert = screen.getByTestId('saveSuccess');
+ expect(errorAlert.textContent).toEqual(
+ expect.stringContaining('Proctored exam settings saved successfully.'),
+ );
+ expect(document.activeElement).toEqual(errorAlert);
+ });
+
+ it('Escalation email field hidden when proctoring backend is not Proctortrack', async () => {
+ await waitFor(() => {
+ screen.getByDisplayValue('proctortrack');
+ });
+ const proctoringBackendSelect = screen.getByDisplayValue('proctortrack');
+ const selectEscalationEmailElement = screen.getByTestId('escalationEmail');
+ expect(selectEscalationEmailElement.value).toEqual('test@example.com');
+ await act(async () => {
+ fireEvent.change(proctoringBackendSelect, { target: { value: 'software_secure' } });
+ });
+ expect(screen.queryByTestId('escalationEmail')).toBeNull();
+ });
+
+ it('Escalation email Field Show when proctoring backend is switched back to Proctortrack', async () => {
+ await waitFor(() => {
+ screen.getByDisplayValue('proctortrack');
+ });
+ const proctoringBackendSelect = screen.getByDisplayValue('proctortrack');
+ let selectEscalationEmailElement = screen.getByTestId('escalationEmail');
+ await act(async () => {
+ fireEvent.change(proctoringBackendSelect, { target: { value: 'software_secure' } });
+ });
+ expect(screen.queryByTestId('escalationEmail')).toBeNull();
+ await act(async () => {
+ fireEvent.change(proctoringBackendSelect, { target: { value: 'proctortrack' } });
+ });
+ expect(screen.queryByTestId('escalationEmail')).toBeDefined();
+ selectEscalationEmailElement = screen.getByTestId('escalationEmail');
+ expect(selectEscalationEmailElement.value).toEqual('test@example.com');
+ });
+
+ it('Submits form when "Enter" key is hit in the escalation email field', async () => {
+ await waitFor(() => {
+ screen.getByDisplayValue('proctortrack');
+ });
+ const selectEscalationEmailElement = screen.getByDisplayValue('test@example.com');
+ await act(async () => {
+ fireEvent.change(selectEscalationEmailElement, { target: { value: '' } });
+ });
+ await act(async () => {
+ fireEvent.submit(selectEscalationEmailElement);
+ });
+ // if the error appears, the form has been submitted
+ expect(screen.getByTestId('proctortrackEscalationEmailError')).toBeDefined();
+ });
});
- it('creates an alert when no proctoring escalation email is provided with proctortrack selected', async () => {
- await waitFor(() => {
- screen.getByDisplayValue('proctortrack');
- });
- const selectEscalationEmailElement = screen.getByDisplayValue('test@example.com');
- await act(async () => {
- fireEvent.change(selectEscalationEmailElement, { target: { value: '' } });
- });
- const selectButton = screen.getByTestId('submissionButton');
- await act(async () => {
- fireEvent.click(selectButton);
- });
-
- // verify alert content and focus management
- const escalationEmailError = screen.getByTestId('proctortrackEscalationEmailError');
- expect(escalationEmailError.textContent).not.toBeNull();
- expect(document.activeElement).toEqual(escalationEmailError);
-
- // verify alert link links to offending input
- const errorLink = screen.getByTestId('proctorTrackEscalationEmailErrorLink');
- await act(async () => {
- fireEvent.click(errorLink);
- });
- fireEvent.click(errorLink);
- const escalationEmailInput = screen.getByTestId('escalationEmail');
- expect(document.activeElement).toEqual(escalationEmailInput);
- });
-
- it('creates an alert when invalid proctoring escalation email is provided with proctortrack selected', async () => {
- await waitFor(() => {
- screen.getByDisplayValue('proctortrack');
- });
- const selectEscalationEmailElement = screen.getByDisplayValue('test@example.com');
- await act(async () => {
- fireEvent.change(selectEscalationEmailElement, { target: { value: 'foo.bar' } });
- });
- const selectButton = screen.getByTestId('submissionButton');
- await act(async () => {
- fireEvent.click(selectButton);
- });
-
- // verify alert content and focus management
- const escalationEmailError = screen.getByTestId('proctortrackEscalationEmailError');
- expect(document.activeElement).toEqual(escalationEmailError);
- expect(escalationEmailError.textContent).not.toBeNull();
- expect(document.activeElement).toEqual(escalationEmailError);
-
- // verify alert link links to offending input
- const errorLink = screen.getByTestId('proctorTrackEscalationEmailErrorLink');
- await act(async () => {
- fireEvent.click(errorLink);
- });
- fireEvent.click(errorLink);
- const escalationEmailInput = screen.getByTestId('escalationEmail');
- expect(document.activeElement).toEqual(escalationEmailInput);
- });
-
- it('has no error when valid proctoring escalation email is provided with proctortrack selected', async () => {
- await waitFor(() => {
- screen.getByDisplayValue('proctortrack');
- });
- const selectEscalationEmailElement = screen.getByDisplayValue('test@example.com');
- await act(async () => {
- fireEvent.change(selectEscalationEmailElement, { target: { value: 'foo@bar.com' } });
- });
- const selectButton = screen.getByTestId('submissionButton');
- await act(async () => {
- fireEvent.click(selectButton);
- });
-
- // verify there is no escalation email alert, and focus has been set on save success alert
- expect(screen.queryByTestId('proctortrackEscalationEmailError')).toBeNull();
-
- const errorAlert = screen.getByTestId('saveSuccess');
- expect(errorAlert.textContent).toEqual(
- expect.stringContaining('Proctored exam settings saved successfully.'),
- );
- expect(document.activeElement).toEqual(errorAlert);
- });
-
- it('Escalation Email field hidden when proctoring backend is not Proctortrack', async () => {
- await waitFor(() => {
- screen.getByDisplayValue('proctortrack');
- });
- const proctoringBackendSelect = screen.getByDisplayValue('proctortrack');
- const selectEscalationEmailElement = screen.getByTestId('escalationEmail');
- expect(selectEscalationEmailElement.value).toEqual('test@example.com');
- await act(async () => {
- fireEvent.change(proctoringBackendSelect, { target: { value: 'software_secure' } });
- });
- expect(screen.queryByTestId('escalationEmail')).toBeNull();
- });
-
- it('Escalation Email Field Show when proctoring backend is switched back to Proctortrack', async () => {
- await waitFor(() => {
- screen.getByDisplayValue('proctortrack');
- });
- const proctoringBackendSelect = screen.getByDisplayValue('proctortrack');
- let selectEscalationEmailElement = screen.getByTestId('escalationEmail');
- await act(async () => {
- fireEvent.change(proctoringBackendSelect, { target: { value: 'software_secure' } });
- });
- expect(screen.queryByTestId('escalationEmail')).toBeNull();
- await act(async () => {
- fireEvent.change(proctoringBackendSelect, { target: { value: 'proctortrack' } });
- });
- expect(screen.queryByTestId('escalationEmail')).toBeDefined();
- selectEscalationEmailElement = screen.getByTestId('escalationEmail');
- expect(selectEscalationEmailElement.value).toEqual('test@example.com');
- });
-
- it('submits form when "Enter" key is hit in the escalation email field', async () => {
- await waitFor(() => {
- screen.getByDisplayValue('proctortrack');
- });
- const selectEscalationEmailElement = screen.getByDisplayValue('test@example.com');
- await act(async () => {
- fireEvent.change(selectEscalationEmailElement, { target: { value: '' } });
- });
- await act(async () => {
- fireEvent.submit(selectEscalationEmailElement);
- });
- // if the error appears, the form has been submitted
- expect(screen.getByTestId('proctortrackEscalationEmailError')).toBeDefined();
- });
-});
-
-describe('Disables proctoring provider options', () => {
- const mockGetFutureCourseData = {
- data: {
+ describe('Proctoring provider options', () => {
+ const mockGetFutureCourseData = {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
@@ -303,11 +319,9 @@ describe('Disables proctoring provider options', () => {
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
course_start_date: '2099-01-01T00:00:00Z',
- },
- };
+ };
- const mockGetPastCourseData = {
- data: {
+ const mockGetPastCourseData = {
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
@@ -317,207 +331,206 @@ describe('Disables proctoring provider options', () => {
},
available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
course_start_date: '2013-01-01T00:00:00Z',
- },
- };
+ };
- function mockAPI(getData, isAdmin) {
- const mockClientGet = jest.fn(async () => (getData));
- auth.getAuthenticatedHttpClient = jest.fn(() => ({
- get: mockClientGet,
- }));
- auth.getAuthenticatedUser = jest.fn(() => ({ userId: 3, administrator: isAdmin }));
- }
-
- afterEach(() => {
- cleanup();
- });
-
- it('disables irrelevant Proctoring Provider fields when user is not an administrator and it is after start date', async () => {
- mockAPI(mockGetPastCourseData, false);
- await act(async () => render(intlWrapper()));
- const providerOption = screen.getByTestId('proctortrack');
- expect(providerOption.hasAttribute('disabled')).toEqual(true);
- });
-
- it('enables all Proctoring Provider options if user is not an administrator and it is before start date', async () => {
- mockAPI(mockGetFutureCourseData, false);
- await act(async () => render(intlWrapper()));
- const providerOption = screen.getByTestId('proctortrack');
- expect(providerOption.hasAttribute('disabled')).toEqual(false);
- });
-
- it('enables all Proctoring Provider options if user administrator and it is after start date', async () => {
- mockAPI(mockGetPastCourseData, true);
- await act(async () => render(intlWrapper()));
- const providerOption = screen.getByTestId('proctortrack');
- expect(providerOption.hasAttribute('disabled')).toEqual(false);
- });
-
- it('enables all Proctoring Provider options if user administrator and it is before start date', async () => {
- mockAPI(mockGetFutureCourseData, true);
- await act(async () => render(intlWrapper()));
- const providerOption = screen.getByTestId('proctortrack');
- expect(providerOption.hasAttribute('disabled')).toEqual(false);
- });
-});
-
-describe('Hides fields based on user permissions', () => {
- beforeEach(async () => {
- auth.getAuthenticatedHttpClient = jest.fn(() => ({
- get: async () => ({
- data: {
- proctored_exam_settings: {
- enable_proctored_exams: true,
- allow_proctoring_opt_out: false,
- proctoring_provider: 'mockproc',
- proctoring_escalation_email: 'test@example.com',
- create_zendesk_tickets: true,
- },
- available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
- course_start_date: '2070-01-01T00:00:00Z',
+ function setup(data, isAdmin) {
+ initializeMockApp({
+ authenticatedUser: {
+ userId: 3,
+ username: 'abc123',
+ administrator: isAdmin,
+ roles: [],
},
- catch: () => {},
- }),
- }));
- });
+ });
- afterEach(() => {
- cleanup();
- });
+ axiosMock = new MockAdapter(getAuthenticatedHttpClient());
+ axiosMock.onGet(StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId)).reply(200, data);
+ }
- function mockAuthentication(isAdmin) {
- auth.getAuthenticatedUser = jest.fn(() => ({ userId: 3, administrator: isAdmin }));
- }
-
- it('hides opting out and zendesk tickets for non edX staff', async () => {
- mockAuthentication(false);
- await act(async () => render(intlWrapper()));
- expect(screen.queryByTestId('allowOptingOutYes')).toBeNull();
- expect(screen.queryByTestId('createZendeskTicketsYes')).toBeNull();
- });
-
- it('shows opting out and zendesk tickets for edX staff', async () => {
- mockAuthentication(true);
- await act(async () => render(intlWrapper()));
- expect(screen.queryByTestId('allowOptingOutYes')).not.toBeNull();
- expect(screen.queryByTestId('createZendeskTicketsYes')).not.toBeNull();
- });
-});
-
-describe('ProctoredExamSettings connection states tests', () => {
- it('shows the spinner before the connection is complete', async () => {
- auth.getAuthenticatedUser = jest.fn(() => ({ userId: 3, administrator: false }));
- auth.getAuthenticatedHttpClient = jest.fn(() => ({
- get: jest.fn(() => new Promise(() => {})),
- }));
- render();
- const spinner = screen.getByTestId('spinnerContainer');
- expect(spinner.textContent).toEqual('Loading...');
- });
-
- it('show connection error message when we suffer server side error', async () => {
- const errorObject = {
- customAttributes: {
- httpErrorStatus: 500,
- },
- };
- auth.getAuthenticatedHttpClient = jest.fn(() => ({
- get: async () => {
- throw errorObject;
- },
- }));
-
- await act(async () => render(intlWrapper()));
- const connectionError = screen.getByTestId('connectionError');
- expect(connectionError.textContent).toEqual(
- expect.stringContaining('We encountered a technical error'),
- );
- });
-
- it('show permission error message when user do not have enough permission', async () => {
- const errorObject = {
- customAttributes: {
- httpErrorStatus: 403,
- },
- };
- auth.getAuthenticatedHttpClient = jest.fn(() => ({
- get: async () => {
- throw errorObject;
- },
- }));
-
- await act(async () => render(intlWrapper()));
- const connectionError = screen.getByTestId('permissionError');
- expect(connectionError.textContent).toEqual(
- expect.stringContaining('You are not authorized to view this page'),
- );
- });
-
- afterEach(() => {
- cleanup();
- });
-});
-
-describe('ProctoredExamSettings save settings tests', () => {
- const mockGetData = {
- data: {
- proctored_exam_settings: {
- enable_proctored_exams: true,
- allow_proctoring_opt_out: false,
- proctoring_provider: 'mockproc',
- proctoring_escalation_email: 'test@example.com',
- create_zendesk_tickets: true,
- },
- available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
- },
- };
-
- function mockAPI(getData, postResult) {
- const mockClientGet = jest.fn(async () => (getData));
- const mockClientPost = postResult ? jest.fn(async () => (postResult)) : jest.fn(async () => { throw new Error(); });
- auth.getAuthenticatedHttpClient = jest.fn(() => ({
- get: mockClientGet,
- post: mockClientPost,
- }));
- auth.getAuthenticatedUser = jest.fn(() => ({ userId: 3, administrator: true }));
- return { mockClientGet, mockClientPost };
- }
-
- it('Show spinner while saving', async () => {
- const mockedFunctions = mockAPI(mockGetData, { data: 'success' });
- await act(async () => render(intlWrapper()));
- const submitButton = screen.getByTestId('submissionButton');
- expect(screen.queryByTestId('saveInProgress')).toBeFalsy();
- fireEvent.click(submitButton);
- const submitSpinner = screen.getByTestId('saveInProgress');
- expect(submitSpinner).toBeDefined();
- expect(mockedFunctions.mockClientPost).toHaveBeenCalled();
- await waitForElementToBeRemoved(submitSpinner);
- expect(screen.queryByTestId('saveInProgress')).toBeFalsy();
- });
-
- it('Makes API call successfully with proctoring_escalation_email if proctortrack', async () => {
- const mockedFunctions = mockAPI(mockGetData, { data: 'success' });
- await act(async () => render(intlWrapper()));
- // Make a change to the provider to proctortrack and set the email
- const selectElement = screen.getByDisplayValue('mockproc');
- await act(async () => {
- fireEvent.change(selectElement, { target: { value: 'proctortrack' } });
+ it('Disables irrelevant proctoring provider fields when user is not an administrator and it is after start date', async () => {
+ setup(mockGetPastCourseData, false);
+ await act(async () => render(intlWrapper()));
+ const providerOption = screen.getByTestId('proctortrack');
+ expect(providerOption.hasAttribute('disabled')).toEqual(true);
});
- const escalationEmail = screen.getByTestId('escalationEmail');
- expect(escalationEmail.value).toEqual('test@example.com');
- await act(async () => {
- fireEvent.change(escalationEmail, { target: { value: 'proctortrack@example.com' } });
+
+ it('Enables all proctoring provider options if user is not an administrator and it is before start date', async () => {
+ setup(mockGetFutureCourseData, false);
+ await act(async () => render(intlWrapper()));
+ const providerOption = screen.getByTestId('proctortrack');
+ expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
- expect(escalationEmail.value).toEqual('proctortrack@example.com');
- const submitButton = screen.getByTestId('submissionButton');
- await act(async () => {
- fireEvent.click(submitButton);
+
+ it('Enables all proctoring provider options if user administrator and it is after start date', async () => {
+ setup(mockGetPastCourseData, true);
+ await act(async () => render(intlWrapper()));
+ const providerOption = screen.getByTestId('proctortrack');
+ expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
- expect(mockedFunctions.mockClientPost).toHaveBeenCalled();
- expect(mockedFunctions.mockClientPost).toHaveBeenCalledWith(
- StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
- {
+
+ it('Enables all proctoring provider options if user administrator and it is before start date', async () => {
+ setup(mockGetFutureCourseData, true);
+ await act(async () => render(intlWrapper()));
+ const providerOption = screen.getByTestId('proctortrack');
+ expect(providerOption.hasAttribute('disabled')).toEqual(false);
+ });
+ });
+
+ describe('Toggles field visibility based on user permissions', () => {
+ function setup(isAdmin) {
+ initializeMockApp({
+ authenticatedUser: {
+ userId: 3,
+ username: 'abc123',
+ administrator: isAdmin,
+ roles: [],
+ },
+ });
+
+ axiosMock = new MockAdapter(getAuthenticatedHttpClient());
+ axiosMock.onGet(StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId)).reply(200, {
+ proctored_exam_settings: {
+ enable_proctored_exams: true,
+ allow_proctoring_opt_out: false,
+ proctoring_provider: 'mockproc',
+ proctoring_escalation_email: 'test@example.com',
+ create_zendesk_tickets: true,
+ },
+ available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
+ course_start_date: '2070-01-01T00:00:00Z',
+ });
+ }
+
+ it('Hides opting out and zendesk tickets for non edX staff', async () => {
+ setup(false);
+ await act(async () => render(intlWrapper()));
+ expect(screen.queryByTestId('allowOptingOutYes')).toBeNull();
+ expect(screen.queryByTestId('createZendeskTicketsYes')).toBeNull();
+ });
+
+ it('Shows opting out and zendesk tickets for edX staff', async () => {
+ setup(true);
+ await act(async () => render(intlWrapper()));
+ expect(screen.queryByTestId('allowOptingOutYes')).not.toBeNull();
+ expect(screen.queryByTestId('createZendeskTicketsYes')).not.toBeNull();
+ });
+ });
+
+ describe('Connection states', () => {
+ beforeEach(() => {
+ initializeMockApp({
+ authenticatedUser: {
+ userId: 3,
+ username: 'abc123',
+ administrator: true,
+ roles: [],
+ },
+ });
+ axiosMock = new MockAdapter(getAuthenticatedHttpClient());
+ });
+
+ it('Shows the spinner before the connection is complete', async () => {
+ await act(async () => {
+ render(intlWrapper());
+ // This expectation is _inside_ the `act` intentionally, so that it executes immediately.
+ const spinner = screen.getByTestId('spinnerContainer');
+ expect(spinner.textContent).toEqual('Loading...');
+ });
+ });
+
+ it('Show connection error message when we suffer server side error', async () => {
+ axiosMock.onGet(
+ StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
+ ).reply(500);
+
+ await act(async () => render(intlWrapper()));
+ const connectionError = screen.getByTestId('connectionError');
+ expect(connectionError.textContent).toEqual(
+ expect.stringContaining('We encountered a technical error'),
+ );
+ });
+
+ it('Show permission error message when user do not have enough permission', async () => {
+ axiosMock.onGet(
+ StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
+ ).reply(403);
+
+ await act(async () => render(intlWrapper()));
+ const connectionError = screen.getByTestId('permissionError');
+ expect(connectionError.textContent).toEqual(
+ expect.stringContaining('You are not authorized to view this page'),
+ );
+ });
+ });
+
+ describe('Save settings', () => {
+ beforeEach(() => {
+ initializeMockApp({
+ authenticatedUser: {
+ userId: 3,
+ username: 'abc123',
+ administrator: true,
+ roles: [],
+ },
+ });
+
+ axiosMock = new MockAdapter(getAuthenticatedHttpClient(), { onNoMatch: 'throwException' });
+ axiosMock.onGet(StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId)).reply(200, {
+ proctored_exam_settings: {
+ enable_proctored_exams: true,
+ allow_proctoring_opt_out: false,
+ proctoring_provider: 'mockproc',
+ proctoring_escalation_email: 'test@example.com',
+ create_zendesk_tickets: true,
+ },
+ available_proctoring_providers: ['software_secure', 'proctortrack', 'mockproc'],
+ });
+ });
+
+ it('Show spinner while saving', async () => {
+ axiosMock.onPost(
+ StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
+ ).reply(200, 'success');
+
+ await act(async () => render(intlWrapper()));
+ const submitButton = screen.getByTestId('submissionButton');
+ expect(screen.queryByTestId('saveInProgress')).toBeFalsy();
+ act(() => {
+ fireEvent.click(submitButton);
+ });
+
+ const submitSpinner = screen.getByTestId('saveInProgress');
+ expect(submitSpinner).toBeDefined();
+
+ await waitForElementToBeRemoved(submitSpinner);
+ expect(axiosMock.history.get.length).toBe(1);
+ expect(axiosMock.history.post.length).toBe(1);
+ expect(screen.queryByTestId('saveInProgress')).toBeFalsy();
+ });
+
+ it('Makes API call successfully with proctoring_escalation_email if proctortrack', async () => {
+ axiosMock.onPost(
+ StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
+ ).reply(200, 'success');
+
+ await act(async () => render(intlWrapper()));
+ // Make a change to the provider to proctortrack and set the email
+ const selectElement = screen.getByDisplayValue('mockproc');
+ await act(async () => {
+ fireEvent.change(selectElement, { target: { value: 'proctortrack' } });
+ });
+ const escalationEmail = screen.getByTestId('escalationEmail');
+ expect(escalationEmail.value).toEqual('test@example.com');
+ await act(async () => {
+ fireEvent.change(escalationEmail, { target: { value: 'proctortrack@example.com' } });
+ });
+ expect(escalationEmail.value).toEqual('proctortrack@example.com');
+ const submitButton = screen.getByTestId('submissionButton');
+ await act(async () => {
+ fireEvent.click(submitButton);
+ });
+ expect(axiosMock.history.post.length).toBe(1);
+ expect(JSON.parse(axiosMock.history.post[0].data)).toEqual({
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
@@ -525,89 +538,96 @@ describe('ProctoredExamSettings save settings tests', () => {
proctoring_escalation_email: 'proctortrack@example.com',
create_zendesk_tickets: false,
},
- },
- );
- const errorAlert = screen.getByTestId('saveSuccess');
- expect(errorAlert.textContent).toEqual(
- expect.stringContaining('Proctored exam settings saved successfully.'),
- );
- expect(document.activeElement).toEqual(errorAlert);
- });
+ });
- it('Makes API call successfully without proctoring_escalation_email if not proctortrack', async () => {
- const mockedFunctions = mockAPI(mockGetData, { data: 'success' });
- await act(async () => render(intlWrapper()));
-
- // make sure we have not selected proctortrack as the proctoring provider
- expect(screen.getByDisplayValue('mockproc')).toBeDefined();
-
- const submitButton = screen.getByTestId('submissionButton');
- await act(async () => {
- fireEvent.click(submitButton);
+ const errorAlert = screen.getByTestId('saveSuccess');
+ expect(errorAlert.textContent).toEqual(
+ expect.stringContaining('Proctored exam settings saved successfully.'),
+ );
+ expect(document.activeElement).toEqual(errorAlert);
});
- expect(mockedFunctions.mockClientPost).toHaveBeenCalled();
- expect(mockedFunctions.mockClientPost).toHaveBeenCalledWith(
- StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
- {
+
+ it('Makes API call successfully without proctoring_escalation_email if not proctortrack', async () => {
+ axiosMock.onPost(
+ StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
+ ).reply(200, 'success');
+
+ await act(async () => render(intlWrapper()));
+
+ // make sure we have not selected proctortrack as the proctoring provider
+ expect(screen.getByDisplayValue('mockproc')).toBeDefined();
+
+ const submitButton = screen.getByTestId('submissionButton');
+ await act(async () => {
+ fireEvent.click(submitButton);
+ });
+ expect(axiosMock.history.post.length).toBe(1);
+ expect(JSON.parse(axiosMock.history.post[0].data)).toEqual({
proctored_exam_settings: {
enable_proctored_exams: true,
allow_proctoring_opt_out: false,
proctoring_provider: 'mockproc',
create_zendesk_tickets: true,
},
- },
- );
- const errorAlert = screen.getByTestId('saveSuccess');
- expect(errorAlert.textContent).toEqual(
- expect.stringContaining('Proctored exam settings saved successfully.'),
- );
- expect(document.activeElement).toEqual(errorAlert);
- });
+ });
- it('Makes API call generated error', async () => {
- const mockedFunctions = mockAPI(mockGetData, false);
- await act(async () => render(intlWrapper()));
- const submitButton = screen.getByTestId('submissionButton');
- await act(async () => {
- fireEvent.click(submitButton);
+ const errorAlert = screen.getByTestId('saveSuccess');
+ expect(errorAlert.textContent).toEqual(
+ expect.stringContaining('Proctored exam settings saved successfully.'),
+ );
+ expect(document.activeElement).toEqual(errorAlert);
});
- expect(mockedFunctions.mockClientPost).toHaveBeenCalled();
- const errorAlert = screen.getByTestId('saveError');
- expect(errorAlert.textContent).toEqual(
- expect.stringContaining('We encountered a technical error while trying to save proctored exam settings'),
- );
- expect(document.activeElement).toEqual(errorAlert);
- });
- it('Manages focus correctly after different save statuses', async () => {
- // first make a call that will cause a save error
- const mockedFunctionsBadCall = mockAPI(mockGetData, false);
- await act(async () => render(intlWrapper()));
- const submitButton = screen.getByTestId('submissionButton');
- await act(async () => {
- fireEvent.click(submitButton);
+ it('Makes API call generated error', async () => {
+ axiosMock.onPost(
+ StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
+ ).reply(500);
+
+ await act(async () => render(intlWrapper()));
+ const submitButton = screen.getByTestId('submissionButton');
+ await act(async () => {
+ fireEvent.click(submitButton);
+ });
+ expect(axiosMock.history.post.length).toBe(1);
+ const errorAlert = screen.getByTestId('saveError');
+ expect(errorAlert.textContent).toEqual(
+ expect.stringContaining('We encountered a technical error while trying to save proctored exam settings'),
+ );
+ expect(document.activeElement).toEqual(errorAlert);
});
- expect(mockedFunctionsBadCall.mockClientPost).toHaveBeenCalled();
- const errorAlert = screen.getByTestId('saveError');
- expect(errorAlert.textContent).toEqual(
- expect.stringContaining('We encountered a technical error while trying to save proctored exam settings'),
- );
- expect(document.activeElement).toEqual(errorAlert);
- // now make a call that will allow for a successful save
- const mockedFunctionsGoodCall = mockAPI(mockGetData, { data: 'success' });
- await act(async () => {
- fireEvent.click(submitButton);
+ it('Manages focus correctly after different save statuses', async () => {
+ // first make a call that will cause a save error
+ axiosMock.onPost(
+ StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
+ ).replyOnce(500);
+
+ await act(async () => render(intlWrapper()));
+ const submitButton = screen.getByTestId('submissionButton');
+ await act(async () => {
+ fireEvent.click(submitButton);
+ });
+ expect(axiosMock.history.post.length).toBe(1);
+ const errorAlert = screen.getByTestId('saveError');
+ expect(errorAlert.textContent).toEqual(
+ expect.stringContaining('We encountered a technical error while trying to save proctored exam settings'),
+ );
+ expect(document.activeElement).toEqual(errorAlert);
+
+ // now make a call that will allow for a successful save
+ axiosMock.onPost(
+ StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
+ ).replyOnce(200, 'success');
+ await act(async () => {
+ fireEvent.click(submitButton);
+ });
+
+ expect(axiosMock.history.post.length).toBe(2);
+ const successAlert = screen.getByTestId('saveSuccess');
+ expect(successAlert.textContent).toEqual(
+ expect.stringContaining('Proctored exam settings saved successfully.'),
+ );
+ expect(document.activeElement).toEqual(successAlert);
});
- expect(mockedFunctionsGoodCall.mockClientPost).toHaveBeenCalled();
- const successAlert = screen.getByTestId('saveSuccess');
- expect(successAlert.textContent).toEqual(
- expect.stringContaining('Proctored exam settings saved successfully.'),
- );
- expect(document.activeElement).toEqual(successAlert);
- });
-
- afterEach(() => {
- cleanup();
});
});
diff --git a/src/setupTest.js b/src/setupTest.js
index 9a11bbb28..36691d2c3 100755
--- a/src/setupTest.js
+++ b/src/setupTest.js
@@ -1,9 +1,5 @@
-import axios from 'axios';
-import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import 'core-js/stable';
import 'regenerator-runtime/runtime';
import { configure } from '@testing-library/react';
configure({ testIdAttribute: 'data-test-id' });
-jest.mock('@edx/frontend-platform/auth');
-getAuthenticatedHttpClient.mockReturnValue(axios);