Skip to content

Commit 1466370

Browse files
committed
refactor: Details to finish migration
1 parent c7ae7f8 commit 1466370

49 files changed

Lines changed: 270 additions & 395 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

plugins/course-apps/proctoring/Settings.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { useModel } from 'CourseAuthoring/generic/model-store';
2222
import PermissionDeniedAlert from 'CourseAuthoring/generic/PermissionDeniedAlert';
2323
import { useIsMobile } from 'CourseAuthoring/utils';
2424
import { PagesAndResourcesContext } from 'CourseAuthoring/pages-and-resources/PagesAndResourcesProvider';
25+
import { useCourseAuthoringContext } from 'CourseAuthoring/CourseAuthoringContext';
2526

2627
import messages from './messages';
2728

@@ -66,7 +67,7 @@ const ProctoringSettings = ({ onClose }) => {
6667
}
6768

6869
const { courseId } = useContext(PagesAndResourcesContext);
69-
const courseDetails = useModel('courseDetails', courseId);
70+
const { courseDetails } = useCourseAuthoringContext();
7071
const org = courseDetails?.org;
7172
const appInfo = useModel('courseApps', 'proctoring');
7273
const alertRef = React.createRef();

plugins/course-apps/proctoring/Settings.test.jsx

Lines changed: 69 additions & 78 deletions
Large diffs are not rendered by default.

src/CourseAuthoringContext.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createContext, useContext, useMemo } from 'react';
2+
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
23
import { CourseDetailsData } from './data/api';
34
import { useCourseDetails } from './data/apiHooks';
45
import { RequestStatusType } from './data/constants';
@@ -8,6 +9,7 @@ export type CourseAuthoringContextData = {
89
courseId: string;
910
courseDetails?: CourseDetailsData;
1011
courseDetailStatus: RequestStatusType;
12+
canChangeProviders: boolean;
1113
};
1214

