Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ module.exports = createConfig(
'no-restricted-exports': 'off',
// There is no reason to disallow this syntax anymore; we don't use regenerator-runtime in new browsers
'no-restricted-syntax': 'off',
'no-restricted-imports': ['error', {
patterns: [
{
group: ['@edx/frontend-platform/i18n'],
importNames: ['injectIntl'],
message: "Use 'useIntl' hook instead of injectIntl.",
},
],
}],
},
settings: {
// Import URLs should be resolved using aliases
Expand Down
4 changes: 2 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ We're trying to move away from some deprecated patterns in this codebase. Please
check if your PR meets these recommendations before asking for a review:

- [ ] Any _new_ files are using TypeScript (`.ts`, `.tsx`).
- [ ] Deprecated `propTypes`, `defaultProps`, and `injectIntl` patterns are not used in any new or modified code.
- [ ] Avoid `propTypes` and `defaultProps` in any new or modified code.
- [ ] Tests should use the helpers in `src/testUtils.tsx` (specifically `initializeMocks`)
- [ ] Do not add new fields to the Redux state/store. Use React Context to share state among multiple components.
- [ ] Use React Query to load data from REST APIs. See any `apiHooks.ts` in this repo for examples.
- [ ] All new i18n messages in `messages.ts` files have a `description` for translators to use.
- [ ] Imports avoid using `../`. To import from parent folders, use `@src`, e.g. `import { initializeMocks } from '@src/testUtils';` instead of `from '../../../../testUtils'`
- [ ] Avoid using `../` in import paths. To import from parent folders, use `@src`, e.g. `import { initializeMocks } from '@src/testUtils';` instead of `from '../../../../testUtils'`
63 changes: 31 additions & 32 deletions plugins/course-apps/proctoring/Settings.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import MockAdapter from 'axios-mock-adapter';

import { initializeMockApp, mergeConfig } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { AppProvider } from '@edx/frontend-platform/react';

import StudioApiService from 'CourseAuthoring/data/services/StudioApiService';
Expand All @@ -20,7 +20,6 @@ const defaultProps = {
courseId,
onClose: () => {},
};
const IntlProctoredExamSettings = injectIntl(ProctoredExamSettings);
let store;

const intlWrapper = children => (
Expand Down Expand Up @@ -102,7 +101,7 @@ describe('ProctoredExamSettings', () => {

describe('Field dependencies', () => {
beforeEach(async () => {
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
});

it('Updates Zendesk ticket field if proctortrack is provider', async () => {
Expand Down Expand Up @@ -152,7 +151,7 @@ describe('ProctoredExamSettings', () => {
course_start_date: '2070-01-01T00:00:00Z',
});

await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByText('Proctored exams');
});
Expand Down Expand Up @@ -225,7 +224,7 @@ describe('ProctoredExamSettings', () => {
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, {});

await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
});

proctoringProvidersRequiringEscalationEmail.forEach(provider => {
Expand Down Expand Up @@ -409,7 +408,7 @@ describe('ProctoredExamSettings', () => {
const isAdmin = false;
setupApp(isAdmin);
mockCourseData(mockGetPastCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const providerOption = screen.getByTestId('proctortrack');
expect(providerOption.hasAttribute('disabled')).toEqual(true);
});
Expand All @@ -418,7 +417,7 @@ describe('ProctoredExamSettings', () => {
const isAdmin = false;
setupApp(isAdmin);
mockCourseData(mockGetFutureCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const providerOption = screen.getByTestId('proctortrack');
expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
Expand All @@ -428,7 +427,7 @@ describe('ProctoredExamSettings', () => {
const org = 'test-org';
setupApp(isAdmin, org);
mockCourseData(mockGetFutureCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const providerOption = screen.getByTestId('proctortrack');
expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
Expand All @@ -437,7 +436,7 @@ describe('ProctoredExamSettings', () => {
const isAdmin = true;
setupApp(isAdmin);
mockCourseData(mockGetPastCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const providerOption = screen.getByTestId('proctortrack');
expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
Expand All @@ -446,7 +445,7 @@ describe('ProctoredExamSettings', () => {
const isAdmin = true;
setupApp(isAdmin);
mockCourseData(mockGetFutureCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const providerOption = screen.getByTestId('proctortrack');
expect(providerOption.hasAttribute('disabled')).toEqual(false);
});
Expand All @@ -457,7 +456,7 @@ describe('ProctoredExamSettings', () => {
available_proctoring_providers: ['lti_external', 'proctortrack', 'mockproc'],
};
mockCourseData(courseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
Expand All @@ -470,7 +469,7 @@ describe('ProctoredExamSettings', () => {
available_proctoring_providers: ['lti_external', 'proctortrack', 'mockproc'],
};
mockCourseData(courseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
Expand All @@ -483,7 +482,7 @@ describe('ProctoredExamSettings', () => {
const isAdmin = true;
setupApp(isAdmin);
mockCourseData(mockGetFutureCourseData);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
Expand All @@ -497,7 +496,7 @@ describe('ProctoredExamSettings', () => {
EXAMS_BASE_URL: null,
}, 'CourseAuthoringConfig');

await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByDisplayValue('mockproc');
});
Expand All @@ -516,7 +515,7 @@ describe('ProctoredExamSettings', () => {
).reply(200, {
provider: 'test_lti',
});
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
await waitFor(() => {
screen.getByText('Proctoring provider');
});
Expand All @@ -529,22 +528,22 @@ describe('ProctoredExamSettings', () => {
describe('Toggles field visibility based on user permissions', () => {
it('Hides opting out and zendesk tickets for non edX staff', async () => {
setupApp(false);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
expect(screen.queryByTestId('allowOptingOutYes')).toBeNull();
expect(screen.queryByTestId('createZendeskTicketsYes')).toBeNull();
});

it('Shows opting out and zendesk tickets for edX staff', async () => {
setupApp(true);
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
expect(screen.queryByTestId('allowOptingOutYes')).not.toBeNull();
expect(screen.queryByTestId('createZendeskTicketsYes')).not.toBeNull();
});
});

describe('Connection states', () => {
it('Shows the spinner before the connection is complete', async () => {
render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />));
render(intlWrapper(<ProctoredExamSettings {...defaultProps} />));
const spinner = await screen.findByRole('status');
expect(spinner.textContent).toEqual('Loading...');
});
Expand All @@ -554,7 +553,7 @@ describe('ProctoredExamSettings', () => {
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(500);

await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const connectionError = screen.getByTestId('connectionErrorAlert');
expect(connectionError.textContent).toEqual(
expect.stringContaining('We encountered a technical error when loading this page.'),
Expand All @@ -566,7 +565,7 @@ describe('ProctoredExamSettings', () => {
`${ExamsApiService.getExamsBaseUrl()}/api/v1/providers`,
).reply(500);

await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const connectionError = screen.getByTestId('connectionErrorAlert');
expect(connectionError.textContent).toEqual(
expect.stringContaining('We encountered a technical error when loading this page.'),
Expand All @@ -578,7 +577,7 @@ describe('ProctoredExamSettings', () => {
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(403);

await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const permissionError = screen.getByTestId('permissionDeniedAlert');
expect(permissionError.textContent).toEqual(
expect.stringContaining('You are not authorized to view this page'),
Expand All @@ -597,7 +596,7 @@ describe('ProctoredExamSettings', () => {
});

it('Disable button while submitting', async () => {
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
let submitButton = screen.getByTestId('submissionButton');
expect(screen.queryByTestId('saveInProgress')).toBeFalsy();
fireEvent.click(submitButton);
Expand All @@ -607,7 +606,7 @@ describe('ProctoredExamSettings', () => {
});

it('Makes API call successfully with proctoring_escalation_email if proctortrack', async () => {
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
// Make a change to the provider to proctortrack and set the email
const selectElement = screen.getByDisplayValue('mockproc');
fireEvent.change(selectElement, { target: { value: 'proctortrack' } });
Expand Down Expand Up @@ -638,7 +637,7 @@ describe('ProctoredExamSettings', () => {
});

it('Makes API call successfully without proctoring_escalation_email if not proctortrack', async () => {
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));

// make sure we have not selected proctortrack as the proctoring provider
expect(screen.getByDisplayValue('mockproc')).toBeDefined();
Expand All @@ -665,7 +664,7 @@ describe('ProctoredExamSettings', () => {
});

it('Successfully updates exam configuration and studio provider is set to "lti_external" for lti providers', async () => {
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
// Make a change to the provider to test_lti and set the email
const selectElement = screen.getByDisplayValue('mockproc');
fireEvent.change(selectElement, { target: { value: 'test_lti' } });
Expand Down Expand Up @@ -706,7 +705,7 @@ describe('ProctoredExamSettings', () => {
});

it('Sets exam service provider to null if a non-lti provider is selected', async () => {
await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
fireEvent.click(submitButton);
// update exam service config
Expand Down Expand Up @@ -750,7 +749,7 @@ describe('ProctoredExamSettings', () => {
course_start_date: '2070-01-01T00:00:00Z',
});

await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
fireEvent.click(submitButton);
// does not update exam service config
Expand Down Expand Up @@ -780,7 +779,7 @@ describe('ProctoredExamSettings', () => {
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(500);

await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
fireEvent.click(submitButton);
expect(axiosMock.history.post.length).toBe(1);
Expand All @@ -798,7 +797,7 @@ describe('ProctoredExamSettings', () => {
`${ExamsApiService.getExamsBaseUrl()}/api/v1/configs/course_id/${defaultProps.courseId}`,
).reply(500, 'error');

await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
fireEvent.click(submitButton);
expect(axiosMock.history.post.length).toBe(1);
Expand All @@ -816,7 +815,7 @@ describe('ProctoredExamSettings', () => {
`${ExamsApiService.getExamsBaseUrl()}/api/v1/configs/course_id/${defaultProps.courseId}`,
).reply(403, 'error');

await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
fireEvent.click(submitButton);
expect(axiosMock.history.post.length).toBe(1);
Expand All @@ -835,7 +834,7 @@ describe('ProctoredExamSettings', () => {
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(500);

await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
const submitButton = screen.getByTestId('submissionButton');
fireEvent.click(submitButton);
expect(axiosMock.history.post.length).toBe(1);
Expand Down Expand Up @@ -868,7 +867,7 @@ describe('ProctoredExamSettings', () => {
const isAdmin = false;
setupApp(isAdmin);

await act(async () => render(intlWrapper(<IntlProctoredExamSettings {...defaultProps} />)));
await act(async () => render(intlWrapper(<ProctoredExamSettings {...defaultProps} />)));
// Make a change to the proctoring provider
const selectElement = screen.getByDisplayValue('mockproc');
fireEvent.change(selectElement, { target: { value: 'proctortrack' } });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
import { injectIntl, FormattedMessage, FormattedNumber } from '@edx/frontend-platform/i18n';
import { FormattedMessage, FormattedNumber } from '@edx/frontend-platform/i18n';
import { Icon } from '@openedx/paragon';
import { Link } from 'react-router-dom';
import { ModeComment } from '@openedx/paragon/icons';
Expand Down Expand Up @@ -127,4 +127,4 @@ ChecklistItemComment.propTypes = {
]).isRequired,
};

export default injectIntl(ChecklistItemComment);
export default ChecklistItemComment;
Loading