Skip to content

Commit b13dfef

Browse files
committed
test: Adding more test to fix the coverage
1 parent 934e2e9 commit b13dfef

2 files changed

Lines changed: 267 additions & 5 deletions

File tree

src/course-outline/outline-sidebar/info-sidebar/InfoSidebar.test.tsx

Lines changed: 248 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jest.mock('@src/course-outline/outline-sidebar/OutlineSidebarContext', () => ({
1313
...jest.requireActual('@src/course-outline/outline-sidebar/OutlineSidebarContext').useOutlineSidebarContext(),
1414
selectedContainerState,
1515
clearSelection: jest.fn(),
16-
setSelectedContainerState: jest.fn(),
16+
setSelectedContainerState: mockSetSelectedContainerState,
1717
}),
1818
}));
1919

@@ -32,6 +32,12 @@ const handleDuplicateSectionSubmit = jest.fn();
3232
const handleDuplicateUnitSubmit = jest.fn();
3333
const handleDuplicateSubsectionSubmit = jest.fn();
3434
const mockedNavigate = jest.fn();
35+
const updateUnitOrderByIndex = jest.fn();
36+
const updateSubsectionOrderByIndex = jest.fn();
37+
const updateSectionOrderByIndex = jest.fn();
38+
const mockSetSelectedContainerState = jest.fn();
39+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
40+
let mockSections: any[] = [];
3541

3642
jest.mock('react-router-dom', () => ({
3743
...jest.requireActual('react-router-dom'),
@@ -47,12 +53,12 @@ jest.mock('@src/CourseAuthoringContext', () => ({
4753
openUnlinkModal,
4854
handleDuplicateUnitSubmit,
4955
getUnitUrl: jest.fn(),
50-
sections: [],
51-
updateUnitOrderByIndex: jest.fn(),
56+
sections: mockSections,
57+
updateUnitOrderByIndex,
5258
handleDuplicateSectionSubmit,
53-
updateSectionOrderByIndex: jest.fn(),
59+
updateSectionOrderByIndex,
5460
handleDuplicateSubsectionSubmit,
55-
updateSubsectionOrderByIndex: jest.fn(),
61+
updateSubsectionOrderByIndex,
5662
}),
5763
}));
5864

@@ -73,6 +79,11 @@ describe('InfoSidebar component', () => {
7379
handleDuplicateUnitSubmit.mockClear();
7480
handleDuplicateSubsectionSubmit.mockClear();
7581
mockedNavigate.mockClear();
82+
updateUnitOrderByIndex.mockClear();
83+
updateSubsectionOrderByIndex.mockClear();
84+
updateSectionOrderByIndex.mockClear();
85+
mockSetSelectedContainerState.mockClear();
86+
mockSections = [];
7687
});
7788

7889
it('renders InfoSidebar with course info if selectedContainerState is undefined', async () => {
@@ -258,6 +269,102 @@ describe('InfoSidebar component', () => {
258269
expect.stringContaining('/library/'),
259270
);
260271
});
272+
273+
it('copies location ID to clipboard when Copy Location is clicked', async () => {
274+
const user = userEvent.setup();
275+
const writeText = jest.fn().mockResolvedValue(undefined);
276+
Object.defineProperty(navigator, 'clipboard', {
277+
value: { writeText },
278+
writable: true,
279+
configurable: true,
280+
});
281+
await renderUnitMenu();
282+
283+
const menuToggle = screen.getByRole('button', { name: 'Item Menu' });
284+
fireEvent.click(menuToggle);
285+
286+
const copyLocationBtn = await screen.findByText('Copy Location ID');
287+
await user.click(copyLocationBtn);
288+
289+
expect(writeText).toHaveBeenCalledWith('unit1');
290+
});
291+
292+
describe('handleMove', () => {
293+
const seqId = 'block-v1:UNIX+UX1+2025_T3+type@sequential+block@seq1';
294+
const chId = 'block-v1:UNIX+UX1+2025_T3+type@chapter+block@ch1';
295+
const draggableUnitData = {
296+
...unitData,
297+
actions: { ...unitData.actions, draggable: true },
298+
};
299+
300+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
301+
const makeMovableUnit = (id: string): any => ({
302+
id,
303+
actions: { draggable: true },
304+
childInfo: { children: [] },
305+
});
306+
307+
const renderDraggableUnitMenu = async () => {
308+
mockSections = [{
309+
id: chId,
310+
childInfo: {
311+
children: [{
312+
id: seqId,
313+
childInfo: {
314+
children: [
315+
makeMovableUnit('unit0'),
316+
makeMovableUnit(unitId),
317+
makeMovableUnit('unit2'),
318+
],
319+
},
320+
}],
321+
},
322+
}];
323+
selectedContainerState = {
324+
currentId: unitId,
325+
subsectionId: seqId,
326+
sectionId: chId,
327+
sectionIndex: 0,
328+
index: 1,
329+
};
330+
axiosMock.onGet(getXBlockApiUrl(unitId)).reply(200, draggableUnitData);
331+
renderComponent();
332+
await screen.findByText(draggableUnitData.displayName);
333+
await screen.findByRole('button', { name: 'Item Menu' });
334+
};
335+
336+
it('calls updateUnitOrderByIndex and setSelectedContainerState when Move Up is clicked', async () => {
337+
const user = userEvent.setup();
338+
await renderDraggableUnitMenu();
339+
340+
const menuToggle = screen.getByRole('button', { name: 'Item Menu' });
341+
fireEvent.click(menuToggle);
342+
343+
const moveUpBtn = await screen.findByText('Move Up');
344+
await user.click(moveUpBtn);
345+
346+
expect(updateUnitOrderByIndex).toHaveBeenCalled();
347+
expect(mockSetSelectedContainerState).toHaveBeenCalledWith(
348+
expect.objectContaining({ index: 0, subsectionId: seqId, sectionId: chId }),
349+
);
350+
});
351+
352+
it('calls updateUnitOrderByIndex and setSelectedContainerState when Move Down is clicked', async () => {
353+
const user = userEvent.setup();
354+
await renderDraggableUnitMenu();
355+
356+
const menuToggle = screen.getByRole('button', { name: 'Item Menu' });
357+
fireEvent.click(menuToggle);
358+
359+
const moveDownBtn = await screen.findByText('Move Down');
360+
await user.click(moveDownBtn);
361+
362+
expect(updateUnitOrderByIndex).toHaveBeenCalled();
363+
expect(mockSetSelectedContainerState).toHaveBeenCalledWith(
364+
expect.objectContaining({ index: 2, subsectionId: seqId, sectionId: chId }),
365+
);
366+
});
367+
});
261368
});
262369

