@khanacademy/wonder-blocks-popover 3.2.14 → 3.2.16

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.
@@ -1,932 +0,0 @@
1
- import * as React from "react";
2
- import {render, screen, waitFor} from "@testing-library/react";
3
- import {userEvent, PointerEventsCheckLevel} from "@testing-library/user-event";
4
-
5
- import {View} from "@khanacademy/wonder-blocks-core";
6
- import Button from "@khanacademy/wonder-blocks-button";
7
-
8
- import {fireEvent} from "@storybook/test";
9
- import Popover from "../popover";
10
- import PopoverContent from "../popover-content";
11
- import {PopoverContentCore} from "../../index";
12
-
13
- describe("Popover", () => {
14
- it("should set the anchor as the popover ref", async () => {
15
- // Arrange
16
- const ref: React.RefObject<HTMLButtonElement> = React.createRef();
17
-
18
- render(
19
- <Popover
20
- placement="top"
21
- content={<PopoverContent title="Title" content="content" />}
22
- >
23
- {({open}: any) => (
24
- <button data-anchor onClick={open} ref={ref}>
25
- Open default popover
26
- </button>
27
- )}
28
- </Popover>,
29
- );
30
-
31
- // Act
32
-
33
- // Assert
34
- await waitFor(() => {
35
- expect(ref.current).toBeInstanceOf(HTMLButtonElement);
36
- });
37
- });
38
-
39
- it("should hide the popover dialog by default", async () => {
40
- // Arrange, Act
41
- render(
42
- <Popover
43
- placement="top"
44
- content={<PopoverContent title="Title" content="content" />}
45
- >
46
- {({open}: any) => (
47
- <button data-anchor onClick={open}>
48
- Open default popover
49
- </button>
50
- )}
51
- </Popover>,
52
- );
53
-
54
- // Assert
55
- expect(screen.queryByText("Title")).not.toBeInTheDocument();
56
- });
57
-
58
- it("should render the popover content after clicking the trigger", async () => {
59
- // Arrange
60
- render(
61
- <Popover
62
- placement="top"
63
- content={<PopoverContent title="Title" content="content" />}
64
- >
65
- {({open}: any) => (
66
- <button data-anchor onClick={open}>
67
- Open default popover
68
- </button>
69
- )}
70
- </Popover>,
71
- );
72
-
73
- // Act
74
- await userEvent.click(await screen.findByRole("button"));
75
-
76
- // Assert
77
- expect(await screen.findByText("Title")).toBeInTheDocument();
78
- });
79
-
80
- it("should close the popover from inside the content", async () => {
81
- // Arrange
82
- const onCloseMock = jest.fn();
83
-
84
- render(
85
- <Popover
86
- placement="top"
87
- onClose={onCloseMock}
88
- content={({close}: any) => (
89
- <PopoverContentCore>
90
- <span>custom popover</span>
91
- <button data-close-button onClick={close}>
92
- close popover
93
- </button>
94
- </PopoverContentCore>
95
- )}
96
- >
97
- {({open}: any) => (
98
- <button data-anchor onClick={open}>
99
- Open default popover
100
- </button>
101
- )}
102
- </Popover>,
103
- );
104
-
105
- // open the popover
106
- await userEvent.click(await screen.findByRole("button"));
107
-
108
- // Act
109
- // we try to close it from inside the content
110
- await userEvent.click(
111
- await screen.findByRole("button", {name: "close popover"}),
112
- {
113
- pointerEventsCheck: PointerEventsCheckLevel.Never,
114
- },
115
- );
116
-
117
- // Assert
118
- expect(screen.queryByText("Title")).not.toBeInTheDocument();
119
- expect(onCloseMock).toBeCalled();
120
- });
121
-
122
- it("should close the Popover using the default close button", async () => {
123
- // Arrange
124
- const onCloseMock = jest.fn();
125
-
126
- render(
127
- <Popover
128
- placement="top"
129
- onClose={onCloseMock}
130
- content={
131
- <PopoverContent
132
- title="Title"
133
- content="content"
134
- closeButtonVisible={true}
135
- closeButtonLabel="Click to close popover"
136
- />
137
- }
138
- >
139
- {({open}: any) => (
140
- <button data-anchor onClick={open}>
141
- Open default popover
142
- </button>
143
- )}
144
- </Popover>,
145
- );
146
-
147
- // open the popover
148
- await userEvent.click(await screen.findByRole("button"));
149
-
150
- // Act
151
- // we try to close it using the default close button
152
- await userEvent.click(
153
- await screen.findByRole("button", {name: "Click to close popover"}),
154
- {
155
- pointerEventsCheck: PointerEventsCheckLevel.Never,
156
- },
157
- );
158
-
159
- // Assert
160
- expect(screen.queryByText("Title")).not.toBeInTheDocument();
161
- expect(onCloseMock).toBeCalled();
162
- });
163
-
164
- it("should shift-tab back to the anchor after popover is closed", async () => {
165
- // Arrange
166
- const PopoverComponent = () => {
167
- const [opened, setOpened] = React.useState(true);
168
- return (
169
- <View>
170
- <Popover
171
- opened={opened}
172
- onClose={() => {
173
- setOpened(false);
174
- }}
175
- content={({close}) => (
176
- <PopoverContent
177
- title="Controlled popover"
178
- content="This popover is controlled programatically."
179
- actions={
180
- <Button
181
- onClick={() => {
182
- close();
183
- }}
184
- >
185
- Click to close the popover
186
- </Button>
187
- }
188
- />
189
- )}
190
- >
191
- <Button>Anchor element</Button>
192
- </Popover>
193
- <Button onClick={() => setOpened(true)}>
194
- Outside button (click here to re-open the popover)
195
- </Button>
196
- </View>
197
- );
198
- };
199
-
200
- render(<PopoverComponent />);
201
-
202
- // Act
203
- const closeButton = await screen.findByRole("button", {
204
- name: "Click to close the popover",
205
- });
206
- closeButton.click();
207
-
208
- // At this point, the focus returns to the anchor element
209
-
210
- // Shift-tab over to the document body
211
- await userEvent.tab({shift: true});
212
-
213
- // Shift-tab over to the outside button
214
- await userEvent.tab({shift: true});
215
-
216
- // Shift-tab over to the anchor element
217
- await userEvent.tab({shift: true});
218
-
219
- // Assert
220
- const anchorButton = await screen.findByRole("button", {
221
- name: "Anchor element",
222
- });
223
- expect(anchorButton).toHaveFocus();
224
- });
225
-
226
- it("should close the popover when pressing Enter on the close button", async () => {
227
- // Arrange
228
- render(
229
- <Popover
230
- placement="top"
231
- onClose={jest.fn()}
232
- content={
233
- <PopoverContent
234
- title="Title"
235
- content="content"
236
- closeButtonVisible={true}
237
- closeButtonLabel="Click to close popover"
238
- />
239
- }
240
- >
241
- <Button onClick={jest.fn()}>Open default popover</Button>
242
- </Popover>,
243
- );
244
-
245
- // open the popover by focusing on the trigger element
246
- await userEvent.tab();
247
- await userEvent.keyboard("{enter}");
248
-
249
- // Act
250
- // Close the popover by pressing Enter on the close button.
251
- // NOTE: we need to use fireEvent here because await userEvent doesn't support
252
- // keyUp/Down events and we use these handlers to override the default
253
- // behavior of the button.
254
- // eslint-disable-next-line testing-library/prefer-user-event
255
- fireEvent.keyDown(
256
- await screen.findByRole("button", {name: "Click to close popover"}),
257
- {key: "Enter", code: "Enter", charCode: 13},
258
- );
259
- // eslint-disable-next-line testing-library/prefer-user-event
260
- fireEvent.keyDown(
261
- await screen.findByRole("button", {name: "Click to close popover"}),
262
- {key: "Enter", code: "Enter", charCode: 13},
263
- );
264
- // eslint-disable-next-line testing-library/prefer-user-event
265
- fireEvent.keyUp(
266
- await screen.findByRole("button", {name: "Click to close popover"}),
267
- {key: "Enter", code: "Enter", charCode: 13},
268
- );
269
-
270
- // Assert
271
- expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
272
- });
273
-
274
- describe("return focus", () => {
275
- it("should return focus to the trigger element by default", async () => {
276
- // Arrange
277
- render(
278
- <Popover
279
- dismissEnabled={true}
280
- content={
281
- <PopoverContent
282
- closeButtonVisible={true}
283
- title="Returning focus to a specific element"
284
- content='After dismissing the popover, the focus will be set on the button labeled "Focus here after close."'
285
- />
286
- }
287
- >
288
- <Button>Open popover</Button>
289
- </Popover>,
290
- );
291
-
292
- const anchorButton = await screen.findByRole("button", {
293
- name: "Open popover",
294
- });
295
-
296
- // open the popover
297
- await userEvent.click(anchorButton);
298
- await screen.findByRole("dialog");
299
-
300
- // Act
301
- const closeButton = await screen.findByRole("button", {
302
- name: "Close Popover",
303
- });
304
- closeButton.click();
305
-
306
- // Assert
307
- expect(anchorButton).toHaveFocus();
308
- });
309
-
310
- it("should return focus to a specific element if closedFocusId is set", async () => {
311
- // Arrange
312
- render(
313
- <View>
314
- <Button id="button-to-focus-on">
315
- Focus here after close
316
- </Button>
317
- <Popover
318
- closedFocusId="button-to-focus-on"
319
- dismissEnabled={true}
320
- content={
321
- <PopoverContent
322
- closeButtonVisible={true}
323
- title="Returning focus to a specific element"
324
- content='After dismissing the popover, the focus will be set on the button labeled "Focus here after close."'
325
- />
326
- }
327
- >
328
- <Button>Open popover</Button>
329
- </Popover>
330
- </View>,
331
- );
332
-
333
- const anchorButton = await screen.findByRole("button", {
334
- name: "Open popover",
335
- });
336
-
337
- // open the popover
338
- await userEvent.click(anchorButton);
339
- await screen.findByRole("dialog");
340
-
341
- // Act
342
- const closeButton = await screen.findByRole("button", {
343
- name: "Close Popover",
344
- });
345
- closeButton.click();
346
-
347
- // Assert
348
- const buttonToFocusOn = await screen.findByRole("button", {
349
- name: "Focus here after close",
350
- });
351
- expect(buttonToFocusOn).toHaveFocus();
352
- });
353
- });
354
-
355
- describe("dismissEnabled", () => {
356
- it("should close the Popover if dismissEnabled is set", async () => {
357
- // Arrange
358
- render(
359
- <Popover
360
- dismissEnabled={true}
361
- placement="top"
362
- content={<PopoverContent title="Title" content="content" />}
363
- >
364
- {({open}: any) => (
365
- <button data-anchor onClick={open}>
366
- Open default popover
367
- </button>
368
- )}
369
- </Popover>,
370
- );
371
-
372
- // open the popover
373
- await userEvent.click(
374
- await screen.findByRole("button", {
375
- name: "Open default popover",
376
- }),
377
- );
378
-
379
- // Act
380
- // we try to close it using the same trigger element
381
- await userEvent.click(
382
- await screen.findByRole("button", {
383
- name: "Open default popover",
384
- }),
385
- );
386
-
387
- // Assert
388
- await waitFor(() => {
389
- expect(screen.queryByText("Title")).not.toBeInTheDocument();
390
- });
391
- });
392
-
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 () => {
396
- // Arrange
397
- render(
398
- <Popover
399
- dismissEnabled={true}
400
- placement="top"
401
- content={<PopoverContent title="Title" content="content" />}
402
- >
403
- {({open}: any) => (
404
- <button data-anchor onClick={open}>
405
- Open default popover
406
- </button>
407
- )}
408
- </Popover>,
409
- );
410
-
411
- // open the popover
412
- await userEvent.click(
413
- await screen.findByRole("button", {
414
- name: "Open default popover",
415
- }),
416
- );
417
-
418
- // Act
419
- // we try to close it pressing the Escape key
420
- await userEvent.keyboard("{esc}");
421
-
422
- // Assert
423
- expect(
424
- await screen.findByRole("button", {
425
- name: "Open default popover",
426
- }),
427
- ).toHaveFocus();
428
- });
429
-
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 () => {
434
- // Arrange
435
- const {container} = render(
436
- <Popover
437
- dismissEnabled={true}
438
- placement="top"
439
- content={<PopoverContent title="Title" content="content" />}
440
- >
441
- {({open}: any) => (
442
- <button data-anchor onClick={open}>
443
- Open default popover
444
- </button>
445
- )}
446
- </Popover>,
447
- );
448
-
449
- // open the popover
450
- await userEvent.click(
451
- await screen.findByRole("button", {
452
- name: "Open default popover",
453
- }),
454
- );
455
-
456
- // Act
457
- // we try to close it clicking outside the popover
458
- await userEvent.click(container);
459
-
460
- // Assert
461
- expect(
462
- await screen.findByRole("button", {
463
- name: "Open default popover",
464
- }),
465
- ).toHaveFocus();
466
- });
467
-
468
- it("should NOT return focus to the anchor element when clicking on an interactive element", async () => {
469
- // Arrange
470
- render(
471
- <View>
472
- <Popover
473
- dismissEnabled={true}
474
- placement="top"
475
- content={
476
- <PopoverContent title="Title" content="content" />
477
- }
478
- >
479
- {({open}: any) => (
480
- <button data-anchor onClick={open}>
481
- Open default popover
482
- </button>
483
- )}
484
- </Popover>
485
- <Button>Next button outside</Button>
486
- </View>,
487
- );
488
-
489
- // open the popover
490
- await userEvent.click(
491
- await screen.findByRole("button", {
492
- name: "Open default popover",
493
- }),
494
- );
495
-
496
- // Act
497
- // we try to close it clicking outside the popover
498
- await userEvent.click(
499
- await screen.findByRole("button", {
500
- name: "Next button outside",
501
- }),
502
- );
503
-
504
- // Assert
505
- // The focus should remain on the button outside the popover
506
- expect(
507
- await screen.findByRole("button", {
508
- name: "Next button outside",
509
- }),
510
- ).toHaveFocus();
511
- });
512
- });
513
-
514
- describe("a11y", () => {
515
- it("should announce a popover correctly by reading the title contents", async () => {
516
- // Arrange
517
- render(
518
- <Popover
519
- onClose={jest.fn()}
520
- content={
521
- <PopoverContent
522
- title="The title is read by the screen reader"
523
- content="content"
524
- closeButtonVisible={true}
525
- closeButtonLabel="Click to close popover"
526
- />
527
- }
528
- >
529
- <Button>Open default popover</Button>
530
- </Popover>,
531
- );
532
-
533
- // Act
534
- // Open the popover
535
- await userEvent.click(
536
- await screen.findByRole("button", {
537
- name: "Open default popover",
538
- }),
539
- );
540
-
541
- // Assert
542
- expect(
543
- await screen.findByRole("dialog", {
544
- name: "The title is read by the screen reader",
545
- }),
546
- ).toBeInTheDocument();
547
- });
548
-
549
- it("should announce a custom popover correctly by reading the title contents", async () => {
550
- // Arrange
551
- render(
552
- <Popover
553
- onClose={jest.fn()}
554
- id="custom-popover"
555
- content={
556
- <PopoverContentCore closeButtonVisible={true}>
557
- <h1 id="custom-popover-title">
558
- This is a custom popover title
559
- </h1>
560
- <p id="custom-popover-content">
561
- The custom popover description
562
- </p>
563
- </PopoverContentCore>
564
- }
565
- >
566
- <Button>Open default popover</Button>
567
- </Popover>,
568
- );
569
-
570
- // Act
571
- // Open the popover
572
- await userEvent.click(
573
- await screen.findByRole("button", {
574
- name: "Open default popover",
575
- }),
576
- );
577
-
578
- // Assert
579
- expect(
580
- await screen.findByRole("dialog", {
581
- name: "This is a custom popover title",
582
- }),
583
- ).toBeInTheDocument();
584
- });
585
-
586
- it("should announce a popover correctly by reading the aria-label attribute", async () => {
587
- // Arrange
588
- render(
589
- <Popover
590
- id="test-popover"
591
- onClose={jest.fn()}
592
- aria-label="Popover Aria Label"
593
- content={
594
- <PopoverContentCore closeButtonVisible={true}>
595
- <h1 id="test-popover-title">
596
- This is a popover title
597
- </h1>
598
- <p id="test-popover-content">
599
- This is a popover description
600
- </p>
601
- </PopoverContentCore>
602
- }
603
- >
604
- <Button>Open default popover</Button>
605
- </Popover>,
606
- );
607
-
608
- // Act
609
- await userEvent.click(
610
- await screen.findByRole("button", {
611
- name: "Open default popover",
612
- }),
613
- );
614
-
615
- // Assert
616
- expect(
617
- await screen.findByRole("dialog", {
618
- name: "Popover Aria Label",
619
- }),
620
- ).toBeInTheDocument();
621
- });
622
-
623
- it("should announce a popover correctly by reading the title contents", async () => {
624
- // Arrange
625
- render(
626
- <Popover
627
- id="test-popover"
628
- onClose={jest.fn()}
629
- aria-describedby="describing-popover-id"
630
- content={
631
- <PopoverContentCore closeButtonVisible={true}>
632
- <h1 id="test-popover-title">
633
- This is a popover title
634
- </h1>
635
- <p id="describing-popover-id">
636
- This is a popover description
637
- </p>
638
- </PopoverContentCore>
639
- }
640
- >
641
- <Button>Open default popover</Button>
642
- </Popover>,
643
- );
644
-
645
- // Act
646
- await userEvent.click(
647
- await screen.findByRole("button", {
648
- name: "Open default popover",
649
- }),
650
- );
651
-
652
- //Assert
653
- expect(
654
- await screen.findByRole("dialog", {
655
- name: "This is a popover title",
656
- }),
657
- ).toBeInTheDocument();
658
- });
659
-
660
- it("should announce a popover correctly by reading the describing contents", async () => {
661
- // Arrange
662
- render(
663
- <Popover
664
- id="test-popover"
665
- onClose={jest.fn()}
666
- aria-describedby="describing-popover-id"
667
- content={
668
- <PopoverContentCore closeButtonVisible={true}>
669
- <h1 id="test-popover-title">
670
- This is a popover title
671
- </h1>
672
- <p id="describing-popover-id">
673
- This is a popover description
674
- </p>
675
- </PopoverContentCore>
676
- }
677
- >
678
- <Button>Open default popover</Button>
679
- </Popover>,
680
- );
681
-
682
- // Act
683
- await userEvent.click(
684
- await screen.findByRole("button", {
685
- name: "Open default popover",
686
- }),
687
- );
688
-
689
- //Assert
690
- expect(
691
- await screen.findByRole("dialog", {
692
- description: "This is a popover description",
693
- }),
694
- ).toBeInTheDocument();
695
- });
696
-
697
- it("should correctly describe the popover content core's aria label", async () => {
698
- // Arrange
699
- render(
700
- <Popover
701
- onClose={jest.fn()}
702
- content={
703
- <PopoverContentCore aria-label="Popover Content Core">
704
- <button data-close-button onClick={close}>
705
- Close Popover
706
- </button>
707
- </PopoverContentCore>
708
- }
709
- >
710
- <Button>Open default popover</Button>
711
- </Popover>,
712
- );
713
-
714
- // Act
715
- // Open the popover
716
- const openButton = await screen.findByRole("button", {
717
- name: "Open default popover",
718
- });
719
-
720
- await userEvent.click(openButton);
721
- const popover = await screen.findByRole("dialog");
722
-
723
- // disabling this check because we need to access the popover content core
724
- // in order to verify the aria-label is getting passed correctly
725
- // eslint-disable-next-line testing-library/no-node-access
726
- const popoverContentCore = popover.firstChild as HTMLElement;
727
-
728
- // Assert
729
- expect(popoverContentCore.getAttribute("aria-label")).toBe(
730
- "Popover Content Core",
731
- );
732
- });
733
- });
734
-
735
- describe.each([true, false])("keyboard navigation", (portal) => {
736
- it(`when portal=${portal}, should move focus to the first focusable element after popover is open`, async () => {
737
- // Arrange
738
- render(
739
- <>
740
- <Button>Prev focusable element outside</Button>
741
- <Popover
742
- onClose={jest.fn()}
743
- portal={portal}
744
- content={
745
- <PopoverContent
746
- title="Popover title"
747
- content="content"
748
- actions={
749
- <>
750
- <Button>Button 1 inside popover</Button>
751
- <Button>Button 2 inside popover</Button>
752
- </>
753
- }
754
- />
755
- }
756
- >
757
- <Button>Open default popover</Button>
758
- </Popover>
759
- <Button>Next focusable element outside</Button>
760
- </>,
761
- );
762
-
763
- // Focus on the first element outside the popover
764
- await userEvent.tab();
765
- // open the popover by focusing on the trigger element
766
- await userEvent.tab();
767
- await userEvent.keyboard("{enter}");
768
-
769
- // Act
770
- // Wait for the popover to be open.
771
- await screen.findByRole("dialog");
772
-
773
- // Assert
774
- // Focus should move to the first button inside the popover
775
- expect(
776
- await screen.findByRole("button", {
777
- name: "Button 1 inside popover",
778
- }),
779
- ).toHaveFocus();
780
- });
781
-
782
- it(`when portal=${portal}, should allow flowing focus correctly even if the popover remains open`, async () => {
783
- // Arrange
784
- render(
785
- <>
786
- <Button>Prev focusable element outside</Button>
787
- <Popover
788
- onClose={jest.fn()}
789
- portal={portal}
790
- content={
791
- <PopoverContent
792
- title="Popover title"
793
- content="content"
794
- actions={<Button>Button inside popover</Button>}
795
- />
796
- }
797
- >
798
- <Button>Open default popover</Button>
799
- </Popover>
800
- <Button>Next focusable element outside</Button>
801
- </>,
802
- );
803
-
804
- // Focus on the first element outside the popover
805
- await userEvent.tab();
806
- // open the popover by focusing on the trigger element
807
- await userEvent.tab();
808
- await userEvent.keyboard("{enter}");
809
-
810
- // Wait for the popover to be open.
811
- await screen.findByRole("dialog");
812
-
813
- // Act
814
- // Focus on the next element after the popover
815
- await userEvent.tab();
816
-
817
- // Assert
818
- expect(
819
- await screen.findByRole("button", {
820
- name: "Next focusable element outside",
821
- }),
822
- ).toHaveFocus();
823
- });
824
-
825
- it(`when portal=${portal}, should allow circular navigation when the popover is open`, async () => {
826
- // Arrange
827
- render(
828
- <>
829
- <Button>Prev focusable element outside</Button>
830
- <Popover
831
- onClose={jest.fn()}
832
- portal={portal}
833
- content={
834
- <PopoverContent
835
- title="Popover title"
836
- content="content"
837
- actions={<Button>Button inside popover</Button>}
838
- />
839
- }
840
- >
841
- <Button>Open default popover</Button>
842
- </Popover>
843
- <Button>Next focusable element outside</Button>
844
- </>,
845
- );
846
-
847
- // Focus on the first element outside the popover
848
- await userEvent.tab();
849
- // open the popover by focusing on the trigger element
850
- await userEvent.tab();
851
- await userEvent.keyboard("{enter}");
852
-
853
- // Wait for the popover to be open.
854
- await screen.findByRole("dialog");
855
-
856
- // Focus on the next element after the popover
857
- await userEvent.tab();
858
-
859
- // Focus on the document body
860
- await userEvent.tab();
861
-
862
- // Act
863
- // Focus again on the first element in the document.
864
- await userEvent.tab();
865
-
866
- // Assert
867
- expect(
868
- await screen.findByRole("button", {
869
- name: "Prev focusable element outside",
870
- }),
871
- ).toHaveFocus();
872
- });
873
-
874
- it(`when portal=${portal}, should allow navigating backwards when the popover is open`, async () => {
875
- // Arrange
876
- render(
877
- <>
878
- <Button>Prev focusable element outside</Button>
879
- <Popover
880
- onClose={jest.fn()}
881
- portal={portal}
882
- content={
883
- <PopoverContent
884
- title="Popover title"
885
- content="content"
886
- actions={<Button>Button inside popover</Button>}
887
- />
888
- }
889
- >
890
- <Button>Open default popover</Button>
891
- </Popover>
892
- <Button>Next focusable element outside</Button>
893
- </>,
894
- );
895
-
896
- // Open the popover
897
- await userEvent.click(
898
- await screen.findByRole("button", {
899
- name: "Open default popover",
900
- }),
901
- );
902
-
903
- // Wait for the popover to be open.
904
- await screen.findByRole("dialog");
905
-
906
- // At this point, the focus moves to the focusable element inside
907
- // the popover, so we need to move the focus back to the trigger
908
- // element.
909
- await userEvent.tab({shift: true});
910
-
911
- // Focus on the first element in the document
912
- await userEvent.tab({shift: true});
913
-
914
- // Focus on the document body
915
- await userEvent.tab({shift: true});
916
-
917
- // Focus on the last element in the document
918
- await userEvent.tab({shift: true});
919
-
920
- // Act
921
- // Focus again on element inside the popover.
922
- await userEvent.tab({shift: true});
923
-
924
- // Assert
925
- expect(
926
- await screen.findByRole("button", {
927
- name: "Button inside popover",
928
- }),
929
- ).toHaveFocus();
930
- });
931
- });
932
- });