Skip to content

Commit 359007b

Browse files
committed
test: Tests added for selected cards
1 parent 82a440c commit 359007b

8 files changed

Lines changed: 168 additions & 88 deletions

File tree

src/course-outline/common/context/SidebarContext.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { createContext, useCallback, useContext, useMemo, useState } from "react";
1+
import {
2+
createContext, useCallback, useContext, useMemo, useState,
3+
} from 'react';
24

35
export type SidebarContextData = {
46
selectedContainerId?: string;
5-
openContainerInfoSidebar: (containerId: string) => void;
7+
openContainerInfoSidebar: (containerId: string) => void;
68
};
79

810
/**
@@ -18,7 +20,7 @@ type SidebarProviderProps = {
1820
};
1921

2022
export const SidebarProvider = ({ children }: SidebarProviderProps) => {
21-
const [ selectedContainerId, setSelectedContainerId ] = useState<string | undefined>();
23+
const [selectedContainerId, setSelectedContainerId] = useState<string | undefined>();
2224

2325
const openContainerInfoSidebar = useCallback((containerId: string) => {
2426
setSelectedContainerId(containerId);
@@ -27,7 +29,7 @@ export const SidebarProvider = ({ children }: SidebarProviderProps) => {
2729
const context = useMemo<SidebarContextData>(() => {
2830
const contextValue = {
2931
selectedContainerId,
30-
openContainerInfoSidebar,
32+
openContainerInfoSidebar,
3133
};
3234

3335
return contextValue;

src/course-outline/drag-helper/SortableItem.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ const SortableItem = ({
7373
className="mx-0"
7474
onClick={onClick}
7575
onKeyDown={(e) => {
76-
if (!onClick) return;
76+
if (!onClick) { return; }
7777

78-
if (e.key === "Enter" || e.key === " ") {
78+
if (e.key === 'Enter' || e.key === ' ') {
7979
e.preventDefault();
8080
onClick(e);
8181
}

src/course-outline/section-card/SectionCard.test.tsx

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
} from '@src/testUtils';
44
import { XBlock } from '@src/data/types';
55
import SectionCard from './SectionCard';
6+
import { SidebarProvider } from '../common/context/SidebarContext';
67

78
const mockUseAcceptLibraryBlockChanges = jest.fn();
89
const mockUseIgnoreLibraryBlockChanges = jest.fn();
@@ -81,28 +82,30 @@ const section = {
8182
const onEditSectionSubmit = jest.fn();
8283

8384
const renderComponent = (props?: object, entry = '/course/:courseId') => render(
84-
<SectionCard
85-
section={section}
86-
index={1}
87-
canMoveItem={jest.fn()}
88-
onOrderChange={jest.fn()}
89-
onOpenPublishModal={jest.fn()}
90-
onOpenHighlightsModal={jest.fn()}
91-
onOpenDeleteModal={jest.fn()}
92-
onOpenUnlinkModal={jest.fn()}
93-
onOpenConfigureModal={jest.fn()}
94-
onEditSectionSubmit={onEditSectionSubmit}
95-
onDuplicateSubmit={jest.fn()}
96-
isSectionsExpanded
97-
onNewSubsectionSubmit={jest.fn()}
98-
isSelfPaced={false}
99-
isCustomRelativeDatesActive={false}
100-
onAddSubsectionFromLibrary={jest.fn()}
101-
resetScrollState={jest.fn()}
102-
{...props}
103-
>
104-
<span>children</span>
105-
</SectionCard>,
85+
<SidebarProvider>
86+
<SectionCard
87+
section={section}
88+
index={1}
89+
canMoveItem={jest.fn()}
90+
onOrderChange={jest.fn()}
91+
onOpenPublishModal={jest.fn()}
92+
onOpenHighlightsModal={jest.fn()}
93+
onOpenDeleteModal={jest.fn()}
94+
onOpenUnlinkModal={jest.fn()}
95+
onOpenConfigureModal={jest.fn()}
96+
onEditSectionSubmit={onEditSectionSubmit}
97+
onDuplicateSubmit={jest.fn()}
98+
isSectionsExpanded
99+
onNewSubsectionSubmit={jest.fn()}
100+
isSelfPaced={false}
101+
isCustomRelativeDatesActive={false}
102+
onAddSubsectionFromLibrary={jest.fn()}
103+
resetScrollState={jest.fn()}
104+
{...props}
105+
>
106+
<span>children</span>
107+
</SectionCard>
108+
</SidebarProvider>,
106109
{
107110
path: '/course/:courseId',
108111
params: { courseId: '5' },
@@ -122,6 +125,28 @@ describe('<SectionCard />', () => {
122125

123126
expect(screen.getByTestId('section-card-header')).toBeInTheDocument();
124127
expect(screen.getByTestId('section-card__content')).toBeInTheDocument();
128+
129+
// The card is not selected
130+
const card = screen.getByTestId('section-card');
131+
expect(card).not.toHaveClass('outline-card-selected');
132+
});
133+
134+
it('render SectionCard component in selected state', () => {
135+
const { container } = renderComponent();
136+
137+
expect(screen.getByTestId('section-card-header')).toBeInTheDocument();
138+
139+
// The card is not selected
140+
const card = screen.getByTestId('section-card');
141+
expect(card).not.toHaveClass('outline-card-selected');
142+
143+
// Get the <Row> that contains the card and click it to select the card
144+
const el = container.querySelector('div.row.mx-0') as HTMLInputElement;
145+
expect(el).not.toBeNull();
146+
fireEvent.click(el!);
147+
148+
// The card is selected
149+
expect(card).toHaveClass('outline-card-selected');
125150
});
126151

127152
it('expands/collapses the card when the expand button is clicked', () => {

src/course-outline/section-card/SectionCard.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,11 +289,12 @@ const SectionCard = ({
289289
onClick={onClickCard}
290290
>
291291
<div
292-
className={classNames('section-card',
292+
className={classNames(
293+
'section-card',
293294
{
294-
'highlight': isScrolledToElement,
295+
highlight: isScrolledToElement,
295296
'outline-card-selected': section.id === selectedContainerId,
296-
}
297+
},
297298
)}
298299
data-testid="section-card"
299300
ref={currentRef}

src/course-outline/subsection-card/SubsectionCard.test.tsx

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
import { XBlock } from '@src/data/types';
66
import cardHeaderMessages from '../card-header/messages';
77
import SubsectionCard from './SubsectionCard';
8+
import { SidebarProvider } from '../common/context/SidebarContext';
89

910
let store;
1011
const containerKey = 'lct:org:lib:unit:1';
@@ -105,29 +106,31 @@ const section: XBlock = {
105106
const onEditSubectionSubmit = jest.fn();
106107

107108
const renderComponent = (props?: object, entry = '/course/:courseId') => render(
108-
<SubsectionCard
109-
section={section}
110-
subsection={subsection}
111-
index={1}
112-
isSelfPaced={false}
113-
getPossibleMoves={jest.fn()}
114-
onOrderChange={jest.fn()}
115-
onOpenPublishModal={jest.fn()}
116-
onOpenDeleteModal={jest.fn()}
117-
onOpenUnlinkModal={jest.fn()}
118-
onNewUnitSubmit={jest.fn()}
119-
onAddUnitFromLibrary={handleOnAddUnitFromLibrary}
120-
isCustomRelativeDatesActive={false}
121-
onEditSubmit={onEditSubectionSubmit}
122-
onDuplicateSubmit={jest.fn()}
123-
onOpenConfigureModal={jest.fn()}
124-
onPasteClick={jest.fn()}
125-
resetScrollState={jest.fn()}
126-
isSectionsExpanded={false}
127-
{...props}
128-
>
129-
<span>children</span>
130-
</SubsectionCard>,
109+
<SidebarProvider>
110+
<SubsectionCard
111+
section={section}
112+
subsection={subsection}
113+
index={1}
114+
isSelfPaced={false}
115+
getPossibleMoves={jest.fn()}
116+
onOrderChange={jest.fn()}
117+
onOpenPublishModal={jest.fn()}
118+
onOpenDeleteModal={jest.fn()}
119+
onOpenUnlinkModal={jest.fn()}
120+
onNewUnitSubmit={jest.fn()}
121+
onAddUnitFromLibrary={handleOnAddUnitFromLibrary}
122+
isCustomRelativeDatesActive={false}
123+
onEditSubmit={onEditSubectionSubmit}
124+
onDuplicateSubmit={jest.fn()}
125+
onOpenConfigureModal={jest.fn()}
126+
onPasteClick={jest.fn()}
127+
resetScrollState={jest.fn()}
128+
isSectionsExpanded={false}
129+
{...props}
130+
>
131+
<span>children</span>
132+
</SubsectionCard>
133+
</SidebarProvider>,
131134
{
132135
path: '/course/:courseId',
133136
params: { courseId: '5' },
@@ -147,6 +150,28 @@ describe('<SubsectionCard />', () => {
147150
renderComponent();
148151

149152
expect(screen.getByTestId('subsection-card-header')).toBeInTheDocument();
153+
154+
// The card is not selected
155+
const card = screen.getByTestId('subsection-card');
156+
expect(card).not.toHaveClass('outline-card-selected');
157+
});
158+
159+
it('render SubsectionCard component in selected state', () => {
160+
const { container } = renderComponent();
161+
162+
expect(screen.getByTestId('subsection-card-header')).toBeInTheDocument();
163+
164+
// The card is not selected
165+
const card = screen.getByTestId('subsection-card');
166+
expect(card).not.toHaveClass('outline-card-selected');
167+
168+
// Get the <Row> that contains the card and click it to select the card
169+
const el = container.querySelector('div.row.mx-0') as HTMLInputElement;
170+
expect(el).not.toBeNull();
171+
fireEvent.click(el!);
172+
173+
// The card is selected
174+
expect(card).toHaveClass('outline-card-selected');
150175
});
151176

152177
it('expands/collapses the card when the subsection button is clicked', async () => {

src/course-outline/subsection-card/SubsectionCard.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,11 +291,12 @@ const SubsectionCard = ({
291291
onClick={onClickCard}
292292
>
293293
<div
294-
className={classNames('subsection-card',
294+
className={classNames(
295+
'subsection-card',
295296
{
296-
'highlight': isScrolledToElement,
297+
highlight: isScrolledToElement,
297298
'outline-card-selected': subsection.id === selectedContainerId,
298-
}
299+
},
299300
)}
300301
data-testid="subsection-card"
301302
ref={currentRef}

src/course-outline/unit-card/UnitCard.test.tsx

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
import { XBlock } from '@src/data/types';
66
import UnitCard from './UnitCard';
77
import cardMessages from '../card-header/messages';
8+
import { SidebarProvider } from '../common/context/SidebarContext';
89

910
const mockUseAcceptLibraryBlockChanges = jest.fn();
1011
const mockUseIgnoreLibraryBlockChanges = jest.fn();
@@ -73,28 +74,30 @@ const unit = {
7374
} satisfies Partial<XBlock> as XBlock;
7475

7576
const renderComponent = (props?: object) => render(
76-
<UnitCard
77-
section={section}
78-
subsection={subsection}
79-
unit={unit}
80-
index={1}
81-
getPossibleMoves={jest.fn()}
82-
onOrderChange={jest.fn()}
83-
onOpenPublishModal={jest.fn()}
84-
onOpenDeleteModal={jest.fn()}
85-
onOpenUnlinkModal={jest.fn()}
86-
onOpenConfigureModal={jest.fn()}
87-
onEditSubmit={jest.fn()}
88-
onDuplicateSubmit={jest.fn()}
89-
getTitleLink={(id) => `/some/${id}`}
90-
isSelfPaced={false}
91-
isCustomRelativeDatesActive={false}
92-
discussionsSettings={{
93-
providerType: '',
94-
enableGradedUnits: false,
95-
}}
96-
{...props}
97-
/>,
77+
<SidebarProvider>
78+
<UnitCard
79+
section={section}
80+
subsection={subsection}
81+
unit={unit}
82+
index={1}
83+
getPossibleMoves={jest.fn()}
84+
onOrderChange={jest.fn()}
85+
onOpenPublishModal={jest.fn()}
86+
onOpenDeleteModal={jest.fn()}
87+
onOpenUnlinkModal={jest.fn()}
88+
onOpenConfigureModal={jest.fn()}
89+
onEditSubmit={jest.fn()}
90+
onDuplicateSubmit={jest.fn()}
91+
getTitleLink={(id) => `/some/${id}`}
92+
isSelfPaced={false}
93+
isCustomRelativeDatesActive={false}
94+
discussionsSettings={{
95+
providerType: '',
96+
enableGradedUnits: false,
97+
}}
98+
{...props}
99+
/>
100+
</SidebarProvider>,
98101
{
99102
path: '/course/:courseId',
100103
params: { courseId: '5' },
@@ -114,6 +117,28 @@ describe('<UnitCard />', () => {
114117
'href',
115118
'/some/block-v1:UNIX+UX1+2025_T3+type@unit+block@0',
116119
);
120+
121+
// The card is not selected
122+
const card = screen.getByTestId('unit-card');
123+
expect(card).not.toHaveClass('outline-card-selected');
124+
});
125+
126+
it('render UnitCard component in selected state', () => {
127+
const { container } = renderComponent();
128+
129+
expect(screen.getByTestId('unit-card-header')).toBeInTheDocument();
130+
131+
// The card is not selected
132+
const card = screen.getByTestId('unit-card');
133+
expect(card).not.toHaveClass('outline-card-selected');
134+
135+
// Get the <Row> that contains the card and click it to select the card
136+
const el = container.querySelector('div.row.mx-0') as HTMLInputElement;
137+
expect(el).not.toBeNull();
138+
fireEvent.click(el!);
139+
140+
// The card is selected
141+
expect(card).toHaveClass('outline-card-selected');
117142
});
118143

119144
it('hides header based on isHeaderVisible flag', async () => {

src/course-outline/unit-card/UnitCard.tsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,12 @@ const UnitCard = ({
168168
}
169169
}, [dispatch, section, queryClient, courseId]);
170170

171+
const onClickCard = useCallback((e: React.MouseEvent) => {
172+
if (e.target === e.currentTarget) {
173+
openContainerInfoSidebar(unit.id);
174+
}
175+
}, [openContainerInfoSidebar]);
176+
171177
const titleComponent = (
172178
<TitleLink
173179
title={displayName}
@@ -210,12 +216,6 @@ const UnitCard = ({
210216
&& !subsection.upstreamInfo?.upstreamRef
211217
);
212218

213-
const onClickCard = useCallback((e: React.MouseEvent) => {
214-
if (e.target === e.currentTarget) {
215-
openContainerInfoSidebar(unit.id);
216-
}
217-
}, [openContainerInfoSidebar]);
218-
219219
return (
220220
<>
221221
<SortableItem
@@ -235,11 +235,12 @@ const UnitCard = ({
235235
onClick={onClickCard}
236236
>
237237
<div
238-
className={classNames('unit-card',
238+
className={classNames(
239+
'unit-card',
239240
{
240-
'highlight': isScrolledToElement,
241+
highlight: isScrolledToElement,
241242
'outline-card-selected': unit.id === selectedContainerId,
242-
}
243+
},
243244
)}
244245
data-testid="unit-card"
245246
ref={currentRef}

0 commit comments

Comments
 (0)