Skip to content

Commit 071c47c

Browse files
committed
test: Tests added for selected cards
1 parent 06ae806 commit 071c47c

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();
@@ -82,28 +83,30 @@ const section = {
8283
const onEditSectionSubmit = jest.fn();
8384

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

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

128153
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
@@ -295,11 +295,12 @@ const SectionCard = ({
295295
onClick={onClickCard}
296296
>
297297
<div
298-
className={classNames('section-card',
298+
className={classNames(
299+
'section-card',
299300
{
300-
'highlight': isScrolledToElement,
301+
highlight: isScrolledToElement,
301302
'outline-card-selected': section.id === selectedContainerId,
302-
}
303+
},
303304
)}
304305
data-testid="section-card"
305306
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';
@@ -106,29 +107,31 @@ const section: XBlock = {
106107
const onEditSubectionSubmit = jest.fn();
107108

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

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

153178
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
@@ -297,11 +297,12 @@ const SubsectionCard = ({
297297
onClick={onClickCard}
298298
>
299299
<div
300-
className={classNames('subsection-card',
300+
className={classNames(
301+
'subsection-card',
301302
{
302-
'highlight': isScrolledToElement,
303+
highlight: isScrolledToElement,
303304
'outline-card-selected': subsection.id === selectedContainerId,
304-
}
305+
},
305306
)}
306307
data-testid="subsection-card"
307308
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();
@@ -74,28 +75,30 @@ const unit = {
7475
} satisfies Partial<XBlock> as XBlock;
7576

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

120145
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}
@@ -216,12 +222,6 @@ const UnitCard = ({
216222
&& !subsection.upstreamInfo?.upstreamRef
217223
);
218224

219-
const onClickCard = useCallback((e: React.MouseEvent) => {
220-
if (e.target === e.currentTarget) {
221-
openContainerInfoSidebar(unit.id);
222-
}
223-
}, [openContainerInfoSidebar]);
224-
225225
return (
226226
<>
227227
<SortableItem
@@ -241,11 +241,12 @@ const UnitCard = ({
241241
onClick={onClickCard}
242242
>
243243
<div
244-
className={classNames('unit-card',
244+
className={classNames(
245+
'unit-card',
245246
{
246-
'highlight': isScrolledToElement,
247+
highlight: isScrolledToElement,
247248
'outline-card-selected': unit.id === selectedContainerId,
248-
}
249+
},
249250
)}
250251
data-testid="unit-card"
251252
ref={currentRef}

0 commit comments

Comments
 (0)