Skip to content

Commit 0fad221

Browse files
committed
test: improve coverage
1 parent 9eedb9c commit 0fad221

5 files changed

Lines changed: 207 additions & 1 deletion

File tree

src/course-outline/outline-sidebar/AddSidebar.test.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,4 +432,38 @@ describe('AddSidebar', () => {
432432
0,
433433
);
434434
});
435+
436+
it('back from subsection opens section', async () => {
437+
const user = userEvent.setup();
438+
const section = outlineChildren[0];
439+
const subsection = section.childInfo.children[0];
440+
selectedContainerState = {
441+
currentId: subsection.id,
442+
subsectionId: subsection.id,
443+
sectionId: section.id,
444+
};
445+
renderComponent();
446+
447+
const back = await screen.findByRole('button', { name: 'Back' });
448+
await user.click(back);
449+
450+
expect(openContainerSidebar).toHaveBeenCalledWith(section.id, undefined, section.id, 0);
451+
expect(clearSelection).not.toHaveBeenCalled();
452+
});
453+
454+
it('back from section clears selection', async () => {
455+
const user = userEvent.setup();
456+
const section = outlineChildren[0];
457+
selectedContainerState = {
458+
currentId: section.id,
459+
sectionId: section.id,
460+
};
461+
renderComponent();
462+
463+
const back = await screen.findByRole('button', { name: 'Back' });
464+
await user.click(back);
465+
466+
expect(clearSelection).toHaveBeenCalled();
467+
expect(openContainerSidebar).not.toHaveBeenCalled();
468+
});
435469
});

src/course-outline/outline-sidebar/OutlineAlignSidebar.test.tsx

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,78 @@ describe('OutlineAlignSidebar', () => {
130130
index: 0,
131131
});
132132
});
133+
134+
it('back button from subsection selects section', async () => {
135+
jest
136+
.spyOn(OutlineSidebarContext, 'useOutlineSidebarContext')
137+
.mockReturnValue({
138+
selectedContainerState: {
139+
currentId: 'subsection-1',
140+
subsectionId: 'subsection-1',
141+
sectionId: 'section-1',
142+
},
143+
clearSelection,
144+
openContainerSidebar,
145+
} as any);
146+
147+
render(<OutlineAlignSidebar />);
148+
149+
const backButton = await screen.findByRole('button', { name: /back/i });
150+
backButton.click();
151+
152+
expect(openContainerSidebar).toHaveBeenCalledWith('section-1', undefined, 'section-1', 0);
153+
expect(setCurrentSelection).toHaveBeenCalledWith({
154+
currentId: 'section-1',
155+
sectionId: 'section-1',
156+
index: 0,
157+
});
158+
});
159+
160+
it('back button from section clears selection', async () => {
161+
jest
162+
.spyOn(OutlineSidebarContext, 'useOutlineSidebarContext')
163+
.mockReturnValue({
164+
selectedContainerState: {
165+
currentId: 'section-1',
166+
sectionId: 'section-1',
167+
},
168+
clearSelection,
169+
openContainerSidebar,
170+
} as any);
171+
172+
render(<OutlineAlignSidebar />);
173+
174+
const backButton = await screen.findByRole('button', { name: /back/i });
175+
backButton.click();
176+
177+
expect(clearSelection).toHaveBeenCalled();
178+
expect(setCurrentSelection).toHaveBeenCalledWith(undefined);
179+
});
180+
181+
it('back button handles missing section when selecting subsection parent', async () => {
182+
jest
183+
.spyOn(OutlineSidebarContext, 'useOutlineSidebarContext')
184+
.mockReturnValue({
185+
selectedContainerState: {
186+
currentId: 'unit-1',
187+
subsectionId: 'subsection-1',
188+
sectionId: 'missing-section',
189+
},
190+
clearSelection,
191+
openContainerSidebar,
192+
} as any);
193+
194+
render(<OutlineAlignSidebar />);
195+
196+
const backButton = await screen.findByRole('button', { name: /back/i });
197+
backButton.click();
198+
199+
expect(openContainerSidebar).toHaveBeenCalledWith('subsection-1', 'subsection-1', 'missing-section', undefined);
200+
expect(setCurrentSelection).toHaveBeenCalledWith({
201+
currentId: 'subsection-1',
202+
subsectionId: 'subsection-1',
203+
sectionId: 'missing-section',
204+
index: undefined,
205+
});
206+
});
133207
});

