Skip to content

Commit 6566e3b

Browse files
test(design-system): add tests for components with zero coverage [AR-46651] (#130)
[Jira](https://drivenets.atlassian.net/browse/AR-46651) ### Components - Drawer - Expandable Text Input - Vertical Tabs
1 parent 8ebb713 commit 6566e3b

3 files changed

Lines changed: 239 additions & 13 deletions

File tree

packages/design-system/src/components/ds-drawer/ds-drawer.stories.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Meta, StoryObj } from '@storybook/react-vite';
22
import { useState } from 'react';
33
import classNames from 'classnames';
4+
import { expect, userEvent, within } from 'storybook/test';
45
import DsDrawer from './ds-drawer';
56
import { DsButton } from '../ds-button';
67
import { DsTextInput } from '../ds-text-input';
@@ -136,6 +137,20 @@ export const Default: Story = {
136137
</>
137138
),
138139
},
140+
play: async ({ canvasElement }) => {
141+
const canvas = within(canvasElement);
142+
143+
const openButton = canvas.getByRole('button', { name: /open drawer/i });
144+
await userEvent.click(openButton);
145+
146+
const drawer = await canvas.findByRole('dialog');
147+
await expect(drawer).toHaveAttribute('data-state', 'open');
148+
149+
const closeButton = canvas.getByRole('button', { name: /close/i });
150+
await userEvent.click(closeButton);
151+
152+
await expect(drawer).toHaveAttribute('data-state', 'closed');
153+
},
139154
};
140155

141156
const Tabs = ({ total = 4 }: { total?: number }) => {
@@ -239,6 +254,19 @@ export const WithBackdropAndScroll: Story = {
239254
</>
240255
),
241256
},
257+
play: async ({ canvasElement }) => {
258+
const canvas = within(canvasElement);
259+
260+
const openButton = canvas.getByRole('button', { name: /open drawer/i });
261+
await userEvent.click(openButton);
262+
263+
const drawer = await canvas.findByRole('dialog');
264+
await expect(drawer).toHaveAttribute('data-state', 'open');
265+
266+
const backdrop = canvasElement.querySelector('[data-part="backdrop"]');
267+
await expect(backdrop).toBeInTheDocument();
268+
await expect(backdrop).toHaveAttribute('data-state', 'open');
269+
},
242270
};
243271

