@khanacademy/wonder-blocks-button 6.3.8 → 6.3.10
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/CHANGELOG.md +26 -0
- package/package.json +8 -8
- package/src/__tests__/__snapshots__/custom-snapshot.test.tsx.snap +0 -3325
- package/src/__tests__/custom-snapshot.test.tsx +0 -110
- package/src/components/__tests__/button-with-icon.test.tsx +0 -277
- package/src/components/__tests__/button.test.tsx +0 -850
- package/src/components/__tests__/button.typestest.tsx +0 -48
- package/src/components/button-core.tsx +0 -519
- package/src/components/button-icon.tsx +0 -47
- package/src/components/button.tsx +0 -309
- package/src/index.ts +0 -5
- package/src/themes/default.ts +0 -163
- package/src/themes/khanmigo.ts +0 -58
- package/src/themes/themed-button.tsx +0 -43
- package/tsconfig-build.json +0 -17
- package/tsconfig-build.tsbuildinfo +0 -1
|
@@ -1,850 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test for Wonder Blocks Button component.
|
|
3
|
-
*
|
|
4
|
-
* The test for buttons with icons are in a separate file
|
|
5
|
-
* (button-with-icon.test.tsx) since this one is already too long.
|
|
6
|
-
*/
|
|
7
|
-
import * as React from "react";
|
|
8
|
-
import {MemoryRouter, Route, Switch} from "react-router-dom";
|
|
9
|
-
import {render, screen, waitFor} from "@testing-library/react";
|
|
10
|
-
import {userEvent} from "@testing-library/user-event";
|
|
11
|
-
|
|
12
|
-
import Button from "../button";
|
|
13
|
-
|
|
14
|
-
describe("Button", () => {
|
|
15
|
-
const {location} = window;
|
|
16
|
-
|
|
17
|
-
beforeAll(() => {
|
|
18
|
-
// @ts-expect-error [FEI-5019] - TS2790 - The operand of a 'delete' operator must be optional.
|
|
19
|
-
delete window.location;
|
|
20
|
-
// @ts-expect-error [FEI-5019] - TS2740 - Type '{ assign: Mock<any, any, any>; }' is missing the following properties from type 'Location': ancestorOrigins, hash, host, hostname, and 8 more.
|
|
21
|
-
window.location = {assign: jest.fn()};
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
afterAll(() => {
|
|
25
|
-
window.location = location;
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test("client-side navigation", async () => {
|
|
29
|
-
// Arrange
|
|
30
|
-
render(
|
|
31
|
-
<MemoryRouter>
|
|
32
|
-
<div>
|
|
33
|
-
<Button href="/foo">Click me!</Button>
|
|
34
|
-
<Switch>
|
|
35
|
-
<Route path="/foo">
|
|
36
|
-
<div id="foo">Hello, world!</div>
|
|
37
|
-
</Route>
|
|
38
|
-
</Switch>
|
|
39
|
-
</div>
|
|
40
|
-
</MemoryRouter>,
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
// Act
|
|
44
|
-
const button = await screen.findByRole("button");
|
|
45
|
-
await userEvent.click(button);
|
|
46
|
-
|
|
47
|
-
// Assert
|
|
48
|
-
expect(await screen.findByText("Hello, world!")).toBeInTheDocument();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test("beforeNav rejection blocks client-side navigation", async () => {
|
|
52
|
-
// Arrange
|
|
53
|
-
render(
|
|
54
|
-
<MemoryRouter>
|
|
55
|
-
<div>
|
|
56
|
-
<Button href="/foo" beforeNav={() => Promise.reject()}>
|
|
57
|
-
Click me!
|
|
58
|
-
</Button>
|
|
59
|
-
<Switch>
|
|
60
|
-
<Route path="/foo">
|
|
61
|
-
<div id="foo">Hello, world!</div>
|
|
62
|
-
</Route>
|
|
63
|
-
</Switch>
|
|
64
|
-
</div>
|
|
65
|
-
</MemoryRouter>,
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
// Act
|
|
69
|
-
const button = await screen.findByRole("button");
|
|
70
|
-
await userEvent.click(button);
|
|
71
|
-
|
|
72
|
-
// Assert
|
|
73
|
-
expect(screen.queryByText("Hello, world!")).not.toBeInTheDocument();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test("beforeNav rejection blocks calling safeWithNav", async () => {
|
|
77
|
-
// Arrange
|
|
78
|
-
const safeWithNavMock = jest.fn();
|
|
79
|
-
render(
|
|
80
|
-
<MemoryRouter>
|
|
81
|
-
<div>
|
|
82
|
-
<Button
|
|
83
|
-
href="/foo"
|
|
84
|
-
beforeNav={() => Promise.reject()}
|
|
85
|
-
safeWithNav={safeWithNavMock}
|
|
86
|
-
>
|
|
87
|
-
Click me!
|
|
88
|
-
</Button>
|
|
89
|
-
<Switch>
|
|
90
|
-
<Route path="/foo">
|
|
91
|
-
<div id="foo">Hello, world!</div>
|
|
92
|
-
</Route>
|
|
93
|
-
</Switch>
|
|
94
|
-
</div>
|
|
95
|
-
</MemoryRouter>,
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
// Act
|
|
99
|
-
const button = await screen.findByRole("button");
|
|
100
|
-
await userEvent.click(button);
|
|
101
|
-
|
|
102
|
-
// Assert
|
|
103
|
-
expect(safeWithNavMock).not.toHaveBeenCalled();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test("beforeNav resolution results in client-side navigation", async () => {
|
|
107
|
-
// Arrange
|
|
108
|
-
render(
|
|
109
|
-
<MemoryRouter>
|
|
110
|
-
<div>
|
|
111
|
-
<Button href="/foo" beforeNav={() => Promise.resolve()}>
|
|
112
|
-
Click me!
|
|
113
|
-
</Button>
|
|
114
|
-
<Switch>
|
|
115
|
-
<Route path="/foo">
|
|
116
|
-
<div id="foo">Hello, world!</div>
|
|
117
|
-
</Route>
|
|
118
|
-
</Switch>
|
|
119
|
-
</div>
|
|
120
|
-
</MemoryRouter>,
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
// Act
|
|
124
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
125
|
-
|
|
126
|
-
// Assert
|
|
127
|
-
await waitFor(async () => {
|
|
128
|
-
expect(
|
|
129
|
-
await screen.findByText("Hello, world!"),
|
|
130
|
-
).toBeInTheDocument();
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
test("beforeNav resolution results in safeWithNav being called", async () => {
|
|
135
|
-
// Arrange
|
|
136
|
-
const safeWithNavMock = jest.fn();
|
|
137
|
-
render(
|
|
138
|
-
<MemoryRouter>
|
|
139
|
-
<div>
|
|
140
|
-
<Button
|
|
141
|
-
href="/foo"
|
|
142
|
-
beforeNav={() => Promise.resolve()}
|
|
143
|
-
safeWithNav={safeWithNavMock}
|
|
144
|
-
>
|
|
145
|
-
Click me!
|
|
146
|
-
</Button>
|
|
147
|
-
<Switch>
|
|
148
|
-
<Route path="/foo">
|
|
149
|
-
<div id="foo">Hello, world!</div>
|
|
150
|
-
</Route>
|
|
151
|
-
</Switch>
|
|
152
|
-
</div>
|
|
153
|
-
</MemoryRouter>,
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
// Act
|
|
157
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
158
|
-
|
|
159
|
-
// Assert
|
|
160
|
-
await waitFor(() => {
|
|
161
|
-
expect(safeWithNavMock).toHaveBeenCalled();
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
// Unfortunately we can't test the spinner here after upgrading to
|
|
166
|
-
// user-event v14 as the render happens before we're aable to check on the
|
|
167
|
-
// state of the spinner.
|
|
168
|
-
test.skip("show circular spinner before beforeNav resolves", async () => {
|
|
169
|
-
// Arrange
|
|
170
|
-
render(
|
|
171
|
-
<MemoryRouter>
|
|
172
|
-
<div>
|
|
173
|
-
<Button href="/foo" beforeNav={() => Promise.resolve()}>
|
|
174
|
-
Click me!
|
|
175
|
-
</Button>
|
|
176
|
-
<Switch>
|
|
177
|
-
<Route path="/foo">
|
|
178
|
-
<div id="foo">Hello, world!</div>
|
|
179
|
-
</Route>
|
|
180
|
-
</Switch>
|
|
181
|
-
</div>
|
|
182
|
-
</MemoryRouter>,
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
// Act
|
|
186
|
-
const button = await screen.findByRole("button");
|
|
187
|
-
await userEvent.click(button);
|
|
188
|
-
|
|
189
|
-
// Assert
|
|
190
|
-
// TODO(juan): Find a way to use a more accessible query.
|
|
191
|
-
expect(await screen.findByTestId("button-spinner")).toBeInTheDocument();
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
test("safeWithNav with skipClientNav=true waits for promise resolution", async () => {
|
|
195
|
-
// Arrange
|
|
196
|
-
jest.spyOn(window.location, "assign");
|
|
197
|
-
render(
|
|
198
|
-
<MemoryRouter>
|
|
199
|
-
<div>
|
|
200
|
-
<Button
|
|
201
|
-
href="/foo"
|
|
202
|
-
safeWithNav={() => Promise.resolve()}
|
|
203
|
-
skipClientNav={true}
|
|
204
|
-
>
|
|
205
|
-
Click me!
|
|
206
|
-
</Button>
|
|
207
|
-
<Switch>
|
|
208
|
-
<Route path="/foo">
|
|
209
|
-
<div id="foo">Hello, world!</div>
|
|
210
|
-
</Route>
|
|
211
|
-
</Switch>
|
|
212
|
-
</div>
|
|
213
|
-
</MemoryRouter>,
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
// Act
|
|
217
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
218
|
-
|
|
219
|
-
// Assert
|
|
220
|
-
await waitFor(() => {
|
|
221
|
-
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
test("safeWithNav with skipClientNav=true shows spinner", async () => {
|
|
226
|
-
// Arrange
|
|
227
|
-
jest.spyOn(window.location, "assign");
|
|
228
|
-
render(
|
|
229
|
-
<MemoryRouter>
|
|
230
|
-
<div>
|
|
231
|
-
<Button
|
|
232
|
-
href="/foo"
|
|
233
|
-
safeWithNav={() => Promise.resolve()}
|
|
234
|
-
skipClientNav={true}
|
|
235
|
-
>
|
|
236
|
-
Click me!
|
|
237
|
-
</Button>
|
|
238
|
-
<Switch>
|
|
239
|
-
<Route path="/foo">
|
|
240
|
-
<div id="foo">Hello, world!</div>
|
|
241
|
-
</Route>
|
|
242
|
-
</Switch>
|
|
243
|
-
</div>
|
|
244
|
-
</MemoryRouter>,
|
|
245
|
-
);
|
|
246
|
-
|
|
247
|
-
// Act
|
|
248
|
-
const button = await screen.findByRole("button");
|
|
249
|
-
await userEvent.click(button);
|
|
250
|
-
|
|
251
|
-
// Assert
|
|
252
|
-
expect(await screen.findByTestId("button-spinner")).toBeInTheDocument();
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
test("beforeNav resolution and safeWithNav with skipClientNav=true waits for promise resolution", async () => {
|
|
256
|
-
// Arrange
|
|
257
|
-
jest.spyOn(window.location, "assign");
|
|
258
|
-
render(
|
|
259
|
-
<MemoryRouter>
|
|
260
|
-
<div>
|
|
261
|
-
<Button
|
|
262
|
-
href="/foo"
|
|
263
|
-
beforeNav={() => Promise.resolve()}
|
|
264
|
-
safeWithNav={() => Promise.resolve()}
|
|
265
|
-
skipClientNav={true}
|
|
266
|
-
>
|
|
267
|
-
Click me!
|
|
268
|
-
</Button>
|
|
269
|
-
<Switch>
|
|
270
|
-
<Route path="/foo">
|
|
271
|
-
<div id="foo">Hello, world!</div>
|
|
272
|
-
</Route>
|
|
273
|
-
</Switch>
|
|
274
|
-
</div>
|
|
275
|
-
</MemoryRouter>,
|
|
276
|
-
);
|
|
277
|
-
|
|
278
|
-
// Act
|
|
279
|
-
const button = await screen.findByRole("button");
|
|
280
|
-
await userEvent.click(button);
|
|
281
|
-
|
|
282
|
-
// Assert
|
|
283
|
-
await waitFor(() => {
|
|
284
|
-
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
285
|
-
});
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
test("safeWithNav with skipClientNav=true waits for promise rejection", async () => {
|
|
289
|
-
// Arrange
|
|
290
|
-
jest.spyOn(window.location, "assign");
|
|
291
|
-
render(
|
|
292
|
-
<MemoryRouter>
|
|
293
|
-
<div>
|
|
294
|
-
<Button
|
|
295
|
-
href="/foo"
|
|
296
|
-
safeWithNav={() => Promise.reject()}
|
|
297
|
-
skipClientNav={true}
|
|
298
|
-
>
|
|
299
|
-
Click me!
|
|
300
|
-
</Button>
|
|
301
|
-
<Switch>
|
|
302
|
-
<Route path="/foo">
|
|
303
|
-
<div id="foo">Hello, world!</div>
|
|
304
|
-
</Route>
|
|
305
|
-
</Switch>
|
|
306
|
-
</div>
|
|
307
|
-
</MemoryRouter>,
|
|
308
|
-
);
|
|
309
|
-
|
|
310
|
-
// Act
|
|
311
|
-
const button = await screen.findByRole("button");
|
|
312
|
-
await userEvent.click(button);
|
|
313
|
-
|
|
314
|
-
// Assert
|
|
315
|
-
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
test("safeWithNav with skipClientNav=false calls safeWithNav but doesn't wait to navigate", async () => {
|
|
319
|
-
// Arrange
|
|
320
|
-
jest.spyOn(window.location, "assign");
|
|
321
|
-
const safeWithNavMock = jest.fn();
|
|
322
|
-
render(
|
|
323
|
-
<MemoryRouter>
|
|
324
|
-
<div>
|
|
325
|
-
<Button
|
|
326
|
-
href="/foo"
|
|
327
|
-
safeWithNav={safeWithNavMock}
|
|
328
|
-
skipClientNav={false}
|
|
329
|
-
>
|
|
330
|
-
Click me!
|
|
331
|
-
</Button>
|
|
332
|
-
<Switch>
|
|
333
|
-
<Route path="/foo">
|
|
334
|
-
<div id="foo">Hello, world!</div>
|
|
335
|
-
</Route>
|
|
336
|
-
</Switch>
|
|
337
|
-
</div>
|
|
338
|
-
</MemoryRouter>,
|
|
339
|
-
);
|
|
340
|
-
|
|
341
|
-
// Act
|
|
342
|
-
const button = await screen.findByRole("button");
|
|
343
|
-
await userEvent.click(button);
|
|
344
|
-
|
|
345
|
-
// Assert
|
|
346
|
-
expect(safeWithNavMock).toHaveBeenCalled();
|
|
347
|
-
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
test("safeWithNav with beforeNav resolution and skipClientNav=false calls safeWithNav but doesn't wait to navigate", async () => {
|
|
351
|
-
// Arrange
|
|
352
|
-
jest.spyOn(window.location, "assign");
|
|
353
|
-
const safeWithNavMock = jest.fn();
|
|
354
|
-
render(
|
|
355
|
-
<MemoryRouter>
|
|
356
|
-
<div>
|
|
357
|
-
<Button
|
|
358
|
-
href="/foo"
|
|
359
|
-
beforeNav={() => Promise.resolve()}
|
|
360
|
-
safeWithNav={safeWithNavMock}
|
|
361
|
-
skipClientNav={false}
|
|
362
|
-
>
|
|
363
|
-
Click me!
|
|
364
|
-
</Button>
|
|
365
|
-
<Switch>
|
|
366
|
-
<Route path="/foo">
|
|
367
|
-
<div id="foo">Hello, world!</div>
|
|
368
|
-
</Route>
|
|
369
|
-
</Switch>
|
|
370
|
-
</div>
|
|
371
|
-
</MemoryRouter>,
|
|
372
|
-
);
|
|
373
|
-
|
|
374
|
-
// Act
|
|
375
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
376
|
-
|
|
377
|
-
// Assert
|
|
378
|
-
await waitFor(() => {
|
|
379
|
-
expect(safeWithNavMock).toHaveBeenCalled();
|
|
380
|
-
});
|
|
381
|
-
await waitFor(() => {
|
|
382
|
-
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
383
|
-
});
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
test("client-side navigation with unknown URL fails", async () => {
|
|
387
|
-
// Arrange
|
|
388
|
-
render(
|
|
389
|
-
<MemoryRouter>
|
|
390
|
-
<div>
|
|
391
|
-
<Button href="/unknown">Click me!</Button>
|
|
392
|
-
<Switch>
|
|
393
|
-
<Route path="/foo">
|
|
394
|
-
<div id="foo">Hello, world!</div>
|
|
395
|
-
</Route>
|
|
396
|
-
</Switch>
|
|
397
|
-
</div>
|
|
398
|
-
</MemoryRouter>,
|
|
399
|
-
);
|
|
400
|
-
|
|
401
|
-
// Act
|
|
402
|
-
const button = await screen.findByRole("button");
|
|
403
|
-
await userEvent.click(button);
|
|
404
|
-
|
|
405
|
-
// Assert
|
|
406
|
-
expect(screen.queryByText("Hello, world!")).not.toBeInTheDocument();
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
test("client-side navigation with `skipClientNav` set to `true` fails", async () => {
|
|
410
|
-
// Arrange
|
|
411
|
-
render(
|
|
412
|
-
<MemoryRouter>
|
|
413
|
-
<div>
|
|
414
|
-
<Button href="/foo" skipClientNav>
|
|
415
|
-
Click me!
|
|
416
|
-
</Button>
|
|
417
|
-
<Switch>
|
|
418
|
-
<Route path="/foo">
|
|
419
|
-
<div id="foo">Hello, world!</div>
|
|
420
|
-
</Route>
|
|
421
|
-
</Switch>
|
|
422
|
-
</div>
|
|
423
|
-
</MemoryRouter>,
|
|
424
|
-
);
|
|
425
|
-
|
|
426
|
-
// Act
|
|
427
|
-
const button = await screen.findByRole("button");
|
|
428
|
-
await userEvent.click(button);
|
|
429
|
-
|
|
430
|
-
// Assert
|
|
431
|
-
expect(screen.queryByText("Hello, world!")).not.toBeInTheDocument();
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
test("disallow navigation when href and disabled are both set", async () => {
|
|
435
|
-
// Arrange
|
|
436
|
-
render(
|
|
437
|
-
<MemoryRouter>
|
|
438
|
-
<div>
|
|
439
|
-
<Button href="/foo" disabled={true}>
|
|
440
|
-
Click me!
|
|
441
|
-
</Button>
|
|
442
|
-
<Switch>
|
|
443
|
-
<Route path="/foo">
|
|
444
|
-
<div id="foo">Hello, world!</div>
|
|
445
|
-
</Route>
|
|
446
|
-
</Switch>
|
|
447
|
-
</div>
|
|
448
|
-
</MemoryRouter>,
|
|
449
|
-
);
|
|
450
|
-
|
|
451
|
-
// Act
|
|
452
|
-
const button = await screen.findByRole("button");
|
|
453
|
-
await userEvent.click(button);
|
|
454
|
-
|
|
455
|
-
// Assert
|
|
456
|
-
expect(screen.queryByText("Hello, world!")).not.toBeInTheDocument();
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
test("don't call beforeNav when href and disabled are both set", async () => {
|
|
460
|
-
// Arrange
|
|
461
|
-
const beforeNavMock = jest.fn();
|
|
462
|
-
render(
|
|
463
|
-
<MemoryRouter>
|
|
464
|
-
<div>
|
|
465
|
-
<Button
|
|
466
|
-
href="/foo"
|
|
467
|
-
disabled={true}
|
|
468
|
-
beforeNav={beforeNavMock}
|
|
469
|
-
>
|
|
470
|
-
Click me!
|
|
471
|
-
</Button>
|
|
472
|
-
<Switch>
|
|
473
|
-
<Route path="/foo">
|
|
474
|
-
<div id="foo">Hello, world!</div>
|
|
475
|
-
</Route>
|
|
476
|
-
</Switch>
|
|
477
|
-
</div>
|
|
478
|
-
</MemoryRouter>,
|
|
479
|
-
);
|
|
480
|
-
|
|
481
|
-
// Act
|
|
482
|
-
const button = await screen.findByRole("button");
|
|
483
|
-
await userEvent.click(button);
|
|
484
|
-
|
|
485
|
-
// Assert
|
|
486
|
-
expect(beforeNavMock).not.toHaveBeenCalled();
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
test("don't call safeWithNav when href and disabled are both set", async () => {
|
|
490
|
-
// Arrange
|
|
491
|
-
const safeWithNavMock = jest.fn();
|
|
492
|
-
render(
|
|
493
|
-
<MemoryRouter>
|
|
494
|
-
<div>
|
|
495
|
-
<Button
|
|
496
|
-
href="/foo"
|
|
497
|
-
disabled={true}
|
|
498
|
-
safeWithNav={safeWithNavMock}
|
|
499
|
-
>
|
|
500
|
-
Click me!
|
|
501
|
-
</Button>
|
|
502
|
-
<Switch>
|
|
503
|
-
<Route path="/foo">
|
|
504
|
-
<div id="foo">Hello, world!</div>
|
|
505
|
-
</Route>
|
|
506
|
-
</Switch>
|
|
507
|
-
</div>
|
|
508
|
-
</MemoryRouter>,
|
|
509
|
-
);
|
|
510
|
-
|
|
511
|
-
// Act
|
|
512
|
-
const button = await screen.findByRole("button");
|
|
513
|
-
await userEvent.click(button);
|
|
514
|
-
|
|
515
|
-
// Assert
|
|
516
|
-
expect(safeWithNavMock).not.toHaveBeenCalled();
|
|
517
|
-
});
|
|
518
|
-
|
|
519
|
-
it("should set attribute on the underlying button", async () => {
|
|
520
|
-
// Arrange
|
|
521
|
-
|
|
522
|
-
// Act
|
|
523
|
-
render(
|
|
524
|
-
<Button id="foo" onClick={() => {}}>
|
|
525
|
-
Click me!
|
|
526
|
-
</Button>,
|
|
527
|
-
);
|
|
528
|
-
|
|
529
|
-
// Assert
|
|
530
|
-
expect(await screen.findByRole("button")).toHaveAttribute("id", "foo");
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
it("should set attribute on the underlying link", async () => {
|
|
534
|
-
// Arrange
|
|
535
|
-
|
|
536
|
-
// Act
|
|
537
|
-
render(
|
|
538
|
-
<Button id="foo" href="/bar">
|
|
539
|
-
Click me!
|
|
540
|
-
</Button>,
|
|
541
|
-
);
|
|
542
|
-
|
|
543
|
-
// Assert
|
|
544
|
-
expect(await screen.findByRole("button")).toHaveAttribute(
|
|
545
|
-
"href",
|
|
546
|
-
"/bar",
|
|
547
|
-
);
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
describe("client-side navigation with keyboard", () => {
|
|
551
|
-
it("should navigate on pressing the space key", async () => {
|
|
552
|
-
// Arrange
|
|
553
|
-
render(
|
|
554
|
-
<MemoryRouter>
|
|
555
|
-
<div>
|
|
556
|
-
<Button href="/foo">Click me!</Button>
|
|
557
|
-
<Switch>
|
|
558
|
-
<Route path="/foo">
|
|
559
|
-
<div id="foo">Hello, world!</div>
|
|
560
|
-
</Route>
|
|
561
|
-
</Switch>
|
|
562
|
-
</div>
|
|
563
|
-
</MemoryRouter>,
|
|
564
|
-
);
|
|
565
|
-
|
|
566
|
-
// Act
|
|
567
|
-
const button = await screen.findByRole("button");
|
|
568
|
-
await userEvent.type(button, "{space}");
|
|
569
|
-
|
|
570
|
-
// Assert
|
|
571
|
-
expect(
|
|
572
|
-
await screen.findByText("Hello, world!"),
|
|
573
|
-
).toBeInTheDocument();
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
it("should navigate on pressing the enter key", async () => {
|
|
577
|
-
// Arrange
|
|
578
|
-
render(
|
|
579
|
-
<MemoryRouter>
|
|
580
|
-
<div>
|
|
581
|
-
<Button href="/foo">Click me!</Button>
|
|
582
|
-
<Switch>
|
|
583
|
-
<Route path="/foo">
|
|
584
|
-
<div id="foo">Hello, world!</div>
|
|
585
|
-
</Route>
|
|
586
|
-
</Switch>
|
|
587
|
-
</div>
|
|
588
|
-
</MemoryRouter>,
|
|
589
|
-
);
|
|
590
|
-
|
|
591
|
-
// Act
|
|
592
|
-
const button = await screen.findByRole("button");
|
|
593
|
-
await userEvent.type(button, "{enter}");
|
|
594
|
-
|
|
595
|
-
// Assert
|
|
596
|
-
expect(
|
|
597
|
-
await screen.findByText("Hello, world!"),
|
|
598
|
-
).toBeInTheDocument();
|
|
599
|
-
});
|
|
600
|
-
|
|
601
|
-
test("beforeNav rejection blocks client-side navigation ", async () => {
|
|
602
|
-
// Arrange
|
|
603
|
-
render(
|
|
604
|
-
<MemoryRouter>
|
|
605
|
-
<div>
|
|
606
|
-
<Button href="/foo" beforeNav={() => Promise.reject()}>
|
|
607
|
-
Click me!
|
|
608
|
-
</Button>
|
|
609
|
-
<Switch>
|
|
610
|
-
<Route path="/foo">
|
|
611
|
-
<div id="foo">Hello, world!</div>
|
|
612
|
-
</Route>
|
|
613
|
-
</Switch>
|
|
614
|
-
</div>
|
|
615
|
-
</MemoryRouter>,
|
|
616
|
-
);
|
|
617
|
-
|
|
618
|
-
// Act
|
|
619
|
-
const button = await screen.findByRole("button");
|
|
620
|
-
await userEvent.type(button, "{enter}");
|
|
621
|
-
|
|
622
|
-
// Assert
|
|
623
|
-
expect(screen.queryByText("Hello, world!")).not.toBeInTheDocument();
|
|
624
|
-
});
|
|
625
|
-
|
|
626
|
-
test("beforeNav resolution results in client-side navigation", async () => {
|
|
627
|
-
// Arrange
|
|
628
|
-
render(
|
|
629
|
-
<MemoryRouter>
|
|
630
|
-
<div>
|
|
631
|
-
<Button href="/foo" beforeNav={() => Promise.resolve()}>
|
|
632
|
-
Click me!
|
|
633
|
-
</Button>
|
|
634
|
-
<Switch>
|
|
635
|
-
<Route path="/foo">
|
|
636
|
-
<div id="foo">Hello, world!</div>
|
|
637
|
-
</Route>
|
|
638
|
-
</Switch>
|
|
639
|
-
</div>
|
|
640
|
-
</MemoryRouter>,
|
|
641
|
-
);
|
|
642
|
-
|
|
643
|
-
// Act
|
|
644
|
-
const button = await screen.findByRole("button");
|
|
645
|
-
await userEvent.type(button, "{enter}");
|
|
646
|
-
|
|
647
|
-
// Assert
|
|
648
|
-
await waitFor(async () => {
|
|
649
|
-
expect(
|
|
650
|
-
await screen.findByText("Hello, world!"),
|
|
651
|
-
).toBeInTheDocument();
|
|
652
|
-
});
|
|
653
|
-
});
|
|
654
|
-
|
|
655
|
-
test("safeWithNav with skipClientNav=true waits for promise resolution", async () => {
|
|
656
|
-
// Arrange
|
|
657
|
-
jest.spyOn(window.location, "assign");
|
|
658
|
-
render(
|
|
659
|
-
<MemoryRouter>
|
|
660
|
-
<div>
|
|
661
|
-
<Button
|
|
662
|
-
href="/foo"
|
|
663
|
-
safeWithNav={() => Promise.resolve()}
|
|
664
|
-
skipClientNav={true}
|
|
665
|
-
>
|
|
666
|
-
Click me!
|
|
667
|
-
</Button>
|
|
668
|
-
<Switch>
|
|
669
|
-
<Route path="/foo">
|
|
670
|
-
<div id="foo">Hello, world!</div>
|
|
671
|
-
</Route>
|
|
672
|
-
</Switch>
|
|
673
|
-
</div>
|
|
674
|
-
</MemoryRouter>,
|
|
675
|
-
);
|
|
676
|
-
|
|
677
|
-
// Act
|
|
678
|
-
const button = await screen.findByRole("button");
|
|
679
|
-
await userEvent.type(button, "{enter}");
|
|
680
|
-
|
|
681
|
-
// Assert
|
|
682
|
-
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
683
|
-
});
|
|
684
|
-
|
|
685
|
-
test("safeWithNav with skipClientNav=true waits for promise rejection", async () => {
|
|
686
|
-
// Arrange
|
|
687
|
-
jest.spyOn(window.location, "assign");
|
|
688
|
-
render(
|
|
689
|
-
<MemoryRouter>
|
|
690
|
-
<div>
|
|
691
|
-
<Button
|
|
692
|
-
href="/foo"
|
|
693
|
-
safeWithNav={() => Promise.reject()}
|
|
694
|
-
skipClientNav={true}
|
|
695
|
-
>
|
|
696
|
-
Click me!
|
|
697
|
-
</Button>
|
|
698
|
-
<Switch>
|
|
699
|
-
<Route path="/foo">
|
|
700
|
-
<div id="foo">Hello, world!</div>
|
|
701
|
-
</Route>
|
|
702
|
-
</Switch>
|
|
703
|
-
</div>
|
|
704
|
-
</MemoryRouter>,
|
|
705
|
-
);
|
|
706
|
-
|
|
707
|
-
// Act
|
|
708
|
-
const button = await screen.findByRole("button");
|
|
709
|
-
await userEvent.type(button, "{enter}");
|
|
710
|
-
|
|
711
|
-
// Assert
|
|
712
|
-
await waitFor(() => {
|
|
713
|
-
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
714
|
-
});
|
|
715
|
-
});
|
|
716
|
-
|
|
717
|
-
test("safeWithNav with skipClientNav=false calls safeWithNav but doesn't wait to navigate", async () => {
|
|
718
|
-
// Arrange
|
|
719
|
-
jest.spyOn(window.location, "assign");
|
|
720
|
-
const safeWithNavMock = jest.fn();
|
|
721
|
-
render(
|
|
722
|
-
<MemoryRouter>
|
|
723
|
-
<div>
|
|
724
|
-
<Button
|
|
725
|
-
href="/foo"
|
|
726
|
-
safeWithNav={safeWithNavMock}
|
|
727
|
-
skipClientNav={false}
|
|
728
|
-
>
|
|
729
|
-
Click me!
|
|
730
|
-
</Button>
|
|
731
|
-
<Switch>
|
|
732
|
-
<Route path="/foo">
|
|
733
|
-
<div id="foo">Hello, world!</div>
|
|
734
|
-
</Route>
|
|
735
|
-
</Switch>
|
|
736
|
-
</div>
|
|
737
|
-
</MemoryRouter>,
|
|
738
|
-
);
|
|
739
|
-
|
|
740
|
-
// Act
|
|
741
|
-
const button = await screen.findByRole("button");
|
|
742
|
-
await userEvent.type(button, "{enter}");
|
|
743
|
-
|
|
744
|
-
// Assert
|
|
745
|
-
await waitFor(() => {
|
|
746
|
-
expect(safeWithNavMock).toHaveBeenCalled();
|
|
747
|
-
});
|
|
748
|
-
await waitFor(() => {
|
|
749
|
-
expect(window.location.assign).toHaveBeenCalledWith("/foo");
|
|
750
|
-
});
|
|
751
|
-
});
|
|
752
|
-
});
|
|
753
|
-
|
|
754
|
-
describe("button focus", () => {
|
|
755
|
-
test("primary button can have focus", async () => {
|
|
756
|
-
// Arrange
|
|
757
|
-
render(<Button testId={"button-focus-test"}>Label</Button>);
|
|
758
|
-
|
|
759
|
-
// Act
|
|
760
|
-
const button = await screen.findByTestId("button-focus-test");
|
|
761
|
-
button.focus();
|
|
762
|
-
|
|
763
|
-
// Assert
|
|
764
|
-
expect(button).toHaveFocus();
|
|
765
|
-
});
|
|
766
|
-
|
|
767
|
-
test("primary button can have focus when disabled", async () => {
|
|
768
|
-
// Arrange
|
|
769
|
-
render(
|
|
770
|
-
<Button disabled={true} testId={"button-focus-test"}>
|
|
771
|
-
Label
|
|
772
|
-
</Button>,
|
|
773
|
-
);
|
|
774
|
-
|
|
775
|
-
// Act
|
|
776
|
-
const button = await screen.findByTestId("button-focus-test");
|
|
777
|
-
button.focus();
|
|
778
|
-
|
|
779
|
-
// Assert
|
|
780
|
-
expect(button).toHaveFocus();
|
|
781
|
-
});
|
|
782
|
-
|
|
783
|
-
test("tertiary button can have focus when disabled", async () => {
|
|
784
|
-
// Arrange
|
|
785
|
-
render(
|
|
786
|
-
<Button
|
|
787
|
-
disabled={true}
|
|
788
|
-
testId={"button-focus-test"}
|
|
789
|
-
kind="tertiary"
|
|
790
|
-
>
|
|
791
|
-
Label
|
|
792
|
-
</Button>,
|
|
793
|
-
);
|
|
794
|
-
|
|
795
|
-
// Act
|
|
796
|
-
const button = await screen.findByTestId("button-focus-test");
|
|
797
|
-
button.focus();
|
|
798
|
-
|
|
799
|
-
// Assert
|
|
800
|
-
expect(button).toHaveFocus();
|
|
801
|
-
});
|
|
802
|
-
});
|
|
803
|
-
|
|
804
|
-
describe("type='submit'", () => {
|
|
805
|
-
test("submit button within form via click", async () => {
|
|
806
|
-
// Arrange
|
|
807
|
-
const submitFnMock = jest.fn();
|
|
808
|
-
render(
|
|
809
|
-
<form onSubmit={submitFnMock}>
|
|
810
|
-
<Button type="submit">Click me!</Button>
|
|
811
|
-
</form>,
|
|
812
|
-
);
|
|
813
|
-
|
|
814
|
-
// Act
|
|
815
|
-
const button = await screen.findByRole("button");
|
|
816
|
-
await userEvent.click(button);
|
|
817
|
-
|
|
818
|
-
// Assert
|
|
819
|
-
expect(submitFnMock).toHaveBeenCalled();
|
|
820
|
-
});
|
|
821
|
-
|
|
822
|
-
test("submit button within form via keyboard", async () => {
|
|
823
|
-
// Arrange
|
|
824
|
-
const submitFnMock = jest.fn();
|
|
825
|
-
render(
|
|
826
|
-
<form onSubmit={submitFnMock}>
|
|
827
|
-
<Button type="submit">Click me!</Button>
|
|
828
|
-
</form>,
|
|
829
|
-
);
|
|
830
|
-
|
|
831
|
-
// Act
|
|
832
|
-
const button = await screen.findByRole("button");
|
|
833
|
-
await userEvent.type(button, "{enter}");
|
|
834
|
-
|
|
835
|
-
// Assert
|
|
836
|
-
expect(submitFnMock).toHaveBeenCalled();
|
|
837
|
-
});
|
|
838
|
-
|
|
839
|
-
test("submit button doesn't break if it's not in a form", async () => {
|
|
840
|
-
// Arrange
|
|
841
|
-
render(<Button type="submit">Click me!</Button>);
|
|
842
|
-
|
|
843
|
-
// Act
|
|
844
|
-
expect(async () => {
|
|
845
|
-
// Assert
|
|
846
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
847
|
-
}).not.toThrow();
|
|
848
|
-
});
|
|
849
|
-
});
|
|
850
|
-
});
|