src/course-outline/outline-sidebar/OutlineAlignSidebar.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export const OutlineAlignSidebar = () => {
2323
const subsectionIndex = section
2424
?.childInfo.children.findIndex((subsection) => subsection.id === subsectionId) ?? -1;
2525

26+
// istanbul ignore next
2627
if (!currentId) {
2728
clearSelection();
2829
setCurrentSelection(undefined);
@@ -61,7 +62,9 @@ export const OutlineAlignSidebar = () => {
6162
return;
6263
}
6364

65+
// istanbul ignore next
6466
clearSelection();
67+
// istanbul ignore next
6568
setCurrentSelection(undefined);
6669
};
6770

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ import { getDownstreamApiUrl } from '@src/generic/unlink-modal/data/api';
88
import { InfoSidebar } from './InfoSidebar';
99

1010
let selectedContainerState: SelectionState | undefined;
11+
const mockClearSelection = jest.fn();
1112
jest.mock('@src/course-outline/outline-sidebar/OutlineSidebarContext', () => ({
1213
...jest.requireActual('@src/course-outline/outline-sidebar/OutlineSidebarContext'),
1314
useOutlineSidebarContext: () => ({
1415
...jest.requireActual('@src/course-outline/outline-sidebar/OutlineSidebarContext').useOutlineSidebarContext(),
1516
selectedContainerState,
16-
clearSelection: jest.fn(),
17+
clearSelection: mockClearSelection,
1718
setSelectedContainerState: mockSetSelectedContainerState,
1819
openContainerInfoSidebar: mockOpenContainerInfoSidebar,
1920
}),
@@ -94,6 +95,7 @@ describe('InfoSidebar component', () => {
9495
updateSectionOrderByIndex.mockClear();
9596
mockSetSelectedContainerState.mockClear();
9697
mockOpenContainerInfoSidebar.mockClear();
98+
mockClearSelection.mockClear();
9799
mockSections = [];
98100
});
99101

@@ -476,6 +478,22 @@ describe('InfoSidebar component', () => {
476478
);
477479
});
478480

481+
it('clears selection on back when subsection has no sectionId', async () => {
482+
const user = userEvent.setup();
483+
selectedContainerState = {
484+
currentId: subsectionId,
485+
subsectionId,
486+
};
487+
axiosMock.onGet(getXBlockApiUrl(subsectionId)).reply(200, subsectionData);
488+
renderComponent();
489+
await screen.findByText(subsectionData.displayName);
490+
491+
await user.click(screen.getByRole('button', { name: /back/i }));
492+
493+
expect(mockClearSelection).toHaveBeenCalled();
494+
expect(mockOpenContainerInfoSidebar).not.toHaveBeenCalled();
495+
});
496+
479497
it('calls openDeleteModal when Delete is clicked in subsection menu', async () => {
480498
const user = userEvent.setup();
481499
await renderSubsectionMenu();

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

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,81 @@ describe('UnitSidebar', () => {
169169
await user.click(screen.getByRole('tab', { name: /Settings/i }));
170170
expect(screen.getByText('GenericUnitInfoSettings')).toBeInTheDocument();
171171
});
172+
173+
it('back opens subsection info sidebar when subsectionId exists', async () => {
174+
const user = userEvent.setup();
175+
const openContainerInfoSidebar = jest.fn();
176+
outlineContext.useOutlineSidebarContext.mockReturnValue({
177+
selectedContainerState: { currentId: 'unit-5', sectionId: 's1', subsectionId: 'ss1' },
178+
clearSelection: jest.fn(),
179+
openContainerInfoSidebar,
180+
setSelectedContainerState: jest.fn(),
181+
currentTabKey: 'info',
182+
setCurrentTabKey: jest.fn(),
183+
});
184+
outlineCtx.useCourseOutlineContext.mockReturnValue({
185+
openPublishModal: jest.fn(),
186+
handleDuplicateUnitSubmit: jest.fn(),
187+
sections: [{ id: 's1' }],
188+
updateUnitOrderByIndex: jest.fn(),
189+
openDeleteModal: jest.fn(),
190+
});
191+
apiHooks.useCourseItemData.mockImplementation((id: string) => {
192+
if (id === 's1') {
193+
return {
194+
data: { id: 's1', childInfo: { children: [{ id: 'ss1' }] } },
195+
isPending: false,
196+
};
197+
}
198+
if (id === 'ss1') {
199+
return {
200+
data: { id: 'ss1', childInfo: { children: [] } },
201+
isPending: false,
202+
};
203+
}
204+
return {
205+
data: {
206+
displayName: 'Unit 5',
207+
hasChanges: false,
208+
category: 'vertical',
209+
id: 'unit-5',
210+
actions: { deletable: true, duplicable: true },
211+
},
212+
isPending: false,
213+
};
214+
});
215+
216+
render(<UnitSidebar />);
217+
await user.click(screen.getByRole('button', { name: 'Back' }));
218+
219+
expect(openContainerInfoSidebar).toHaveBeenCalledWith('ss1', 'ss1', 's1', 0);
220+
});
221+
222+
it('back clears selection when subsectionId missing', async () => {
223+
const user = userEvent.setup();
224+
const clearSelection = jest.fn();
225+
outlineContext.useOutlineSidebarContext.mockReturnValue({
226+
selectedContainerState: { currentId: 'unit-6', sectionId: 's1' },
227+
clearSelection,
228+
openContainerInfoSidebar: jest.fn(),
229+
setSelectedContainerState: jest.fn(),
230+
currentTabKey: 'info',
231+
setCurrentTabKey: jest.fn(),
232+
});
233+
apiHooks.useCourseItemData.mockReturnValue({
234+
data: {
235+
displayName: 'Unit 6',
236+
hasChanges: false,
237+
category: 'vertical',
238+
id: 'unit-6',
239+
actions: { deletable: true, duplicable: true },
240+
},
241+
isPending: false,
242+
});
243+
244+
render(<UnitSidebar />);
245+
await user.click(screen.getByRole('button', { name: 'Back' }));
246+
247+
expect(clearSelection).toHaveBeenCalled();
248+
});
172249
});

0 commit comments

Comments
 (0)