244272
export const DockToStart: Story = {

packages/design-system/src/components/ds-expandable-text-input/ds-expandable-text-input.stories.tsx

Lines changed: 97 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Meta, StoryObj } from '@storybook/react-vite';
2+
import { expect, fn, userEvent, within } from 'storybook/test';
23
import { DsExpandableTextInput } from './ds-expandable-text-input';
34
import { textInputSizes } from '../ds-text-input';
45
import { useState } from 'react';
@@ -24,6 +25,7 @@ const meta: Meta<typeof DsExpandableTextInput> = {
2425
options: textInputSizes,
2526
description: 'The size of the input field',
2627
},
28+
onExpandChange: { action: 'expand change' },
2729
disabled: {
2830
control: 'boolean',
2931
description: 'Whether the input is disabled',
@@ -42,6 +44,16 @@ export const Default: Story = {
4244
args: {
4345
icon: 'search',
4446
},
47+
play: async ({ canvasElement }) => {
48+
const canvas = within(canvasElement);
49+
50+
const iconButton = canvas.getByRole('button', { name: 'Open text input' });
51+
await expect(iconButton).toBeInTheDocument();
52+
await expect(iconButton).toHaveAttribute('aria-hidden', 'false');
53+
54+
const input = canvas.getByRole('textbox');
55+
await expect(input).toBeInTheDocument();
56+
},
4557
};
4658

4759
export const CustomIcon: Story = {
@@ -61,15 +73,84 @@ export const ExpandChange: Story = {
6173
args: {
6274
icon: 'search',
6375
placeholder: 'Look at the console',
64-
onExpandChange: (expanded) => {
65-
console.log('Expanded:', expanded);
66-
},
76+
onExpandChange: fn(),
77+
onClear: fn(),
78+
},
79+
play: async ({ args, canvasElement, step }) => {
80+
const canvas = within(canvasElement);
81+
82+
await step('Expand flow', async () => {
83+
const iconButton = canvas.getByRole('button', { name: 'Open text input' });
84+
await userEvent.click(iconButton);
85+
86+
const input = canvas.getByRole('textbox');
87+
await expect(input).toHaveFocus();
88+
await expect(args.onExpandChange).toHaveBeenLastCalledWith(true);
89+
});
90+
91+
await step('Clear flow - with button', async () => {
92+
const input = canvas.getByRole('textbox');
93+
await userEvent.type(input, 'test text');
94+
95+
const clearButton = canvas.getByRole('button', { name: 'Clear' });
96+
await userEvent.click(clearButton);
97+
98+
await expect(args.onClear).toHaveBeenCalled();
99+
await expect(args.onExpandChange).toHaveBeenLastCalledWith(false);
100+
await expect(input).toHaveValue('');
101+
});
102+
103+
// TODO: Fails due to the component bug https://drivenets.atlassian.net/browse/AR-47261.
104+
// Uncomment when the bug is fixed.
105+
// await step('Clear flow - by deleting all text', async () => {
106+
// const iconButton = canvas.getByRole('button', { name: 'Open text input' });
107+
// await userEvent.click(iconButton);
108+
109+
// const input = canvas.getByRole('textbox');
110+
// await userEvent.type(input, 'test');
111+
// await userEvent.clear(input);
112+
113+
// await userEvent.click(canvasElement);
114+
// await expect(args.onExpandChange).toHaveBeenLastCalledWith(false);
115+
// });
116+
117+
await step('Blur without typing', async () => {
118+
const iconButton = canvas.getByRole('button', { name: 'Open text input' });
119+
await userEvent.click(iconButton);
120+
121+
await userEvent.click(canvasElement);
122+
123+
await expect(args.onExpandChange).toHaveBeenLastCalledWith(false);
124+
});
125+
126+
await step('Blur with value - stays expanded', async () => {
127+
const iconButton = canvas.getByRole('button', { name: 'Open text input' });
128+
await userEvent.click(iconButton);
129+
130+
const input = canvas.getByRole('textbox');
131+
await userEvent.type(input, 'test text');
132+
133+
await userEvent.click(canvasElement);
134+
135+
await expect(args.onExpandChange).toHaveBeenLastCalledWith(true);
136+
});
67137
},
68138
};
69139

70140
export const Controlled: Story = {
71-
render: function Render() {
72-
const [value, setValue] = useState('');
141+
argTypes: {
142+
value: {
143+
control: 'text',
144+
description: 'The current value',
145+
},
146+
onChange: { action: 'changed' },
147+
onClear: { action: 'clear' },
148+
},
149+
args: {
150+
value: 'query',
151+
},
152+
render: function Render(args) {
153+
const [value, setValue] = useState(args.value);
73154

74155
return (
75156
<DsExpandableTextInput
@@ -80,6 +161,17 @@ export const Controlled: Story = {
80161
/>
81162
);
82163
},
164+
// TODO: Fails due to the component bug https://drivenets.atlassian.net/browse/AR-47261.
165+
// Uncomment when the bug is fixed.
166+
// play: async ({ canvasElement }) => {
167+
// const canvas = within(canvasElement);
168+
169+
// const input = canvas.getByRole('textbox');
170+
// await expect(input).toHaveValue('search');
171+
172+
// const clearButton = canvas.getByRole('button', { name: 'Clear' });
173+
// await expect(clearButton).toBeVisible();
174+
// },
83175
};
84176

85177
type Person = {

packages/design-system/src/components/ds-vertical-tabs/ds-vertical-tabs.stories.tsx

Lines changed: 114 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Meta, StoryObj } from '@storybook/react-vite';
2+
import { expect, fn, userEvent, within } from 'storybook/test';
23
import DsVerticalTabs from './ds-vertical-tabs';
34
import { DsTypography } from '../ds-typography';
45
import styles from './ds-vertical-tabs.stories.module.scss';
@@ -108,9 +109,12 @@ const TabLabel = ({ item }: { item: TabItem }) => (
108109
);
109110

110111
export const Default: Story = {
111-
render: () => (
112+
args: {
113+
onValueChange: fn(),
114+
},
115+
render: (args) => (
112116
<div className={styles.storyContainer}>
113-
<DsVerticalTabs>
117+
<DsVerticalTabs onValueChange={args.onValueChange}>
114118
<DsVerticalTabs.List>
115119
{sampleItems.map((item) => (
116120
<DsVerticalTabs.Tab key={item.id} value={item.id} disabled={item.disabled}>
@@ -126,12 +130,35 @@ export const Default: Story = {
126130
</DsVerticalTabs>
127131
</div>
128132
),
133+
play: async ({ args, canvas }) => {
134+
const firstTab = canvas.getByRole('tab', { name: /status/i });
135+
await userEvent.click(firstTab);
136+
await expect(firstTab).toHaveAttribute('data-selected');
137+
await expect(canvas.getByText(/selected tab content: status/i)).toBeVisible();
138+
139+
const categoryTab = canvas.getByRole('tab', { name: /^category$/i });
140+
await userEvent.click(categoryTab);
141+
142+
await expect(args.onValueChange).toHaveBeenCalledWith('category');
143+
await expect(categoryTab).toHaveAttribute('data-selected');
144+
await expect(canvas.getByText(/selected tab content: category/i)).toBeVisible();
145+
146+
const versionTab = canvas.getByRole('tab', { name: /^version$/i });
147+
await userEvent.click(versionTab);
148+
149+
await expect(versionTab).toHaveAttribute('data-selected');
150+
await expect(canvas.getByText(/selected tab content: version/i)).toBeVisible();
151+
await expect(args.onValueChange).toHaveBeenCalledWith('version');
152+
},
129153
};
130154

131155
export const WithDisabledItems: Story = {
132-
render: () => (
156+
args: {
157+
onValueChange: fn(),
158+
},
159+
render: (args) => (
133160
<div className={styles.storyContainer}>
134-
<DsVerticalTabs>
161+
<DsVerticalTabs onValueChange={args.onValueChange}>
135162
<DsVerticalTabs.List>
136163
{sampleItemsWithDisabled.map((item) => (
137164
<DsVerticalTabs.Tab key={item.id} value={item.id} disabled={item.disabled}>
@@ -147,13 +174,33 @@ export const WithDisabledItems: Story = {
147174
</DsVerticalTabs>
148175
</div>
149176
),
177+
play: async ({ args, canvasElement }) => {
178+
const canvas = within(canvasElement);
179+
180+
const disabledTab = canvas.getByRole('tab', { name: /status/i });
181+
await expect(disabledTab).toBeDisabled();
182+
183+
await userEvent.click(disabledTab);
184+
await expect(args.onValueChange).not.toHaveBeenCalled();
185+
186+
const runningTab = canvas.getByRole('tab', { name: /running\/completed/i });
187+
await userEvent.click(runningTab);
188+
189+
await expect(args.onValueChange).toHaveBeenCalledWith('running');
190+
await expect(runningTab).toHaveAttribute('data-selected');
191+
await expect(canvas.getByText(/selected tab content: running/i)).toBeVisible();
192+
await expect(disabledTab).toBeDisabled();
193+
},
150194
};
151195

152196
export const LongLabels: Story = {
153-
render: () => {
197+
args: {
198+
onValueChange: fn(),
199+
},
200+
render: (args) => {
154201
return (
155202
<div className={styles.storyContainerShort}>
156-
<DsVerticalTabs>
203+
<DsVerticalTabs onValueChange={args.onValueChange}>
157204
<DsVerticalTabs.List>
158205
{itemsWithLongLabels.map((item) => (
159206
<DsVerticalTabs.Tab key={item.id} value={item.id} disabled={item.disabled}>
@@ -170,13 +217,41 @@ export const LongLabels: Story = {
170217
</div>
171218
);
172219
},
220+
play: async ({ args, canvasElement }) => {
221+
const canvas = within(canvasElement);
222+
223+
const longLabel1 = canvas.getByRole('tab', {
224+
name: /very long navigation item label that might overflow/i,
225+
});
226+
const longLabel2 = canvas.getByRole('tab', { name: /another really long label for testing purposes/i });
227+
const shortLabel = canvas.getByRole('tab', { name: /^short/i });
228+
229+
await expect(longLabel1).toBeVisible();
230+
await expect(longLabel2).toBeVisible();
231+
await expect(shortLabel).toBeVisible();
232+
233+
await userEvent.click(longLabel2);
234+
235+
await expect(longLabel2).toHaveAttribute('data-selected');
236+
await expect(canvas.getByText(/selected tab content: 2/i)).toBeVisible();
237+
await expect(args.onValueChange).toHaveBeenCalledWith('2');
238+
239+
await userEvent.click(shortLabel);
240+
241+
await expect(shortLabel).toHaveAttribute('data-selected');
242+
await expect(canvas.getByText(/selected tab content: 3/i)).toBeVisible();
243+
await expect(args.onValueChange).toHaveBeenCalledWith('3');
244+
},
173245
};
174246

175247
export const HighCounts: Story = {
176-
render: () => {
248+
args: {
249+
onValueChange: fn(),
250+
},
251+
render: (args) => {
177252
return (
178253
<div className={styles.storyContainerShort}>
179-
<DsVerticalTabs>
254+
<DsVerticalTabs onValueChange={args.onValueChange}>
180255
<DsVerticalTabs.List>
181256
{itemsWithHighCounts.map((item) => (
182257
<DsVerticalTabs.Tab key={item.id} value={item.id} disabled={item.disabled}>
@@ -193,4 +268,35 @@ export const HighCounts: Story = {
193268
</div>
194269
);
195270
},
271+
play: async ({ args, canvasElement }) => {
272+
const canvas = within(canvasElement);
273+
274+
await expect(canvas.getByText('999')).toBeVisible();
275+
await expect(canvas.getByText('1000')).toBeVisible();
276+
await expect(canvas.getByText('12345')).toBeVisible();
277+
278+
const statusTab = canvas.getByRole('tab', { name: /status/i });
279+
const categoryTab = canvas.getByRole('tab', { name: /category/i });
280+
const versionTab = canvas.getByRole('tab', { name: /version/i });
281+
282+
await expect(statusTab).toBeVisible();
283+
await expect(categoryTab).toBeVisible();
284+
await expect(versionTab).toBeVisible();
285+
286+
await userEvent.click(categoryTab);
287+
288+
await expect(categoryTab).toHaveAttribute('data-selected');
289+
await expect(canvas.getByText(/selected tab content: category/i)).toBeVisible();
290+
await expect(args.onValueChange).toHaveBeenCalledWith('category');
291+
292+
await userEvent.click(versionTab);
293+
294+
await expect(versionTab).toHaveAttribute('data-selected');
295+
await expect(canvas.getByText(/selected tab content: version/i)).toBeVisible();
296+
await expect(args.onValueChange).toHaveBeenCalledWith('version');
297+
298+
await expect(canvas.getByText('999')).toBeVisible();
299+
await expect(canvas.getByText('1000')).toBeVisible();
300+
await expect(canvas.getByText('12345')).toBeVisible();
301+
},
196302
};

0 commit comments

Comments
 (0)