uikit-react-public 0.30.1 → 0.32.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Heading/Heading.stories.d.ts +5 -7
- package/dist/components/MenuNew/Menu.context.d.ts +9 -0
- package/dist/components/MenuNew/Menu.d.ts +2 -1
- package/dist/components/MenuNew/MenuHeading.d.ts +1 -1
- package/dist/components/MenuNew/MenuItemText.d.ts +2 -1
- package/dist/components/MenuNew/PrimaryMenuItem.d.ts +1 -1
- package/dist/components/Select/Select.types.d.ts +1 -1
- package/dist/components/Sidebar/Sidebar.d.ts +12 -0
- package/dist/components/Sidebar/Sidebar.stories.d.ts +38 -0
- package/dist/components/Sidebar/__tests__/Sidebar.test.d.ts +1 -0
- package/dist/components/Sidebar/index.d.ts +2 -0
- package/dist/components/Snackbar/Snackbar.d.ts +9 -5
- package/dist/components/Snackbar/Snackbar.stories.d.ts +3 -1
- package/dist/components/Snackbar/Snackbars.d.ts +19 -0
- package/dist/components/Snackbar/Snackbars.stories.d.ts +52 -0
- package/dist/components/Snackbar/__tests__/Snackbars.test.d.ts +1 -0
- package/dist/components/Snackbar/index.d.ts +2 -0
- package/dist/components/index.d.ts +4 -1
- package/dist/index.js +5979 -5448
- package/lib/components/Dropdown/Dropdown.stories.tsx +69 -74
- package/lib/components/Heading/Documentation.mdx +4 -14
- package/lib/components/Heading/Heading.stories.tsx +16 -30
- package/lib/components/MenuNew/Menu.context.tsx +18 -0
- package/lib/components/MenuNew/Menu.tsx +14 -9
- package/lib/components/MenuNew/MenuDivider.tsx +12 -1
- package/lib/components/MenuNew/MenuHeading.tsx +6 -0
- package/lib/components/MenuNew/MenuItemText.tsx +27 -3
- package/lib/components/MenuNew/MenuSection.tsx +11 -0
- package/lib/components/MenuNew/PrimaryMenuItem.tsx +71 -2
- package/lib/components/Select/Select.types.ts +1 -7
- package/lib/components/Select/__tests__/Select.test.tsx +112 -0
- package/lib/components/Select/__tests__/__snapshots__/Select.test.tsx.snap +5 -0
- package/lib/components/Select/subcomponents/CustomSelect.tsx +75 -3
- package/lib/components/Select/subcomponents/FilterInput.tsx +1 -1
- package/lib/components/Sidebar/Sidebar.stories.tsx +94 -0
- package/lib/components/Sidebar/Sidebar.tsx +208 -0
- package/lib/components/Sidebar/__tests__/Sidebar.test.tsx +96 -0
- package/lib/components/Sidebar/__tests__/__snapshots__/Sidebar.test.tsx.snap +272 -0
- package/lib/components/Sidebar/index.ts +2 -0
- package/lib/components/Snackbar/Snackbar.stories.tsx +22 -0
- package/lib/components/Snackbar/Snackbar.tsx +168 -119
- package/lib/components/Snackbar/Snackbars.stories.tsx +141 -0
- package/lib/components/Snackbar/Snackbars.tsx +377 -0
- package/lib/components/Snackbar/__tests__/Snackbar.test.tsx +222 -10
- package/lib/components/Snackbar/__tests__/Snackbars.test.tsx +377 -0
- package/lib/components/Snackbar/__tests__/__snapshots__/Snackbar.test.tsx.snap +46 -25
- package/lib/components/Snackbar/index.ts +6 -0
- package/lib/components/index.ts +10 -1
- package/package.json +1 -1
|
@@ -2,18 +2,32 @@ import { describe, expect, test, vi, beforeEach } from 'vitest';
|
|
|
2
2
|
import { render, screen } from '@testing-library/react';
|
|
3
3
|
// import '@testing-library/jest-dom';
|
|
4
4
|
import Snackbar from '../Snackbar';
|
|
5
|
-
import
|
|
5
|
+
import Icon from '../../Icon';
|
|
6
|
+
import { ThemeContextProvider, themes } from '../../../theme/useTheme';
|
|
7
|
+
|
|
8
|
+
const tokenTestTheme = {
|
|
9
|
+
...themes.light,
|
|
10
|
+
colour: {
|
|
11
|
+
...themes.light.colour,
|
|
12
|
+
fill: {
|
|
13
|
+
...themes.light.colour.fill,
|
|
14
|
+
brandPrimary: '#010101',
|
|
15
|
+
critical: '#020202',
|
|
16
|
+
success: '#030303',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
6
20
|
|
|
7
21
|
describe('Snackbar', () => {
|
|
8
22
|
beforeEach(() => {
|
|
9
|
-
vi.
|
|
23
|
+
vi.restoreAllMocks();
|
|
10
24
|
});
|
|
11
25
|
|
|
12
26
|
// Snapshot tests
|
|
13
27
|
|
|
14
28
|
test('snapshot: minimal props', () => {
|
|
15
29
|
const renderResult = render(
|
|
16
|
-
<ThemeContextProvider>
|
|
30
|
+
<ThemeContextProvider theme='light'>
|
|
17
31
|
<Snackbar action='close'>Test snackbar</Snackbar>
|
|
18
32
|
</ThemeContextProvider>
|
|
19
33
|
);
|
|
@@ -22,7 +36,7 @@ describe('Snackbar', () => {
|
|
|
22
36
|
|
|
23
37
|
test('snapshot: custom test id', () => {
|
|
24
38
|
const renderResult = render(
|
|
25
|
-
<ThemeContextProvider>
|
|
39
|
+
<ThemeContextProvider theme='light'>
|
|
26
40
|
<Snackbar
|
|
27
41
|
action='undo'
|
|
28
42
|
testId='custom-test-id'
|
|
@@ -39,7 +53,7 @@ describe('Snackbar', () => {
|
|
|
39
53
|
test('Test ID: Default', () => {
|
|
40
54
|
const defaultTestId = 'ucl-uikit-snackbar';
|
|
41
55
|
render(
|
|
42
|
-
<ThemeContextProvider>
|
|
56
|
+
<ThemeContextProvider theme='light'>
|
|
43
57
|
<Snackbar action='close'>Test snackbar</Snackbar>
|
|
44
58
|
</ThemeContextProvider>
|
|
45
59
|
);
|
|
@@ -49,7 +63,7 @@ describe('Snackbar', () => {
|
|
|
49
63
|
|
|
50
64
|
test('Test ID: Custom', () => {
|
|
51
65
|
render(
|
|
52
|
-
<ThemeContextProvider>
|
|
66
|
+
<ThemeContextProvider theme='light'>
|
|
53
67
|
<Snackbar
|
|
54
68
|
action='undo'
|
|
55
69
|
testId='custom-test-id'
|
|
@@ -62,10 +76,123 @@ describe('Snackbar', () => {
|
|
|
62
76
|
expect(customTestId).toBeDefined();
|
|
63
77
|
});
|
|
64
78
|
|
|
79
|
+
test('passes ref to the root element', () => {
|
|
80
|
+
const ref = { current: null as HTMLDivElement | null };
|
|
81
|
+
|
|
82
|
+
render(
|
|
83
|
+
<ThemeContextProvider theme='light'>
|
|
84
|
+
<Snackbar ref={ref}>Test snackbar</Snackbar>
|
|
85
|
+
</ThemeContextProvider>
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
expect(ref.current).toBe(screen.getByTestId('ucl-uikit-snackbar'));
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('Default variant uses polite status semantics', () => {
|
|
92
|
+
render(
|
|
93
|
+
<ThemeContextProvider theme='light'>
|
|
94
|
+
<Snackbar action='undo'>Test snackbar</Snackbar>
|
|
95
|
+
</ThemeContextProvider>
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const snackbar = screen.getByRole('status');
|
|
99
|
+
expect(snackbar.textContent).toBe('Test snackbar');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('Error variant uses assertive alert semantics', () => {
|
|
103
|
+
render(
|
|
104
|
+
<ThemeContextProvider theme='light'>
|
|
105
|
+
<Snackbar
|
|
106
|
+
action='close'
|
|
107
|
+
variant='error'
|
|
108
|
+
>
|
|
109
|
+
Test snackbar
|
|
110
|
+
</Snackbar>
|
|
111
|
+
</ThemeContextProvider>
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const snackbar = screen.getByRole('alert');
|
|
115
|
+
expect(snackbar.textContent).toBe('Test snackbar');
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('Success variant uses polite status semantics', () => {
|
|
119
|
+
render(
|
|
120
|
+
<ThemeContextProvider theme='light'>
|
|
121
|
+
<Snackbar
|
|
122
|
+
action='close'
|
|
123
|
+
variant='success'
|
|
124
|
+
>
|
|
125
|
+
Test snackbar
|
|
126
|
+
</Snackbar>
|
|
127
|
+
</ThemeContextProvider>
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const snackbar = screen.getByRole('status');
|
|
131
|
+
expect(snackbar.textContent).toBe('Test snackbar');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test.each([
|
|
135
|
+
['default', 'rgb(1, 1, 1)'],
|
|
136
|
+
['error', 'rgb(2, 2, 2)'],
|
|
137
|
+
['success', 'rgb(3, 3, 3)'],
|
|
138
|
+
] as const)(
|
|
139
|
+
'%s variant uses its semantic background token',
|
|
140
|
+
(variant, colour) => {
|
|
141
|
+
render(
|
|
142
|
+
<ThemeContextProvider theme={tokenTestTheme}>
|
|
143
|
+
<Snackbar
|
|
144
|
+
action='close'
|
|
145
|
+
variant={variant}
|
|
146
|
+
>
|
|
147
|
+
Test snackbar
|
|
148
|
+
</Snackbar>
|
|
149
|
+
</ThemeContextProvider>
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
expect(
|
|
153
|
+
getComputedStyle(screen.getByTestId('ucl-uikit-snackbar'))
|
|
154
|
+
.backgroundColor
|
|
155
|
+
).toBe(colour);
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
test('Close button has a default accessible name', () => {
|
|
160
|
+
render(
|
|
161
|
+
<ThemeContextProvider theme='light'>
|
|
162
|
+
<Snackbar action='close'>Test snackbar</Snackbar>
|
|
163
|
+
</ThemeContextProvider>
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const closeButton = screen.getByRole('button', {
|
|
167
|
+
name: 'Dismiss notification',
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
expect(closeButton).toBeDefined();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('Close button accessible name can be customised', () => {
|
|
174
|
+
render(
|
|
175
|
+
<ThemeContextProvider theme='light'>
|
|
176
|
+
<Snackbar
|
|
177
|
+
action='close'
|
|
178
|
+
closeButtonAriaLabel='Dismiss saved notification'
|
|
179
|
+
>
|
|
180
|
+
Test snackbar
|
|
181
|
+
</Snackbar>
|
|
182
|
+
</ThemeContextProvider>
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const closeButton = screen.getByRole('button', {
|
|
186
|
+
name: 'Dismiss saved notification',
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
expect(closeButton).toBeDefined();
|
|
190
|
+
});
|
|
191
|
+
|
|
65
192
|
test('Close callback is called', () => {
|
|
66
193
|
const onClose = vi.fn();
|
|
67
194
|
render(
|
|
68
|
-
<ThemeContextProvider>
|
|
195
|
+
<ThemeContextProvider theme='light'>
|
|
69
196
|
<Snackbar
|
|
70
197
|
action='close'
|
|
71
198
|
onClose={onClose}
|
|
@@ -82,7 +209,7 @@ describe('Snackbar', () => {
|
|
|
82
209
|
test('Undo callback is called', () => {
|
|
83
210
|
const onUndo = vi.fn();
|
|
84
211
|
render(
|
|
85
|
-
<ThemeContextProvider>
|
|
212
|
+
<ThemeContextProvider theme='light'>
|
|
86
213
|
<Snackbar
|
|
87
214
|
action='undo'
|
|
88
215
|
onUndo={onUndo}
|
|
@@ -96,10 +223,95 @@ describe('Snackbar', () => {
|
|
|
96
223
|
expect(onUndo).toHaveBeenCalled();
|
|
97
224
|
});
|
|
98
225
|
|
|
226
|
+
test('Undo action uses sentence case label', () => {
|
|
227
|
+
render(
|
|
228
|
+
<ThemeContextProvider theme='light'>
|
|
229
|
+
<Snackbar action='undo'>Test snackbar</Snackbar>
|
|
230
|
+
</ThemeContextProvider>
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
expect(screen.getByRole('button', { name: 'Undo' })).toBeDefined();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test('Default variant renders info icon', () => {
|
|
237
|
+
vi.spyOn(Icon, 'Info').mockImplementation((props) => (
|
|
238
|
+
<svg
|
|
239
|
+
data-testid='info-icon'
|
|
240
|
+
{...props}
|
|
241
|
+
/>
|
|
242
|
+
));
|
|
243
|
+
|
|
244
|
+
render(
|
|
245
|
+
<ThemeContextProvider theme='light'>
|
|
246
|
+
<Snackbar action='close'>Test snackbar</Snackbar>
|
|
247
|
+
</ThemeContextProvider>
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
expect(screen.getByTestId('info-icon')).toBeDefined();
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
test('Error variant renders warning icon', () => {
|
|
254
|
+
vi.spyOn(Icon, 'AlertTriangle').mockImplementation((props) => (
|
|
255
|
+
<svg
|
|
256
|
+
data-testid='alert-triangle-icon'
|
|
257
|
+
{...props}
|
|
258
|
+
/>
|
|
259
|
+
));
|
|
260
|
+
|
|
261
|
+
render(
|
|
262
|
+
<ThemeContextProvider theme='light'>
|
|
263
|
+
<Snackbar
|
|
264
|
+
action='close'
|
|
265
|
+
variant='error'
|
|
266
|
+
>
|
|
267
|
+
Test snackbar
|
|
268
|
+
</Snackbar>
|
|
269
|
+
</ThemeContextProvider>
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
expect(screen.getByTestId('alert-triangle-icon')).toBeDefined();
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
test('Success variant renders check icon', () => {
|
|
276
|
+
vi.spyOn(Icon, 'CheckCircle').mockImplementation((props) => (
|
|
277
|
+
<svg
|
|
278
|
+
data-testid='check-circle-icon'
|
|
279
|
+
{...props}
|
|
280
|
+
/>
|
|
281
|
+
));
|
|
282
|
+
|
|
283
|
+
render(
|
|
284
|
+
<ThemeContextProvider theme='light'>
|
|
285
|
+
<Snackbar
|
|
286
|
+
action='close'
|
|
287
|
+
variant='success'
|
|
288
|
+
>
|
|
289
|
+
Test snackbar
|
|
290
|
+
</Snackbar>
|
|
291
|
+
</ThemeContextProvider>
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
expect(screen.getByTestId('check-circle-icon')).toBeDefined();
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test('Decorative icons are hidden from assistive technology', () => {
|
|
298
|
+
render(
|
|
299
|
+
<ThemeContextProvider theme='light'>
|
|
300
|
+
<Snackbar action='close'>Test snackbar</Snackbar>
|
|
301
|
+
</ThemeContextProvider>
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
const icons = screen.getAllByTestId('ucl-uikit-icon');
|
|
305
|
+
|
|
306
|
+
icons.forEach((icon) => {
|
|
307
|
+
expect(icon.getAttribute('aria-hidden')).toBe('true');
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
|
|
99
311
|
test("Close callback cannot be called when action is 'undo'", () => {
|
|
100
312
|
const onClose = vi.fn();
|
|
101
313
|
render(
|
|
102
|
-
<ThemeContextProvider>
|
|
314
|
+
<ThemeContextProvider theme='light'>
|
|
103
315
|
<Snackbar
|
|
104
316
|
action='undo'
|
|
105
317
|
onClose={onClose}
|
|
@@ -117,7 +329,7 @@ describe('Snackbar', () => {
|
|
|
117
329
|
test("Undo callback cannot be called when action is 'close'", () => {
|
|
118
330
|
const onUndo = vi.fn();
|
|
119
331
|
render(
|
|
120
|
-
<ThemeContextProvider>
|
|
332
|
+
<ThemeContextProvider theme='light'>
|
|
121
333
|
<Snackbar
|
|
122
334
|
action='close'
|
|
123
335
|
onUndo={onUndo}
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import { act, render, screen } from '@testing-library/react';
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
|
|
3
|
+
import { ThemeContextProvider } from '../../../theme/useTheme';
|
|
4
|
+
import Snackbars, { type SnackbarsItem } from '../Snackbars';
|
|
5
|
+
|
|
6
|
+
const renderSnackbars = (
|
|
7
|
+
items: SnackbarsItem[],
|
|
8
|
+
onDismiss = vi.fn(),
|
|
9
|
+
props: Partial<React.ComponentProps<typeof Snackbars>> = {}
|
|
10
|
+
) =>
|
|
11
|
+
render(
|
|
12
|
+
<ThemeContextProvider>
|
|
13
|
+
<Snackbars
|
|
14
|
+
items={items}
|
|
15
|
+
onDismiss={onDismiss}
|
|
16
|
+
duration={0}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
</ThemeContextProvider>
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
describe('Snackbars', () => {
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
vi.useFakeTimers();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
vi.clearAllTimers();
|
|
29
|
+
vi.useRealTimers();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('renders a single snackbar with default lifecycle wrapper', () => {
|
|
33
|
+
renderSnackbars([{ id: 'saved', children: 'Saved' }]);
|
|
34
|
+
|
|
35
|
+
expect(screen.getByTestId('ucl-uikit-snackbars')).toBeDefined();
|
|
36
|
+
expect(screen.getByTestId('ucl-uikit-snackbars-saved')).toBeDefined();
|
|
37
|
+
expect(screen.getByText('Saved')).toBeDefined();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('passes snackbar props through to each rendered snackbar', () => {
|
|
41
|
+
const onFocus = vi.fn();
|
|
42
|
+
const onBlur = vi.fn();
|
|
43
|
+
|
|
44
|
+
renderSnackbars([
|
|
45
|
+
{
|
|
46
|
+
id: 'saved',
|
|
47
|
+
children: 'Saved',
|
|
48
|
+
closeButtonAriaLabel: 'Close saved notification',
|
|
49
|
+
onFocus,
|
|
50
|
+
onBlur,
|
|
51
|
+
tabIndex: 0,
|
|
52
|
+
title: 'Saved notification',
|
|
53
|
+
},
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
const snackbar = screen.getByTestId('ucl-uikit-snackbars-saved');
|
|
57
|
+
|
|
58
|
+
expect(snackbar).toHaveAttribute('title', 'Saved notification');
|
|
59
|
+
expect(
|
|
60
|
+
screen.getByLabelText('Close saved notification')
|
|
61
|
+
).toBeInTheDocument();
|
|
62
|
+
|
|
63
|
+
act(() => {
|
|
64
|
+
snackbar.focus();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
expect(onFocus).toHaveBeenCalledTimes(1);
|
|
68
|
+
|
|
69
|
+
act(() => {
|
|
70
|
+
snackbar.blur();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
expect(onBlur).toHaveBeenCalledTimes(1);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('renders up to maxVisible snackbars', () => {
|
|
77
|
+
renderSnackbars(
|
|
78
|
+
[
|
|
79
|
+
{ id: 'one', children: 'One' },
|
|
80
|
+
{ id: 'two', children: 'Two' },
|
|
81
|
+
{ id: 'three', children: 'Three' },
|
|
82
|
+
],
|
|
83
|
+
vi.fn(),
|
|
84
|
+
{ maxVisible: 2 }
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
expect(screen.getByText('One')).toBeDefined();
|
|
88
|
+
expect(screen.getByText('Two')).toBeDefined();
|
|
89
|
+
expect(screen.queryByText('Three')).toBeNull();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('close action dismisses after transition duration', () => {
|
|
93
|
+
const onDismiss = vi.fn();
|
|
94
|
+
renderSnackbars([{ id: 'saved', children: 'Saved' }], onDismiss, {
|
|
95
|
+
transitionDuration: 200,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const closeButton = screen.getByTestId(
|
|
99
|
+
'ucl-uikit-snackbars-saved-close-button'
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
act(() => {
|
|
103
|
+
closeButton.click();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
expect(closeButton).toBeDisabled();
|
|
107
|
+
expect(onDismiss).not.toHaveBeenCalled();
|
|
108
|
+
|
|
109
|
+
act(() => {
|
|
110
|
+
vi.advanceTimersByTime(200);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
expect(onDismiss).toHaveBeenCalledWith('saved');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('close action is disabled while exiting', () => {
|
|
117
|
+
const onClose = vi.fn();
|
|
118
|
+
const onDismiss = vi.fn();
|
|
119
|
+
renderSnackbars([{ id: 'saved', children: 'Saved', onClose }], onDismiss, {
|
|
120
|
+
transitionDuration: 200,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const closeButton = screen.getByTestId(
|
|
124
|
+
'ucl-uikit-snackbars-saved-close-button'
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
act(() => {
|
|
128
|
+
closeButton.click();
|
|
129
|
+
closeButton.click();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
expect(closeButton).toBeDisabled();
|
|
133
|
+
expect(onClose).toHaveBeenCalledTimes(1);
|
|
134
|
+
expect(onDismiss).not.toHaveBeenCalled();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('undo action calls onUndo and dismisses after transition duration', () => {
|
|
138
|
+
const onDismiss = vi.fn();
|
|
139
|
+
const onUndo = vi.fn();
|
|
140
|
+
renderSnackbars(
|
|
141
|
+
[
|
|
142
|
+
{
|
|
143
|
+
id: 'undoable',
|
|
144
|
+
action: 'undo',
|
|
145
|
+
children: 'Undoable',
|
|
146
|
+
onUndo,
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
onDismiss,
|
|
150
|
+
{ transitionDuration: 200 }
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
act(() => {
|
|
154
|
+
screen.getByTestId('ucl-uikit-snackbars-undoable-undo-button').click();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
expect(
|
|
158
|
+
screen.getByTestId('ucl-uikit-snackbars-undoable-undo-button')
|
|
159
|
+
).toBeDisabled();
|
|
160
|
+
expect(onUndo).toHaveBeenCalledTimes(1);
|
|
161
|
+
expect(onDismiss).not.toHaveBeenCalled();
|
|
162
|
+
|
|
163
|
+
act(() => {
|
|
164
|
+
vi.advanceTimersByTime(200);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
expect(onDismiss).toHaveBeenCalledWith('undoable');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test('undo action is disabled while exiting', () => {
|
|
171
|
+
const onDismiss = vi.fn();
|
|
172
|
+
const onUndo = vi.fn();
|
|
173
|
+
renderSnackbars(
|
|
174
|
+
[
|
|
175
|
+
{
|
|
176
|
+
id: 'undoable',
|
|
177
|
+
action: 'undo',
|
|
178
|
+
children: 'Undoable',
|
|
179
|
+
onUndo,
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
onDismiss,
|
|
183
|
+
{ transitionDuration: 200 }
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const undoButton = screen.getByTestId(
|
|
187
|
+
'ucl-uikit-snackbars-undoable-undo-button'
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
act(() => {
|
|
191
|
+
undoButton.click();
|
|
192
|
+
undoButton.click();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
expect(undoButton).toBeDisabled();
|
|
196
|
+
expect(onUndo).toHaveBeenCalledTimes(1);
|
|
197
|
+
expect(onDismiss).not.toHaveBeenCalled();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test('auto-dismisses after duration and transition duration', () => {
|
|
201
|
+
const onDismiss = vi.fn();
|
|
202
|
+
renderSnackbars([{ id: 'saved', children: 'Saved' }], onDismiss, {
|
|
203
|
+
duration: 100,
|
|
204
|
+
transitionDuration: 200,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
act(() => {
|
|
208
|
+
vi.advanceTimersByTime(100);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
expect(onDismiss).not.toHaveBeenCalled();
|
|
212
|
+
|
|
213
|
+
act(() => {
|
|
214
|
+
vi.advanceTimersByTime(200);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
expect(onDismiss).toHaveBeenCalledWith('saved');
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test('does not auto-dismiss when duration is zero', () => {
|
|
221
|
+
const onDismiss = vi.fn();
|
|
222
|
+
renderSnackbars([{ id: 'saved', children: 'Saved' }], onDismiss, {
|
|
223
|
+
duration: 0,
|
|
224
|
+
transitionDuration: 50,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
act(() => {
|
|
228
|
+
vi.advanceTimersByTime(1000);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
expect(onDismiss).not.toHaveBeenCalled();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test('undo action still auto-dismisses when duration is zero', () => {
|
|
235
|
+
const onDismiss = vi.fn();
|
|
236
|
+
renderSnackbars(
|
|
237
|
+
[{ id: 'undoable', action: 'undo', children: 'Undoable' }],
|
|
238
|
+
onDismiss,
|
|
239
|
+
{
|
|
240
|
+
duration: 0,
|
|
241
|
+
transitionDuration: 50,
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
act(() => {
|
|
246
|
+
vi.advanceTimersByTime(5000);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
expect(onDismiss).not.toHaveBeenCalled();
|
|
250
|
+
|
|
251
|
+
act(() => {
|
|
252
|
+
vi.advanceTimersByTime(50);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
expect(onDismiss).toHaveBeenCalledWith('undoable');
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test('undo action item duration zero falls back to the collection duration', () => {
|
|
259
|
+
const onDismiss = vi.fn();
|
|
260
|
+
renderSnackbars(
|
|
261
|
+
[
|
|
262
|
+
{
|
|
263
|
+
id: 'undoable',
|
|
264
|
+
action: 'undo',
|
|
265
|
+
children: 'Undoable',
|
|
266
|
+
duration: 0,
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
onDismiss,
|
|
270
|
+
{
|
|
271
|
+
duration: 100,
|
|
272
|
+
transitionDuration: 50,
|
|
273
|
+
}
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
act(() => {
|
|
277
|
+
vi.advanceTimersByTime(100);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
expect(onDismiss).not.toHaveBeenCalled();
|
|
281
|
+
|
|
282
|
+
act(() => {
|
|
283
|
+
vi.advanceTimersByTime(50);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
expect(onDismiss).toHaveBeenCalledWith('undoable');
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test('pauses auto-dismiss while a snackbar has focus', () => {
|
|
290
|
+
const onDismiss = vi.fn();
|
|
291
|
+
renderSnackbars([{ id: 'saved', children: 'Saved' }], onDismiss, {
|
|
292
|
+
duration: 100,
|
|
293
|
+
transitionDuration: 50,
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
act(() => {
|
|
297
|
+
vi.advanceTimersByTime(60);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
act(() => {
|
|
301
|
+
screen.getByTestId('ucl-uikit-snackbars-saved-close-button').focus();
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
act(() => {
|
|
305
|
+
vi.advanceTimersByTime(500);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
expect(onDismiss).not.toHaveBeenCalled();
|
|
309
|
+
|
|
310
|
+
act(() => {
|
|
311
|
+
screen.getByTestId('ucl-uikit-snackbars-saved-close-button').blur();
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
act(() => {
|
|
315
|
+
vi.advanceTimersByTime(39);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
expect(onDismiss).not.toHaveBeenCalled();
|
|
319
|
+
|
|
320
|
+
act(() => {
|
|
321
|
+
vi.advanceTimersByTime(1);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
expect(onDismiss).not.toHaveBeenCalled();
|
|
325
|
+
|
|
326
|
+
act(() => {
|
|
327
|
+
vi.advanceTimersByTime(50);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
expect(onDismiss).toHaveBeenCalledWith('saved');
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
test('adding a snackbar does not refresh existing snackbar duration timers', () => {
|
|
334
|
+
const onDismiss = vi.fn();
|
|
335
|
+
const { rerender } = render(
|
|
336
|
+
<ThemeContextProvider>
|
|
337
|
+
<Snackbars
|
|
338
|
+
items={[{ id: 'first', children: 'First' }]}
|
|
339
|
+
onDismiss={onDismiss}
|
|
340
|
+
duration={100}
|
|
341
|
+
transitionDuration={50}
|
|
342
|
+
/>
|
|
343
|
+
</ThemeContextProvider>
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
act(() => {
|
|
347
|
+
vi.advanceTimersByTime(75);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
rerender(
|
|
351
|
+
<ThemeContextProvider>
|
|
352
|
+
<Snackbars
|
|
353
|
+
items={[
|
|
354
|
+
{ id: 'first', children: 'First' },
|
|
355
|
+
{ id: 'second', children: 'Second' },
|
|
356
|
+
]}
|
|
357
|
+
onDismiss={onDismiss}
|
|
358
|
+
duration={100}
|
|
359
|
+
transitionDuration={50}
|
|
360
|
+
/>
|
|
361
|
+
</ThemeContextProvider>
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
act(() => {
|
|
365
|
+
vi.advanceTimersByTime(25);
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
expect(onDismiss).not.toHaveBeenCalled();
|
|
369
|
+
|
|
370
|
+
act(() => {
|
|
371
|
+
vi.advanceTimersByTime(50);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
expect(onDismiss).toHaveBeenCalledTimes(1);
|
|
375
|
+
expect(onDismiss).toHaveBeenCalledWith('first');
|
|
376
|
+
});
|
|
377
|
+
});
|