Skip to content

Commit f28d857

Browse files
committed
test(course-outline): migrate configure tests to factory data
1 parent dd56a92 commit f28d857

1 file changed

Lines changed: 140 additions & 17 deletions

File tree

src/course-outline/CourseOutline.test.tsx

Lines changed: 140 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,91 @@ function useOperationsTestOutline() {
363363
});
364364
}
365365

366+
/** Build a 2-section NodeSpec for configure modal tests. */
367+
function buildConfigureOutlineSpec(): NodeSpec[] {
368+
const id = (type: string, block: string) => `block-v1:edX+DemoX+Demo_Course+type@${type}+block@${block}`;
369+
return [
370+
{
371+
id: id('chapter', 'd8a6192ade314473a78242dfeedfbf5b'),
372+
displayName: 'Introduction 12',
373+
overrides: {
374+
start: '2023-08-10T22:00:00Z',
375+
visibilityState: 'staff_only',
376+
published: false,
377+
courseGraders: ['Homework', 'Exam'],
378+
},
379+
children: [
380+
{
381+
id: id('sequential', '8a85e287e30a47e98d8c1f37f74a6a9d'),
382+
displayName: 'Subsection 1A',
383+
overrides: {
384+
start: '1970-01-01T05:00:00Z',
385+
visibilityState: 'draft',
386+
published: false,
387+
courseGraders: ['Homework', 'Exam'],
388+
isTimeLimited: false,
389+
isProctoredExam: false,
390+
isOnboardingExam: false,
391+
isPracticeExam: false,
392+
examReviewRules: '',
393+
defaultTimeLimitMinutes: null,
394+
hideAfterDue: false,
395+
wasExamEverLinkedWithExternal: false,
396+
onlineProctoringRules: '',
397+
supportsOnboarding: false,
398+
showReviewRules: true,
399+
isPrereq: false,
400+
prereqs: [{
401+
blockUsageKey: id('sequential', 'b713bc2830f34f6f87554028c3068729'),
402+
blockDisplayName: 'Subsection 1B',
403+
}],
404+
},
405+
children: [{ id: id('vertical', '0f652012aa294ed9b4360a1e4f6c5232'), displayName: 'Unit 1A1' }],
406+
},
407+
{
408+
id: id('sequential', 'b713bc2830f34f6f87554028c3068729'),
409+
displayName: 'Subsection 1B',
410+
overrides: {
411+
start: '2013-02-05T05:00:00Z',
412+
visibilityState: 'live',
413+
published: true,
414+
courseGraders: ['Homework', 'Exam'],
415+
},
416+
children: [{ id: id('vertical', 'sec1-sub1-unit-0'), displayName: 'Unit' }],
417+
},
418+
],
419+
},
420+
{
421+
id: id('chapter', 'section-2'),
422+
displayName: 'Section 2',
423+
overrides: { visibilityState: 'live' },
424+
children: [
425+
{
426+
id: id('sequential', 'sec2-sub-0'),
427+
displayName: 'Sec2 Sub 0',
428+
overrides: { courseGraders: ['Homework', 'Exam'] },
429+
children: [{ id: id('vertical', 'sec2-sub-0-unit-0'), displayName: 'Unit' }],
430+
},
431+
],
432+
},
433+
];
434+
}
435+
436+
function useConfigureTestOutline() {
437+
useTestOutline({
438+
sections: buildConfigureOutlineSpec(),
439+
overrides: {
440+
createdOn: new Date().toISOString(),
441+
courseStructure: {
442+
id: 'block-v1:edX+DemoX+Demo_Course+type@course+block@course',
443+
displayName: 'Demonstration Course',
444+
enableProctoredExams: true,
445+
enableTimedExams: true,
446+
},
447+
},
448+
});
449+
}
450+
366451
/** Wrapper around useTestOutline for reorder/move tests — overrides courseStructure.id to match old mock. */
367452
function useReorderTestOutline() {
368453
useTestOutline({
@@ -760,6 +845,7 @@ describe('<CourseOutline />', () => {
760845
});
761846

762847
it('adds new unit correctly', async () => {
848+
useTestOutline();
763849
const { findAllByTestId } = renderComponent();
764850
const [sectionElement] = await findAllByTestId('section-card');
765851
const [subsectionElement] = await within(sectionElement).findAllByTestId('subsection-card');
@@ -773,15 +859,19 @@ describe('<CourseOutline />', () => {
773859
});
774860
const newUnitButton = await within(subsectionElement).findByRole('button', { name: 'New unit' });
775861
await act(async () => fireEvent.click(newUnitButton));
776-
expect(axiosMock.history.post.length).toBe(3);
862+
777863
const [section] = courseOutlineIndexMock.courseStructure.childInfo.children;
778864
const [subsection] = section.childInfo.children;
779-
expect(axiosMock.history.post[2].data).toBe(JSON.stringify({
865+
const newUnitPost = axiosMock.history.post.find(
866+
(entry: any) => entry.data && entry.data.includes(COURSE_BLOCK_NAMES.vertical.id),
867+
);
868+
expect(newUnitPost).toBeDefined();
869+
expect(JSON.parse(newUnitPost!.data)).toEqual({
780870
type: COURSE_BLOCK_NAMES.vertical.id,
781871
category: COURSE_BLOCK_NAMES.vertical.id,
782872
parent_locator: subsection.id,
783873
display_name: COURSE_BLOCK_NAMES.vertical.name,
784-
}));
874+
});
785875
});
786876

787877
it('adds a unit from library correctly', async () => {
@@ -974,6 +1064,7 @@ describe('<CourseOutline />', () => {
9741064

9751065
it('check edit title works for section, subsection and unit', async () => {
9761066
const user = userEvent.setup();
1067+
useOperationsTestOutline();
9771068
renderComponent();
9781069
const [section] = courseOutlineIndexMock.courseStructure.childInfo.children;
9791070
const checkEditTitle = async (element, item, newName, elementName) => {
@@ -1304,6 +1395,7 @@ describe('<CourseOutline />', () => {
13041395
});
13051396

13061397
it('check configure modal for section', async () => {
1398+
useConfigureTestOutline();
13071399
const { findByTestId, findAllByTestId } = renderComponent();
13081400
const section = courseOutlineIndexMock.courseStructure.childInfo.children[0];
13091401
const newReleaseDateIso = '2025-09-10T22:00:00Z';
@@ -1341,14 +1433,17 @@ describe('<CourseOutline />', () => {
13411433
const saveButton = await findByTestId('configure-save-button');
13421434
await act(async () => fireEvent.click(saveButton));
13431435

1344-
expect(axiosMock.history.post.length).toBe(3);
1345-
expect(axiosMock.history.post[2].data).toBe(JSON.stringify({
1436+
const sectionCfgPost = axiosMock.history.post.find(
1437+
(entry: any) => entry.data && entry.data.includes('visible_to_staff_only'),
1438+
);
1439+
expect(sectionCfgPost).toBeDefined();
1440+
expect(JSON.parse(sectionCfgPost!.data)).toEqual({
13461441
publish: 'republish',
13471442
metadata: {
13481443
visible_to_staff_only: true,
13491444
start: newReleaseDateIso,
13501445
},
1351-
}));
1446+
});
13521447

13531448
await act(async () => fireEvent.click(sectionDropdownButton));
13541449
await act(async () => fireEvent.click(configureBtn));
@@ -1358,6 +1453,7 @@ describe('<CourseOutline />', () => {
13581453
});
13591454

13601455
it('check configure modal for subsection', async () => {
1456+
useConfigureTestOutline();
13611457
const user = userEvent.setup();
13621458
const {
13631459
findAllByTestId,
@@ -1446,8 +1542,11 @@ describe('<CourseOutline />', () => {
14461542
await user.click(saveButton);
14471543

14481544
// verify request
1449-
expect(axiosMock.history.post.length).toBe(3);
1450-
expect(axiosMock.history.post[2].data).toBe(JSON.stringify(expectedRequestData));
1545+
const subCfgPost = axiosMock.history.post.find(
1546+
(entry: any) => entry.data && entry.data.includes(expectedRequestData.graderType),
1547+
);
1548+
expect(subCfgPost).toBeDefined();
1549+
expect(JSON.parse(subCfgPost!.data)).toEqual(expectedRequestData);
14511550

14521551
// reopen modal and check values
14531552
await user.click(subsectionDropdownButton);
@@ -1480,6 +1579,7 @@ describe('<CourseOutline />', () => {
14801579
});
14811580

14821581
it('check prereq and proctoring settings in configure modal for subsection', async () => {
1582+
useConfigureTestOutline();
14831583
const user = userEvent.setup();
14841584
const {
14851585
findAllByTestId,
@@ -1587,8 +1687,11 @@ describe('<CourseOutline />', () => {
15871687
await user.click(saveButton);
15881688

15891689
// verify request
1590-
expect(axiosMock.history.post.length).toBe(3);
1591-
expect(axiosMock.history.post[2].data).toBe(JSON.stringify(expectedRequestData));
1690+
const cfgPosta = axiosMock.history.post.find(
1691+
(entry: any) => entry.data && entry.data.includes(expectedRequestData.graderType),
1692+
);
1693+
expect(cfgPosta).toBeDefined();
1694+
expect(JSON.parse(cfgPosta!.data)).toEqual(expectedRequestData);
15921695

15931696
// reopen modal and check values
15941697
await user.click(subsectionDropdownButton);
@@ -1628,6 +1731,7 @@ describe('<CourseOutline />', () => {
16281731
});
16291732

16301733
it('check practice proctoring settings in configure modal', async () => {
1734+
useConfigureTestOutline();
16311735
const user = userEvent.setup();
16321736
const {
16331737
findAllByTestId,
@@ -1712,8 +1816,11 @@ describe('<CourseOutline />', () => {
17121816
await user.click(saveButton);
17131817

17141818
// verify request
1715-
expect(axiosMock.history.post.length).toBe(3);
1716-
expect(axiosMock.history.post[2].data).toBe(JSON.stringify(expectedRequestData));
1819+
const cfgPostb = axiosMock.history.post.find(
1820+
(entry: any) => entry.data && entry.data.includes(expectedRequestData.graderType),
1821+
);
1822+
expect(cfgPostb).toBeDefined();
1823+
expect(JSON.parse(cfgPostb!.data)).toEqual(expectedRequestData);
17171824

17181825
// reopen modal and check values
17191826
await user.click(subsectionDropdownButton);
@@ -1820,8 +1927,11 @@ describe('<CourseOutline />', () => {
18201927
await user.click(saveButton);
18211928

18221929
// verify request
1823-
expect(axiosMock.history.post.length).toBe(3);
1824-
expect(axiosMock.history.post[2].data).toBe(JSON.stringify(expectedRequestData));
1930+
const cfgPostc = axiosMock.history.post.find(
1931+
(entry: any) => entry.data && entry.data.includes(expectedRequestData.graderType),
1932+
);
1933+
expect(cfgPostc).toBeDefined();
1934+
expect(JSON.parse(cfgPostc!.data)).toEqual(expectedRequestData);
18251935

18261936
// reopen modal and check values
18271937
await user.click(subsectionDropdownButton);
@@ -1925,8 +2035,11 @@ describe('<CourseOutline />', () => {
19252035
await user.click(saveButton);
19262036

19272037
// verify request
1928-
expect(axiosMock.history.post.length).toBe(3);
1929-
expect(axiosMock.history.post[2].data).toBe(JSON.stringify(expectedRequestData));
2038+
const noSpecialPost = axiosMock.history.post.find(
2039+
(entry: any) => entry.data && entry.data.includes(expectedRequestData.graderType),
2040+
);
2041+
expect(noSpecialPost).toBeDefined();
2042+
expect(JSON.parse(noSpecialPost!.data)).toEqual(expectedRequestData);
19302043

19312044
// Seed subsection cache + mock parent section GET so invalidateParentQueries
19322045
// refetch succeeds and reopened modal gets correct form values.
@@ -2073,9 +2186,19 @@ describe('<CourseOutline />', () => {
20732186

20742187
it('check update highlights when update highlights query is successfully', async () => {
20752188
const user = userEvent.setup();
2189+
useTestOutline({
2190+
sections: buildOperationsOutlineSpec(),
2191+
overrides: {
2192+
courseStructure: { id: 'block-v1:edX+DemoX+Demo_Course+type@course+block@course' },
2193+
},
2194+
});
2195+
// Seed highlights on section 0 so the highlights button appears.
2196+
const [section] = courseOutlineIndexMock.courseStructure.childInfo.children;
2197+
section.highlights = ['Existing Highlight'];
2198+
queryClient.setQueryData(courseOutlineQueryKeys.courseItemId(section.id), section);
2199+
20762200
renderComponent();
20772201

2078-
const section = courseOutlineIndexMock.courseStructure.childInfo.children[0];
20792202
const highlights = [
20802203
'New Highlight 1',
20812204
'New Highlight 2',

0 commit comments

Comments
 (0)