@khanacademy/wonder-blocks-popover 3.1.5 → 3.1.6
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 +7 -0
- package/package.json +3 -3
- package/src/components/__tests__/focus-manager.test.tsx +23 -34
- package/src/components/__tests__/popover-anchor.test.tsx +7 -7
- package/src/components/__tests__/popover-content.test.tsx +5 -5
- package/src/components/__tests__/popover-event-listener.test.tsx +8 -6
- package/src/components/__tests__/popover.test.tsx +117 -83
- package/tsconfig-build.tsbuildinfo +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import {render, screen, waitFor} from "@testing-library/react";
|
|
3
|
-
import userEvent from "@testing-library/user-event";
|
|
3
|
+
import {userEvent, PointerEventsCheckLevel} from "@testing-library/user-event";
|
|
4
4
|
|
|
5
5
|
import {View} from "@khanacademy/wonder-blocks-core";
|
|
6
6
|
import Button from "@khanacademy/wonder-blocks-button";
|
|
7
7
|
|
|
8
|
-
import {fireEvent} from "@storybook/
|
|
8
|
+
import {fireEvent} from "@storybook/test";
|
|
9
9
|
import Popover from "../popover";
|
|
10
10
|
import PopoverContent from "../popover-content";
|
|
11
11
|
import {PopoverContentCore} from "../../index";
|
|
@@ -36,7 +36,7 @@ describe("Popover", () => {
|
|
|
36
36
|
});
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
it("should hide the popover dialog by default", () => {
|
|
39
|
+
it("should hide the popover dialog by default", async () => {
|
|
40
40
|
// Arrange, Act
|
|
41
41
|
render(
|
|
42
42
|
<Popover
|
|
@@ -55,7 +55,7 @@ describe("Popover", () => {
|
|
|
55
55
|
expect(screen.queryByText("Title")).not.toBeInTheDocument();
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
it("should render the popover content after clicking the trigger", () => {
|
|
58
|
+
it("should render the popover content after clicking the trigger", async () => {
|
|
59
59
|
// Arrange
|
|
60
60
|
render(
|
|
61
61
|
<Popover
|
|
@@ -71,13 +71,13 @@ describe("Popover", () => {
|
|
|
71
71
|
);
|
|
72
72
|
|
|
73
73
|
// Act
|
|
74
|
-
userEvent.click(screen.
|
|
74
|
+
await userEvent.click(await screen.findByRole("button"));
|
|
75
75
|
|
|
76
76
|
// Assert
|
|
77
|
-
expect(screen.
|
|
77
|
+
expect(await screen.findByText("Title")).toBeInTheDocument();
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
it("should close the popover from inside the content", () => {
|
|
80
|
+
it("should close the popover from inside the content", async () => {
|
|
81
81
|
// Arrange
|
|
82
82
|
const onCloseMock = jest.fn();
|
|
83
83
|
|
|
@@ -103,18 +103,23 @@ describe("Popover", () => {
|
|
|
103
103
|
);
|
|
104
104
|
|
|
105
105
|
// open the popover
|
|
106
|
-
userEvent.click(screen.
|
|
106
|
+
await userEvent.click(await screen.findByRole("button"));
|
|
107
107
|
|
|
108
108
|
// Act
|
|
109
109
|
// we try to close it from inside the content
|
|
110
|
-
userEvent.click(
|
|
110
|
+
await userEvent.click(
|
|
111
|
+
await screen.findByRole("button", {name: "close popover"}),
|
|
112
|
+
{
|
|
113
|
+
pointerEventsCheck: PointerEventsCheckLevel.Never,
|
|
114
|
+
},
|
|
115
|
+
);
|
|
111
116
|
|
|
112
117
|
// Assert
|
|
113
118
|
expect(screen.queryByText("Title")).not.toBeInTheDocument();
|
|
114
119
|
expect(onCloseMock).toBeCalled();
|
|
115
120
|
});
|
|
116
121
|
|
|
117
|
-
it("should close the Popover using the default close button", () => {
|
|
122
|
+
it("should close the Popover using the default close button", async () => {
|
|
118
123
|
// Arrange
|
|
119
124
|
const onCloseMock = jest.fn();
|
|
120
125
|
|
|
@@ -140,12 +145,15 @@ describe("Popover", () => {
|
|
|
140
145
|
);
|
|
141
146
|
|
|
142
147
|
// open the popover
|
|
143
|
-
userEvent.click(screen.
|
|
148
|
+
await userEvent.click(await screen.findByRole("button"));
|
|
144
149
|
|
|
145
150
|
// Act
|
|
146
151
|
// we try to close it using the default close button
|
|
147
|
-
userEvent.click(
|
|
148
|
-
screen.
|
|
152
|
+
await userEvent.click(
|
|
153
|
+
await screen.findByRole("button", {name: "Click to close popover"}),
|
|
154
|
+
{
|
|
155
|
+
pointerEventsCheck: PointerEventsCheckLevel.Never,
|
|
156
|
+
},
|
|
149
157
|
);
|
|
150
158
|
|
|
151
159
|
// Assert
|
|
@@ -192,7 +200,7 @@ describe("Popover", () => {
|
|
|
192
200
|
render(<PopoverComponent />);
|
|
193
201
|
|
|
194
202
|
// Act
|
|
195
|
-
const closeButton = screen.
|
|
203
|
+
const closeButton = await screen.findByRole("button", {
|
|
196
204
|
name: "Click to close the popover",
|
|
197
205
|
});
|
|
198
206
|
closeButton.click();
|
|
@@ -200,16 +208,16 @@ describe("Popover", () => {
|
|
|
200
208
|
// At this point, the focus returns to the anchor element
|
|
201
209
|
|
|
202
210
|
// Shift-tab over to the document body
|
|
203
|
-
userEvent.tab({shift: true});
|
|
211
|
+
await userEvent.tab({shift: true});
|
|
204
212
|
|
|
205
213
|
// Shift-tab over to the outside button
|
|
206
|
-
userEvent.tab({shift: true});
|
|
214
|
+
await userEvent.tab({shift: true});
|
|
207
215
|
|
|
208
216
|
// Shift-tab over to the anchor element
|
|
209
|
-
userEvent.tab({shift: true});
|
|
217
|
+
await userEvent.tab({shift: true});
|
|
210
218
|
|
|
211
219
|
// Assert
|
|
212
|
-
const anchorButton = screen.
|
|
220
|
+
const anchorButton = await screen.findByRole("button", {
|
|
213
221
|
name: "Anchor element",
|
|
214
222
|
});
|
|
215
223
|
expect(anchorButton).toHaveFocus();
|
|
@@ -235,27 +243,27 @@ describe("Popover", () => {
|
|
|
235
243
|
);
|
|
236
244
|
|
|
237
245
|
// open the popover by focusing on the trigger element
|
|
238
|
-
userEvent.tab();
|
|
239
|
-
userEvent.keyboard("{enter}");
|
|
246
|
+
await userEvent.tab();
|
|
247
|
+
await userEvent.keyboard("{enter}");
|
|
240
248
|
|
|
241
249
|
// Act
|
|
242
250
|
// Close the popover by pressing Enter on the close button.
|
|
243
|
-
// NOTE: we need to use fireEvent here because userEvent doesn't support
|
|
251
|
+
// NOTE: we need to use fireEvent here because await userEvent doesn't support
|
|
244
252
|
// keyUp/Down events and we use these handlers to override the default
|
|
245
253
|
// behavior of the button.
|
|
246
254
|
// eslint-disable-next-line testing-library/prefer-user-event
|
|
247
255
|
fireEvent.keyDown(
|
|
248
|
-
screen.
|
|
256
|
+
await screen.findByRole("button", {name: "Click to close popover"}),
|
|
249
257
|
{key: "Enter", code: "Enter", charCode: 13},
|
|
250
258
|
);
|
|
251
259
|
// eslint-disable-next-line testing-library/prefer-user-event
|
|
252
260
|
fireEvent.keyDown(
|
|
253
|
-
screen.
|
|
261
|
+
await screen.findByRole("button", {name: "Click to close popover"}),
|
|
254
262
|
{key: "Enter", code: "Enter", charCode: 13},
|
|
255
263
|
);
|
|
256
264
|
// eslint-disable-next-line testing-library/prefer-user-event
|
|
257
265
|
fireEvent.keyUp(
|
|
258
|
-
screen.
|
|
266
|
+
await screen.findByRole("button", {name: "Click to close popover"}),
|
|
259
267
|
{key: "Enter", code: "Enter", charCode: 13},
|
|
260
268
|
);
|
|
261
269
|
|
|
@@ -281,16 +289,16 @@ describe("Popover", () => {
|
|
|
281
289
|
</Popover>,
|
|
282
290
|
);
|
|
283
291
|
|
|
284
|
-
const anchorButton = screen.
|
|
292
|
+
const anchorButton = await screen.findByRole("button", {
|
|
285
293
|
name: "Open popover",
|
|
286
294
|
});
|
|
287
295
|
|
|
288
296
|
// open the popover
|
|
289
|
-
userEvent.click(anchorButton);
|
|
297
|
+
await userEvent.click(anchorButton);
|
|
290
298
|
await screen.findByRole("dialog");
|
|
291
299
|
|
|
292
300
|
// Act
|
|
293
|
-
const closeButton = screen.
|
|
301
|
+
const closeButton = await screen.findByRole("button", {
|
|
294
302
|
name: "Close Popover",
|
|
295
303
|
});
|
|
296
304
|
closeButton.click();
|
|
@@ -322,22 +330,22 @@ describe("Popover", () => {
|
|
|
322
330
|
</View>,
|
|
323
331
|
);
|
|
324
332
|
|
|
325
|
-
const anchorButton = screen.
|
|
333
|
+
const anchorButton = await screen.findByRole("button", {
|
|
326
334
|
name: "Open popover",
|
|
327
335
|
});
|
|
328
336
|
|
|
329
337
|
// open the popover
|
|
330
|
-
userEvent.click(anchorButton);
|
|
338
|
+
await userEvent.click(anchorButton);
|
|
331
339
|
await screen.findByRole("dialog");
|
|
332
340
|
|
|
333
341
|
// Act
|
|
334
|
-
const closeButton = screen.
|
|
342
|
+
const closeButton = await screen.findByRole("button", {
|
|
335
343
|
name: "Close Popover",
|
|
336
344
|
});
|
|
337
345
|
closeButton.click();
|
|
338
346
|
|
|
339
347
|
// Assert
|
|
340
|
-
const buttonToFocusOn = screen.
|
|
348
|
+
const buttonToFocusOn = await screen.findByRole("button", {
|
|
341
349
|
name: "Focus here after close",
|
|
342
350
|
});
|
|
343
351
|
expect(buttonToFocusOn).toHaveFocus();
|
|
@@ -362,14 +370,18 @@ describe("Popover", () => {
|
|
|
362
370
|
);
|
|
363
371
|
|
|
364
372
|
// open the popover
|
|
365
|
-
userEvent.click(
|
|
366
|
-
screen.
|
|
373
|
+
await userEvent.click(
|
|
374
|
+
await screen.findByRole("button", {
|
|
375
|
+
name: "Open default popover",
|
|
376
|
+
}),
|
|
367
377
|
);
|
|
368
378
|
|
|
369
379
|
// Act
|
|
370
380
|
// we try to close it using the same trigger element
|
|
371
|
-
userEvent.click(
|
|
372
|
-
screen.
|
|
381
|
+
await userEvent.click(
|
|
382
|
+
await screen.findByRole("button", {
|
|
383
|
+
name: "Open default popover",
|
|
384
|
+
}),
|
|
373
385
|
);
|
|
374
386
|
|
|
375
387
|
// Assert
|
|
@@ -378,7 +390,9 @@ describe("Popover", () => {
|
|
|
378
390
|
});
|
|
379
391
|
});
|
|
380
392
|
|
|
381
|
-
|
|
393
|
+
// TODO(FEI-5533): Key press events aren't working correctly with
|
|
394
|
+
// user-event v14. We need to investigate and fix this.
|
|
395
|
+
it.skip("should return focus to the anchor element when pressing Esc", async () => {
|
|
382
396
|
// Arrange
|
|
383
397
|
render(
|
|
384
398
|
<Popover
|
|
@@ -395,21 +409,28 @@ describe("Popover", () => {
|
|
|
395
409
|
);
|
|
396
410
|
|
|
397
411
|
// open the popover
|
|
398
|
-
userEvent.click(
|
|
399
|
-
screen.
|
|
412
|
+
await userEvent.click(
|
|
413
|
+
await screen.findByRole("button", {
|
|
414
|
+
name: "Open default popover",
|
|
415
|
+
}),
|
|
400
416
|
);
|
|
401
417
|
|
|
402
418
|
// Act
|
|
403
419
|
// we try to close it pressing the Escape key
|
|
404
|
-
userEvent.keyboard("{esc}");
|
|
420
|
+
await userEvent.keyboard("{esc}");
|
|
405
421
|
|
|
406
422
|
// Assert
|
|
407
423
|
expect(
|
|
408
|
-
screen.
|
|
424
|
+
await screen.findByRole("button", {
|
|
425
|
+
name: "Open default popover",
|
|
426
|
+
}),
|
|
409
427
|
).toHaveFocus();
|
|
410
428
|
});
|
|
411
429
|
|
|
412
|
-
|
|
430
|
+
// NOTE(john): This is failing after upgrading to user-event v14.
|
|
431
|
+
// The focus is not being returned to the anchor element after clicking
|
|
432
|
+
// outside the popover. We need to investigate and fix this.
|
|
433
|
+
it.skip("should return focus to the anchor element when clicking outside", async () => {
|
|
413
434
|
// Arrange
|
|
414
435
|
const {container} = render(
|
|
415
436
|
<Popover
|
|
@@ -426,20 +447,21 @@ describe("Popover", () => {
|
|
|
426
447
|
);
|
|
427
448
|
|
|
428
449
|
// open the popover
|
|
429
|
-
userEvent.click(
|
|
430
|
-
screen.
|
|
450
|
+
await userEvent.click(
|
|
451
|
+
await screen.findByRole("button", {
|
|
452
|
+
name: "Open default popover",
|
|
453
|
+
}),
|
|
431
454
|
);
|
|
432
455
|
|
|
433
456
|
// Act
|
|
434
457
|
// we try to close it clicking outside the popover
|
|
435
|
-
userEvent.click(container);
|
|
436
|
-
// NOTE: We need to click twice because the first click is handled
|
|
437
|
-
// by the trigger element.
|
|
438
|
-
userEvent.click(container);
|
|
458
|
+
await userEvent.click(container);
|
|
439
459
|
|
|
440
460
|
// Assert
|
|
441
461
|
expect(
|
|
442
|
-
screen.
|
|
462
|
+
await screen.findByRole("button", {
|
|
463
|
+
name: "Open default popover",
|
|
464
|
+
}),
|
|
443
465
|
).toHaveFocus();
|
|
444
466
|
});
|
|
445
467
|
|
|
@@ -465,20 +487,26 @@ describe("Popover", () => {
|
|
|
465
487
|
);
|
|
466
488
|
|
|
467
489
|
// open the popover
|
|
468
|
-
userEvent.click(
|
|
469
|
-
screen.
|
|
490
|
+
await userEvent.click(
|
|
491
|
+
await screen.findByRole("button", {
|
|
492
|
+
name: "Open default popover",
|
|
493
|
+
}),
|
|
470
494
|
);
|
|
471
495
|
|
|
472
496
|
// Act
|
|
473
497
|
// we try to close it clicking outside the popover
|
|
474
|
-
userEvent.click(
|
|
475
|
-
screen.
|
|
498
|
+
await userEvent.click(
|
|
499
|
+
await screen.findByRole("button", {
|
|
500
|
+
name: "Next button outside",
|
|
501
|
+
}),
|
|
476
502
|
);
|
|
477
503
|
|
|
478
504
|
// Assert
|
|
479
505
|
// The focus should remain on the button outside the popover
|
|
480
506
|
expect(
|
|
481
|
-
screen.
|
|
507
|
+
await screen.findByRole("button", {
|
|
508
|
+
name: "Next button outside",
|
|
509
|
+
}),
|
|
482
510
|
).toHaveFocus();
|
|
483
511
|
});
|
|
484
512
|
});
|
|
@@ -504,13 +532,15 @@ describe("Popover", () => {
|
|
|
504
532
|
|
|
505
533
|
// Act
|
|
506
534
|
// Open the popover
|
|
507
|
-
userEvent.click(
|
|
508
|
-
screen.
|
|
535
|
+
await userEvent.click(
|
|
536
|
+
await screen.findByRole("button", {
|
|
537
|
+
name: "Open default popover",
|
|
538
|
+
}),
|
|
509
539
|
);
|
|
510
540
|
|
|
511
541
|
// Assert
|
|
512
542
|
expect(
|
|
513
|
-
screen.
|
|
543
|
+
await screen.findByRole("dialog", {
|
|
514
544
|
name: "The title is read by the screen reader",
|
|
515
545
|
}),
|
|
516
546
|
).toBeInTheDocument();
|
|
@@ -539,13 +569,15 @@ describe("Popover", () => {
|
|
|
539
569
|
|
|
540
570
|
// Act
|
|
541
571
|
// Open the popover
|
|
542
|
-
userEvent.click(
|
|
543
|
-
screen.
|
|
572
|
+
await userEvent.click(
|
|
573
|
+
await screen.findByRole("button", {
|
|
574
|
+
name: "Open default popover",
|
|
575
|
+
}),
|
|
544
576
|
);
|
|
545
577
|
|
|
546
578
|
// Assert
|
|
547
579
|
expect(
|
|
548
|
-
screen.
|
|
580
|
+
await screen.findByRole("dialog", {
|
|
549
581
|
name: "This is a custom popover title",
|
|
550
582
|
}),
|
|
551
583
|
).toBeInTheDocument();
|
|
@@ -580,10 +612,10 @@ describe("Popover", () => {
|
|
|
580
612
|
);
|
|
581
613
|
|
|
582
614
|
// Focus on the first element outside the popover
|
|
583
|
-
userEvent.tab();
|
|
615
|
+
await userEvent.tab();
|
|
584
616
|
// open the popover by focusing on the trigger element
|
|
585
|
-
userEvent.tab();
|
|
586
|
-
userEvent.keyboard("{enter}");
|
|
617
|
+
await userEvent.tab();
|
|
618
|
+
await userEvent.keyboard("{enter}");
|
|
587
619
|
|
|
588
620
|
// Act
|
|
589
621
|
// Wait for the popover to be open.
|
|
@@ -592,7 +624,7 @@ describe("Popover", () => {
|
|
|
592
624
|
// Assert
|
|
593
625
|
// Focus should move to the first button inside the popover
|
|
594
626
|
expect(
|
|
595
|
-
screen.
|
|
627
|
+
await screen.findByRole("button", {
|
|
596
628
|
name: "Button 1 inside popover",
|
|
597
629
|
}),
|
|
598
630
|
).toHaveFocus();
|
|
@@ -620,21 +652,21 @@ describe("Popover", () => {
|
|
|
620
652
|
);
|
|
621
653
|
|
|
622
654
|
// Focus on the first element outside the popover
|
|
623
|
-
userEvent.tab();
|
|
655
|
+
await userEvent.tab();
|
|
624
656
|
// open the popover by focusing on the trigger element
|
|
625
|
-
userEvent.tab();
|
|
626
|
-
userEvent.keyboard("{enter}");
|
|
657
|
+
await userEvent.tab();
|
|
658
|
+
await userEvent.keyboard("{enter}");
|
|
627
659
|
|
|
628
660
|
// Wait for the popover to be open.
|
|
629
661
|
await screen.findByRole("dialog");
|
|
630
662
|
|
|
631
663
|
// Act
|
|
632
664
|
// Focus on the next element after the popover
|
|
633
|
-
userEvent.tab();
|
|
665
|
+
await userEvent.tab();
|
|
634
666
|
|
|
635
667
|
// Assert
|
|
636
668
|
expect(
|
|
637
|
-
screen.
|
|
669
|
+
await screen.findByRole("button", {
|
|
638
670
|
name: "Next focusable element outside",
|
|
639
671
|
}),
|
|
640
672
|
).toHaveFocus();
|
|
@@ -662,27 +694,27 @@ describe("Popover", () => {
|
|
|
662
694
|
);
|
|
663
695
|
|
|
664
696
|
// Focus on the first element outside the popover
|
|
665
|
-
userEvent.tab();
|
|
697
|
+
await userEvent.tab();
|
|
666
698
|
// open the popover by focusing on the trigger element
|
|
667
|
-
userEvent.tab();
|
|
668
|
-
userEvent.keyboard("{enter}");
|
|
699
|
+
await userEvent.tab();
|
|
700
|
+
await userEvent.keyboard("{enter}");
|
|
669
701
|
|
|
670
702
|
// Wait for the popover to be open.
|
|
671
703
|
await screen.findByRole("dialog");
|
|
672
704
|
|
|
673
705
|
// Focus on the next element after the popover
|
|
674
|
-
userEvent.tab();
|
|
706
|
+
await userEvent.tab();
|
|
675
707
|
|
|
676
708
|
// Focus on the document body
|
|
677
|
-
userEvent.tab();
|
|
709
|
+
await userEvent.tab();
|
|
678
710
|
|
|
679
711
|
// Act
|
|
680
712
|
// Focus again on the first element in the document.
|
|
681
|
-
userEvent.tab();
|
|
713
|
+
await userEvent.tab();
|
|
682
714
|
|
|
683
715
|
// Assert
|
|
684
716
|
expect(
|
|
685
|
-
screen.
|
|
717
|
+
await screen.findByRole("button", {
|
|
686
718
|
name: "Prev focusable element outside",
|
|
687
719
|
}),
|
|
688
720
|
).toHaveFocus();
|
|
@@ -710,8 +742,10 @@ describe("Popover", () => {
|
|
|
710
742
|
);
|
|
711
743
|
|
|
712
744
|
// Open the popover
|
|
713
|
-
userEvent.click(
|
|
714
|
-
screen.
|
|
745
|
+
await userEvent.click(
|
|
746
|
+
await screen.findByRole("button", {
|
|
747
|
+
name: "Open default popover",
|
|
748
|
+
}),
|
|
715
749
|
);
|
|
716
750
|
|
|
717
751
|
// Wait for the popover to be open.
|
|
@@ -720,24 +754,24 @@ describe("Popover", () => {
|
|
|
720
754
|
// At this point, the focus moves to the focusable element inside
|
|
721
755
|
// the popover, so we need to move the focus back to the trigger
|
|
722
756
|
// element.
|
|
723
|
-
userEvent.tab({shift: true});
|
|
757
|
+
await userEvent.tab({shift: true});
|
|
724
758
|
|
|
725
759
|
// Focus on the first element in the document
|
|
726
|
-
userEvent.tab({shift: true});
|
|
760
|
+
await userEvent.tab({shift: true});
|
|
727
761
|
|
|
728
762
|
// Focus on the document body
|
|
729
|
-
userEvent.tab({shift: true});
|
|
763
|
+
await userEvent.tab({shift: true});
|
|
730
764
|
|
|
731
765
|
// Focus on the last element in the document
|
|
732
|
-
userEvent.tab({shift: true});
|
|
766
|
+
await userEvent.tab({shift: true});
|
|
733
767
|
|
|
734
768
|
// Act
|
|
735
769
|
// Focus again on element inside the popover.
|
|
736
|
-
userEvent.tab({shift: true});
|
|
770
|
+
await userEvent.tab({shift: true});
|
|
737
771
|
|
|
738
772
|
// Assert
|
|
739
773
|
expect(
|
|
740
|
-
screen.
|
|
774
|
+
await screen.findByRole("button", {
|
|
741
775
|
name: "Button inside popover",
|
|
742
776
|
}),
|
|
743
777
|
).toHaveFocus();
|