1315
/**
@@ -29,19 +31,22 @@ export const CourseAuthoringProvider = ({
2931
courseId,
3032
}: CourseAuthoringProviderProps) => {
3133
const { data: courseDetails, status: courseDetailStatus } = useCourseDetails(courseId);
34+
const canChangeProviders = getAuthenticatedUser().administrator || new Date(courseDetails?.start ?? 0) > new Date();
3235

3336
const context = useMemo<CourseAuthoringContextData>(() => {
3437
const contextValue = {
3538
courseId,
3639
courseDetails,
3740
courseDetailStatus,
41+
canChangeProviders,
3842
};
3943

4044
return contextValue;
4145
}, [
4246
courseId,
4347
courseDetails,
4448
courseDetailStatus,
49+
canChangeProviders,
4550
]);
4651

4752
return (
Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import CourseAuthoringPage from './CourseAuthoringPage';
44
import PagesAndResources from './pages-and-resources/PagesAndResources';
55
import { executeThunk } from './utils';
66
import { fetchCourseApps } from './pages-and-resources/data/thunks';
7-
import { fetchCourseDetail } from './data/thunks';
87
import { getApiWaffleFlagsUrl } from './data/api';
98
import { initializeMocks, render } from './testUtils';
9+
import { CourseAuthoringProvider } from './CourseAuthoringContext';
1010

1111
const courseId = 'course-v1:edX+TestX+Test_Course';
1212
let mockPathname = '/evilguy/';
@@ -19,6 +19,12 @@ jest.mock('react-router-dom', () => ({
1919
let axiosMock;
2020
let store;
2121

22+
const renderComponent = children => render(
23+
<CourseAuthoringProvider courseId={courseId}>
24+
{children}
25+
</CourseAuthoringProvider>,
26+
);
27+
2228
beforeEach(async () => {
2329
const mocks = initializeMocks();
2430
store = mocks.reduxStore;
@@ -35,14 +41,13 @@ describe('Editor Pages Load no header', () => {
3541
axiosMock.onGet(`${courseAppsApiUrl}/${courseId}`).reply(200, {
3642
response: { status: 200 },
3743
});
38-
await executeThunk(fetchCourseApps(courseId), store.dispatch);
3944
};
4045
test('renders no loading wheel on editor pages', async () => {
4146
mockPathname = '/editor/';
4247
await mockStoreSuccess();
43-
const wrapper = render(
44-
<CourseAuthoringPage courseId={courseId}>
45-
<PagesAndResources courseId={courseId} />
48+
const wrapper = renderComponent(
49+
<CourseAuthoringPage>
50+
<PagesAndResources />
4651
</CourseAuthoringPage>
4752
,
4853
);
@@ -51,9 +56,9 @@ describe('Editor Pages Load no header', () => {
5156
test('renders loading wheel on non editor pages', async () => {
5257
mockPathname = '/evilguy/';
5358
await mockStoreSuccess();
54-
const wrapper = render(
55-
<CourseAuthoringPage courseId={courseId}>
56-
<PagesAndResources courseId={courseId} />
59+
const wrapper = renderComponent(
60+
<CourseAuthoringPage>
61+
<PagesAndResources />
5762
</CourseAuthoringPage>
5863
,
5964
);
@@ -70,19 +75,17 @@ describe('Course authoring page', () => {
7075
).reply(404, {
7176
response: { status: 404 },
7277
});
73-
await executeThunk(fetchCourseDetail(courseId), store.dispatch);
7478
};
7579
const mockStoreError = async () => {
7680
axiosMock.onGet(
7781
`${courseDetailApiUrl}/${courseId}?username=abc123`,
7882
).reply(500, {
7983
response: { status: 500 },
8084
});
81-
await executeThunk(fetchCourseDetail(courseId), store.dispatch);
8285
};
8386
test('renders not found page on non-existent course key', async () => {
8487
await mockStoreNotFound();
85-
const wrapper = render(<CourseAuthoringPage courseId={courseId} />);
88+
const wrapper = renderComponent(<CourseAuthoringPage />);
8689
expect(await wrapper.findByTestId('notFoundAlert')).toBeInTheDocument();
8790
});
8891
test('does not render not found page on other kinds of error', async () => {
@@ -92,8 +95,8 @@ describe('Course authoring page', () => {
9295
// IN_PROGRESS but also not NOT_FOUND or DENIED- then check that the not
9396
// found alert is not present.
9497
const contentTestId = 'courseAuthoringPageContent';
95-
const wrapper = render(
96-
<CourseAuthoringPage courseId={courseId}>
98+
const wrapper = renderComponent(
99+
<CourseAuthoringPage>
97100
<div data-testid={contentTestId} />
98101
</CourseAuthoringPage>
99102
,
@@ -114,7 +117,7 @@ describe('Course authoring page', () => {
114117
mockPathname = '/editor/';
115118
await mockStoreDenied();
116119

117-
const wrapper = render(<CourseAuthoringPage courseId={courseId} />);
120+
const wrapper = renderComponent(<CourseAuthoringPage />);
118121
expect(await wrapper.findByTestId('permissionDeniedAlert')).toBeInTheDocument();
119122
});
120123
});
Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,11 @@ jest.mock('./custom-pages/CustomPages', () => (props) => {
4848

4949
describe('<CourseAuthoringRoutes>', () => {
5050
beforeEach(async () => {
51-
const { axiosMock } = initializeMocks();
51+
const user = {
52+
userId: 1,
53+
username: 'username',
54+
};
55+
const { axiosMock } = initializeMocks({ user });
5256
axiosMock
5357
.onGet(getApiWaffleFlagsUrl(courseId))
5458
.reply(200, {});
@@ -61,11 +65,7 @@ describe('<CourseAuthoringRoutes>', () => {
6165
);
6266
await waitFor(() => {
6367
expect(screen.getByText(pagesAndResourcesMockText)).toBeVisible();
64-
expect(mockComponentFn).toHaveBeenCalledWith(
65-
expect.objectContaining({
66-
courseId,
67-
}),
68-
);
68+
expect(mockComponentFn).toHaveBeenCalled();
6969
});
7070
});
7171

@@ -93,11 +93,7 @@ describe('<CourseAuthoringRoutes>', () => {
9393
await waitFor(() => {
9494
expect(screen.queryByText(videoSelectorContainerMockText)).toBeInTheDocument();
9595
expect(screen.queryByText(pagesAndResourcesMockText)).not.toBeInTheDocument();
96-
expect(mockComponentFn).toHaveBeenCalledWith(
97-
expect.objectContaining({
98-
courseId,
99-
}),
100-
);
96+
expect(mockComponentFn).toHaveBeenCalled();
10197
});
10298
});
10399
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ import { CourseAuthoringProvider } from './CourseAuthoringContext';
4747
const CourseAuthoringRoutes = () => {
4848
const { courseId } = useParams();
4949

50+
if (courseId === undefined) {
51+
// istanbul ignore next - This shouldn't be possible; it's just here to satisfy the type checker.
52+
throw new Error('Error: route is missing courseId.');
53+
}
54+
5055
return (
5156
<CourseAuthoringProvider courseId={courseId}>
5257
<CourseAuthoringPage>

src/advanced-settings/AdvancedSettings.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import {
55
} from '@openedx/paragon';
66
import { CheckCircle, Info, Warning } from '@openedx/paragon/icons';
77
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
8-
import Placeholder from '../editors/Placeholder';
98
import { useCourseAuthoringContext } from '@src/CourseAuthoringContext';
9+
import Placeholder from '../editors/Placeholder';
1010

1111
import AlertProctoringError from '../generic/AlertProctoringError';
1212
import InternetConnectionAlert from '../generic/internet-connection-alert';

src/advanced-settings/AdvancedSettings.test.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
import { CourseAuthoringProvider } from '@src/CourseAuthoringContext';
12
import {
23
render as baseRender,
34
fireEvent,
45
initializeMocks,
56
waitFor,
67
} from '../testUtils';
7-
import { CourseAuthoringProvider } from '@src/CourseAuthoringContext';
88
import { executeThunk } from '../utils';
99
import { advancedSettingsMock } from './__mocks__';
1010
import { getCourseAdvancedSettingsApiUrl } from './data/api';

src/certificates/Certificates.test.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// @ts-check
22
import userEvent from '@testing-library/user-event';
33

4+
import { CourseAuthoringProvider } from '@src/CourseAuthoringContext';
45
import { initializeMocks, render, waitFor } from '../testUtils';
56
import { RequestStatus } from '../data/constants';
67
import { executeThunk } from '../utils';
@@ -9,7 +10,6 @@ import { fetchCertificates } from './data/thunks';
910
import { certificatesDataMock } from './__mocks__';
1011
import Certificates from './Certificates';
1112
import messages from './messages';
12-
import { CourseAuthoringProvider } from '@src/CourseAuthoringContext';
1313

1414
let axiosMock;
1515
let store;
@@ -18,7 +18,7 @@ const courseId = 'course-123';
1818
const renderComponent = (props) => render(
1919
<CourseAuthoringProvider courseId={courseId}>
2020
<Certificates {...props} />
21-
</CourseAuthoringProvider>
21+
</CourseAuthoringProvider>,
2222
);
2323

2424
describe('Certificates', () => {

src/course-checklist/CourseChecklist.test.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
} from '@src/testUtils';
77
import '@testing-library/jest-dom';
88
import { getConfig, setConfig } from '@edx/frontend-platform';
9+
import { CourseAuthoringProvider } from '@src/CourseAuthoringContext';
910
import { RequestStatus } from '../data/constants';
1011
import { executeThunk } from '../utils';
1112
import { getCourseLaunchApiUrl, getCourseBestPracticesApiUrl } from './data/api';
@@ -17,7 +18,6 @@ import {
1718
} from './factories/mockApiResponses';
1819
import messages from './messages';
1920
import CourseChecklist from './index';
20-
import { CourseAuthoringProvider } from '@src/CourseAuthoringContext';
2121

2222
let axiosMock;
2323
let store;

0 commit comments

Comments
 (0)