263370
describe('SubsectionSidebar menus', () => {
@@ -351,6 +458,79 @@ describe('InfoSidebar component', () => {
351458
expect.stringContaining('/library/'),
352459
);
353460
});
461+
462+
describe('handleMove', () => {
463+
const chId = 'block-v1:UNIX+UX1+2025_T3+type@chapter+block@ch1';
464+
const draggableSubsectionData = {
465+
...subsectionData,
466+
actions: { ...subsectionData.actions, draggable: true },
467+
};
468+
469+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
470+
const makeMovableSubsection = (id: string): any => ({
471+
id,
472+
actions: { draggable: true, childAddable: true },
473+
childInfo: { children: [] },
474+
});
475+
476+
const renderDraggableSubsectionMenu = async () => {
477+
mockSections = [{
478+
id: chId,
479+
actions: { childAddable: true },
480+
upstreamInfo: null,
481+
childInfo: {
482+
children: [
483+
makeMovableSubsection('sub0'),
484+
makeMovableSubsection(subsectionId),
485+
makeMovableSubsection('sub2'),
486+
],
487+
},
488+
}];
489+
selectedContainerState = {
490+
currentId: subsectionId,
491+
subsectionId,
492+
sectionId: chId,
493+
sectionIndex: 0,
494+
index: 1,
495+
};
496+
axiosMock.onGet(getXBlockApiUrl(subsectionId)).reply(200, draggableSubsectionData);
497+
renderComponent();
498+
await screen.findByText(draggableSubsectionData.displayName);
499+
await screen.findByRole('button', { name: 'Item Menu' });
500+
};
501+
502+
it('calls updateSubsectionOrderByIndex and setSelectedContainerState when Move Up is clicked', async () => {
503+
const user = userEvent.setup();
504+
await renderDraggableSubsectionMenu();
505+
506+
const menuToggle = screen.getByRole('button', { name: 'Item Menu' });
507+
fireEvent.click(menuToggle);
508+
509+
const moveUpBtn = await screen.findByText('Move Up');
510+
await user.click(moveUpBtn);
511+
512+
expect(updateSubsectionOrderByIndex).toHaveBeenCalled();
513+
expect(mockSetSelectedContainerState).toHaveBeenCalledWith(
514+
expect.objectContaining({ index: 0, sectionId: chId, sectionIndex: 0 }),
515+
);
516+
});
517+
518+
it('calls updateSubsectionOrderByIndex and setSelectedContainerState when Move Down is clicked', async () => {
519+
const user = userEvent.setup();
520+
await renderDraggableSubsectionMenu();
521+
522+
const menuToggle = screen.getByRole('button', { name: 'Item Menu' });
523+
fireEvent.click(menuToggle);
524+
525+
const moveDownBtn = await screen.findByText('Move Down');
526+
await user.click(moveDownBtn);
527+
528+
expect(updateSubsectionOrderByIndex).toHaveBeenCalled();
529+
expect(mockSetSelectedContainerState).toHaveBeenCalledWith(
530+
expect.objectContaining({ index: 2, sectionId: chId, sectionIndex: 0 }),
531+
);
532+
});
533+
});
354534
});
355535

356536
describe('SectionSidebar menus', () => {
@@ -443,5 +623,68 @@ describe('InfoSidebar component', () => {
443623
expect.stringContaining('/library/'),
444624
);
445625
});
626+
627+
describe('handleMove', () => {
628+
const draggableSectionData = {
629+
...sectionData,
630+
actions: { ...sectionData.actions, draggable: true },
631+
};
632+
633+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
634+
const makeMovableSection = (id: string): any => ({
635+
id,
636+
actions: { draggable: true },
637+
childInfo: { children: [] },
638+
});
639+
640+
const renderDraggableSectionMenu = async () => {
641+
mockSections = [
642+
makeMovableSection('sec0'),
643+
makeMovableSection(sectionId),
644+
makeMovableSection('sec2'),
645+
];
646+
selectedContainerState = {
647+
currentId: sectionId,
648+
sectionId,
649+
index: 1,
650+
};
651+
axiosMock.onGet(getXBlockApiUrl(sectionId)).reply(200, draggableSectionData);
652+
renderComponent();
653+
await screen.findByText(draggableSectionData.displayName);
654+
await screen.findByRole('button', { name: 'Item Menu' });
655+
};
656+
657+
it('calls updateSectionOrderByIndex and setSelectedContainerState when Move Up is clicked', async () => {
658+
const user = userEvent.setup();
659+
await renderDraggableSectionMenu();
660+
661+
const menuToggle = screen.getByRole('button', { name: 'Item Menu' });
662+
fireEvent.click(menuToggle);
663+
664+
const moveUpBtn = await screen.findByText('Move Up');
665+
await user.click(moveUpBtn);
666+
667+
expect(updateSectionOrderByIndex).toHaveBeenCalledWith(1, 0);
668+
expect(mockSetSelectedContainerState).toHaveBeenCalledWith(
669+
expect.objectContaining({ index: 0 }),
670+
);
671+
});
672+
673+
it('calls updateSectionOrderByIndex and setSelectedContainerState when Move Down is clicked', async () => {
674+
const user = userEvent.setup();
675+
await renderDraggableSectionMenu();
676+
677+
const menuToggle = screen.getByRole('button', { name: 'Item Menu' });
678+
fireEvent.click(menuToggle);
679+
680+
const moveDownBtn = await screen.findByText('Move Down');
681+
await user.click(moveDownBtn);
682+
683+
expect(updateSectionOrderByIndex).toHaveBeenCalledWith(1, 2);
684+
expect(mockSetSelectedContainerState).toHaveBeenCalledWith(
685+
expect.objectContaining({ index: 2 }),
686+
);
687+
});
688+
});
446689
});
447690
});

src/course-unit/CourseUnit.test.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3511,5 +3511,24 @@ describe('<CourseUnit />', () => {
35113511
expect.stringContaining('/library/'),
35123512
);
35133513
});
3514+
3515+
it('copies location ID to clipboard when Copy Location ID is clicked from sidebar menu', async () => {
3516+
const user = userEvent.setup();
3517+
const writeText = jest.fn().mockResolvedValue(undefined);
3518+
Object.defineProperty(navigator, 'clipboard', {
3519+
value: { writeText },
3520+
writable: true,
3521+
configurable: true,
3522+
});
3523+
await renderUnitInfoSidebar();
3524+
3525+
const menuToggle = screen.getByRole('button', { name: 'Item Menu' });
3526+
fireEvent.click(menuToggle);
3527+
3528+
const copyLocationBtn = await screen.findByText('Copy Location ID');
3529+
await user.click(copyLocationBtn);
3530+
3531+
expect(writeText).toHaveBeenCalledWith('867dddb6f55d410caaa9c1eb9c6743ec');
3532+
});
35143533
});
35153534
});

0 commit comments

Comments
 (0)