UNPKG

22 kBJavaScriptView Raw
1/* eslint-disable jsx-a11y/no-noninteractive-tabindex */
2import React from 'react';
3import { render, screen } from '@testing-library/react';
4import user from '@testing-library/user-event';
5import '@testing-library/jest-dom';
6import { Offcanvas, OffcanvasBody, OffcanvasHeader, Button } from '..';
7import { testForCustomClass } from '../testUtils';
8
9describe('Offcanvas', () => {
10 let toggle;
11 beforeEach(() => {
12 toggle = () => {};
13 jest.useFakeTimers();
14 });
15
16 afterEach(() => {
17 jest.clearAllTimers();
18 document.body.removeAttribute('style');
19 });
20
21 it('should render offcanvas portal into DOM', () => {
22 render(
23 <Offcanvas isOpen toggle={toggle}>
24 Yo!
25 </Offcanvas>,
26 );
27
28 jest.advanceTimersByTime(300);
29
30 expect(screen.getByText(/yo/i)).toBeInTheDocument();
31 });
32
33 it('should render with the class "offcanvas"', () => {
34 render(
35 <Offcanvas isOpen toggle={toggle}>
36 Yo!
37 </Offcanvas>,
38 );
39
40 expect(screen.getByText(/yo/i)).toHaveClass('offcanvas');
41 });
42
43 it('should render with the backdrop with the class "offcanvas-backdrop" by default', () => {
44 render(
45 <Offcanvas isOpen toggle={toggle}>
46 Yo!
47 </Offcanvas>,
48 );
49
50 expect(document.getElementsByClassName('offcanvas-backdrop')).toHaveLength(
51 1,
52 );
53 });
54
55 it('should not render with the backdrop with the class "offcanvas-backdrop" when backdrop is "false"', () => {
56 render(
57 <Offcanvas isOpen toggle={toggle} backdrop={false}>
58 Yo!
59 </Offcanvas>,
60 );
61
62 expect(document.getElementsByClassName('offcanvas').length).toBe(1);
63 expect(document.getElementsByClassName('offcanvas-backdrop').length).toBe(
64 0,
65 );
66 });
67
68 it('should have custom class name if provided', () => {
69 testForCustomClass(Offcanvas, { isOpen: true, toggle });
70 });
71
72 it('should render with additional props if provided', () => {
73 render(
74 <Offcanvas isOpen toggle={toggle} style={{ maxWidth: '95%' }}>
75 Yo!
76 </Offcanvas>,
77 );
78
79 expect(document.getElementsByClassName('offcanvas')[0].style.maxWidth).toBe(
80 '95%',
81 );
82 });
83
84 it('should render without fade transition if provided with fade={false}', () => {
85 render(
86 <Offcanvas
87 isOpen
88 toggle={toggle}
89 fade={false}
90 className="fadeless-offcanvas"
91 >
92 Howdy!
93 </Offcanvas>,
94 );
95
96 expect(
97 document.getElementsByClassName('fadeless-offcanvas')[0],
98 ).not.toHaveClass('fade');
99 });
100
101 it('should render when expected when passed offcanvasTransition and backdropTransition props', () => {
102 render(
103 <Offcanvas
104 isOpen
105 toggle={toggle}
106 offcanvasTransition={{ timeout: 2 }}
107 backdropTransition={{ timeout: 10 }}
108 className="custom-timeout-offcanvas"
109 >
110 Hello, world!
111 </Offcanvas>,
112 );
113
114 expect(
115 document.getElementsByClassName('custom-timeout-offcanvas')[0],
116 ).toHaveClass('fade');
117 expect(
118 document.getElementsByClassName('custom-timeout-offcanvas')[0],
119 ).not.toHaveClass('show');
120 expect(
121 document.getElementsByClassName('offcanvas-backdrop')[0],
122 ).not.toHaveClass('show');
123
124 jest.advanceTimersByTime(20);
125 expect(
126 document.getElementsByClassName('custom-timeout-offcanvas')[0],
127 ).toHaveClass('show');
128 expect(
129 document.getElementsByClassName('offcanvas-backdrop')[0],
130 ).toHaveClass('show');
131 });
132
133 it('should render with class "offcanvas-backdrop" and have custom class name if provided with backdropClassName', () => {
134 render(
135 <Offcanvas isOpen toggle={toggle} backdropClassName="my-custom-offcanvas">
136 Yo!
137 </Offcanvas>,
138 );
139
140 expect(
141 document.getElementsByClassName(
142 'offcanvas-backdrop my-custom-offcanvas',
143 )[0],
144 ).toBeInTheDocument();
145 });
146
147 it('should render with the class "offcanvas-${direction}" when direction is passed', () => {
148 render(
149 <Offcanvas isOpen toggle={toggle} direction="top">
150 Yo!
151 </Offcanvas>,
152 );
153
154 expect(screen.getByText(/yo/i)).toHaveClass('offcanvas-top');
155 });
156
157 it('should render offcanvas when isOpen is true', () => {
158 render(
159 <Offcanvas isOpen toggle={toggle}>
160 Yo!
161 </Offcanvas>,
162 );
163
164 expect(screen.getByText(/yo/i)).toHaveClass('offcanvas');
165 expect(document.getElementsByClassName('offcanvas-backdrop').length).toBe(
166 1,
167 );
168 });
169
170 it('should render offcanvas with default role of "dialog"', () => {
171 render(
172 <Offcanvas isOpen toggle={toggle}>
173 Yo!
174 </Offcanvas>,
175 );
176 expect(screen.getByText(/yo/i).getAttribute('role')).toBe('dialog');
177 });
178
179 it('should render offcanvas with provided role', () => {
180 render(
181 <Offcanvas isOpen toggle={toggle} role="alert">
182 Yo!
183 </Offcanvas>,
184 );
185
186 expect(screen.getByText(/yo/i).getAttribute('role')).toBe('alert');
187 });
188
189 it('should render offcanvas with aria-labelledby provided labelledBy', () => {
190 render(
191 <Offcanvas isOpen toggle={toggle} labelledBy="myOffcanvasTitle">
192 Yo!
193 </Offcanvas>,
194 );
195
196 expect(screen.getByText(/yo/i).getAttribute('aria-labelledby')).toBe(
197 'myOffcanvasTitle',
198 );
199 });
200
201 it('should not render offcanvas when isOpen is false', () => {
202 render(
203 <Offcanvas isOpen={false} toggle={toggle}>
204 Yo!
205 </Offcanvas>,
206 );
207
208 expect(screen.queryByText(/yo/i)).not.toBeInTheDocument();
209 });
210
211 it('should toggle offcanvas', () => {
212 const { rerender } = render(
213 <Offcanvas isOpen={false} toggle={toggle}>
214 Yo!
215 </Offcanvas>,
216 );
217
218 expect(screen.queryByText(/yo/i)).not.toBeInTheDocument();
219
220 rerender(
221 <Offcanvas isOpen toggle={toggle}>
222 Yo!
223 </Offcanvas>,
224 );
225
226 expect(screen.queryByText(/yo/i)).toBeInTheDocument();
227
228 rerender(
229 <Offcanvas isOpen toggle={toggle}>
230 Yo!
231 </Offcanvas>,
232 );
233
234 expect(screen.queryByText(/yo/i)).toBeInTheDocument();
235 });
236
237 it('should call onClosed & onOpened', () => {
238 const onOpened = jest.fn();
239 const onClosed = jest.fn();
240 const { rerender } = render(
241 <Offcanvas
242 isOpen={false}
243 onOpened={onOpened}
244 onClosed={onClosed}
245 toggle={toggle}
246 >
247 Yo!
248 </Offcanvas>,
249 );
250
251 expect(onOpened).not.toHaveBeenCalled();
252 expect(onClosed).not.toHaveBeenCalled();
253
254 rerender(
255 <Offcanvas isOpen onOpened={onOpened} onClosed={onClosed} toggle={toggle}>
256 Yo!
257 </Offcanvas>,
258 );
259
260 jest.advanceTimersByTime(300);
261
262 expect(onOpened).toHaveBeenCalledTimes(1);
263 expect(onClosed).not.toHaveBeenCalled();
264
265 onOpened.mockClear();
266 onClosed.mockClear();
267
268 rerender(
269 <Offcanvas
270 isOpen={false}
271 onOpened={onOpened}
272 onClosed={onClosed}
273 toggle={toggle}
274 >
275 Yo!
276 </Offcanvas>,
277 );
278
279 jest.advanceTimersByTime(300);
280
281 expect(onClosed).toHaveBeenCalledTimes(1);
282 expect(onOpened).not.toHaveBeenCalled();
283 });
284
285 it('should call onClosed & onOpened when fade={false}', () => {
286 const onOpened = jest.fn();
287 const onClosed = jest.fn();
288 const { rerender } = render(
289 <Offcanvas
290 isOpen={false}
291 onOpened={onOpened}
292 onClosed={onClosed}
293 toggle={toggle}
294 fade={false}
295 >
296 Yo!
297 </Offcanvas>,
298 );
299
300 expect(onOpened).not.toHaveBeenCalled();
301 expect(onClosed).not.toHaveBeenCalled();
302
303 rerender(
304 <Offcanvas
305 isOpen
306 onOpened={onOpened}
307 onClosed={onClosed}
308 toggle={toggle}
309 fade={false}
310 >
311 Yo!
312 </Offcanvas>,
313 );
314
315 jest.advanceTimersByTime(300);
316
317 expect(onOpened).toHaveBeenCalledTimes(1);
318 expect(onClosed).not.toHaveBeenCalled();
319
320 onOpened.mockClear();
321 onClosed.mockClear();
322
323 rerender(
324 <Offcanvas
325 isOpen={false}
326 onOpened={onOpened}
327 onClosed={onClosed}
328 toggle={toggle}
329 fade={false}
330 >
331 Yo!
332 </Offcanvas>,
333 );
334
335 jest.advanceTimersByTime(300);
336
337 expect(onClosed).toHaveBeenCalledTimes(1);
338 expect(onOpened).not.toHaveBeenCalled();
339 });
340
341 it('should call toggle when escape key pressed', () => {
342 const toggle = jest.fn();
343 render(
344 <Offcanvas isOpen toggle={toggle}>
345 Yo!
346 </Offcanvas>,
347 );
348
349 user.keyboard('{esc}');
350 expect(toggle).toHaveBeenCalled();
351 });
352
353 it('should not call toggle when escape key pressed when keyboard is false', () => {
354 const toggle = jest.fn();
355 render(
356 <Offcanvas isOpen toggle={toggle} keyboard={false}>
357 Yo!
358 </Offcanvas>,
359 );
360
361 user.keyboard('{esc}');
362 expect(toggle).not.toHaveBeenCalled();
363 });
364
365 it('should call toggle when clicking backdrop', () => {
366 const toggle = jest.fn();
367 render(
368 <Offcanvas isOpen toggle={toggle}>
369 <button id="clicker">Does Nothing</button>
370 </Offcanvas>,
371 );
372
373 user.click(screen.getByText(/does nothing/i));
374
375 expect(toggle).not.toHaveBeenCalled();
376
377 user.click(document.getElementsByClassName('offcanvas-backdrop')[0]);
378
379 expect(toggle).toHaveBeenCalled();
380 });
381
382 it('should call toggle when clicking backdrop when fade is false', () => {
383 const toggle = jest.fn();
384 render(
385 <Offcanvas isOpen toggle={toggle} fade={false}>
386 <button id="clicker">Does Nothing</button>
387 </Offcanvas>,
388 );
389
390 user.click(screen.getByText(/does nothing/i));
391
392 expect(toggle).not.toHaveBeenCalled();
393
394 user.click(document.getElementsByClassName('offcanvas-backdrop')[0]);
395
396 expect(toggle).toHaveBeenCalled();
397 });
398
399 it('should destroy this._element', () => {
400 const { rerender } = render(
401 <Offcanvas isOpen toggle={toggle}>
402 thor and dr.johns
403 </Offcanvas>,
404 );
405
406 const element = screen.getByText(/thor and dr.johns/i);
407 expect(element).toBeInTheDocument();
408
409 rerender(
410 <Offcanvas isOpen={false} toggle={toggle}>
411 thor and dr.johns
412 </Offcanvas>,
413 );
414 jest.advanceTimersByTime(300);
415 expect(element).not.toBeInTheDocument();
416 });
417
418 it('should destroy this._element when unmountOnClose prop set to true', () => {
419 const { rerender } = render(
420 <Offcanvas isOpen toggle={toggle} unmountOnClose>
421 thor and dr.johns
422 </Offcanvas>,
423 );
424
425 const element = screen.getByText(/thor and dr.johns/i);
426 expect(element).toBeInTheDocument();
427
428 rerender(
429 <Offcanvas isOpen={false} toggle={toggle} unmountOnClose>
430 thor and dr.johns
431 </Offcanvas>,
432 );
433 jest.advanceTimersByTime(300);
434 expect(element).not.toBeInTheDocument();
435 });
436
437 it('should not destroy this._element when unmountOnClose prop set to false', () => {
438 const { rerender } = render(
439 <Offcanvas isOpen toggle={toggle} unmountOnClose={false}>
440 thor and dr.johns
441 </Offcanvas>,
442 );
443
444 const element = screen.getByText(/thor and dr.johns/i);
445 expect(element).toBeInTheDocument();
446
447 rerender(
448 <Offcanvas isOpen={false} toggle={toggle} unmountOnClose={false}>
449 thor and dr.johns
450 </Offcanvas>,
451 );
452 jest.advanceTimersByTime(300);
453 expect(element).toBeInTheDocument();
454 });
455
456 it('should destroy this._element on unmount', () => {
457 const { unmount } = render(
458 <Offcanvas isOpen toggle={toggle}>
459 thor and dr.johns
460 </Offcanvas>,
461 );
462
463 const element = screen.getByText(/thor and dr.johns/i);
464 expect(element).toBeInTheDocument();
465
466 unmount();
467 jest.advanceTimersByTime(300);
468 expect(element).not.toBeInTheDocument();
469 });
470
471 it('should remove exactly visibility styles from body', () => {
472 // set a body class which includes offcanvas-open
473 document.body.style.background = 'blue';
474
475 const { rerender } = render(
476 <Offcanvas isOpen={false} toggle={toggle}>
477 Yo!
478 </Offcanvas>,
479 );
480
481 // assert that the offcanvas is closed and the body class is what was set initially
482 jest.advanceTimersByTime(300);
483 expect(document.body.style.background).toBe('blue');
484 expect(document.body.style.overflow).toBe('');
485
486 rerender(
487 <Offcanvas isOpen toggle={toggle}>
488 Yo!
489 </Offcanvas>,
490 );
491
492 // assert that the offcanvas is open and the body class is what was set initially + offcanvas-open
493 jest.advanceTimersByTime(300);
494 expect(document.body.style.background).toBe('blue');
495 expect(document.body.style.overflow).toBe('hidden');
496
497 // append another body class which includes offcanvas-open
498 // using this to test if replace will leave a space when removing offcanvas-open
499 document.body.style.color = 'red';
500 expect(document.body.style.background).toBe('blue');
501 expect(document.body.style.color).toBe('red');
502 expect(document.body.style.overflow).toBe('hidden');
503
504 rerender(
505 <Offcanvas isOpen={false} toggle={toggle}>
506 Yo!
507 </Offcanvas>,
508 );
509
510 // assert that the offcanvas is closed and the body class is what was set initially
511 jest.advanceTimersByTime(301);
512 expect(document.body.style.background).toBe('blue');
513 expect(document.body.style.color).toBe('red');
514 expect(document.body.style.overflow).toBe('');
515 });
516
517 it('should call onEnter & onExit props if provided', () => {
518 const onEnter = jest.fn();
519 const onExit = jest.fn();
520 const { rerender, unmount } = render(
521 <Offcanvas
522 isOpen={false}
523 onEnter={onEnter}
524 onExit={onExit}
525 toggle={toggle}
526 >
527 Yo!
528 </Offcanvas>,
529 );
530
531 expect(onEnter).toHaveBeenCalled();
532 expect(onExit).not.toHaveBeenCalled();
533
534 onEnter.mockReset();
535 onExit.mockReset();
536
537 rerender(
538 <Offcanvas isOpen onEnter={onEnter} onExit={onExit} toggle={toggle}>
539 Yo!
540 </Offcanvas>,
541 );
542 jest.advanceTimersByTime(300);
543
544 expect(onEnter).not.toHaveBeenCalled();
545 expect(onExit).not.toHaveBeenCalled();
546
547 onEnter.mockReset();
548 onExit.mockReset();
549
550 unmount();
551 expect(onEnter).not.toHaveBeenCalled();
552 expect(onExit).toHaveBeenCalled();
553 });
554
555 it('should update element z index when prop changes', () => {
556 const { rerender } = render(
557 <Offcanvas isOpen zIndex={0}>
558 Yo!
559 </Offcanvas>,
560 );
561 expect(screen.getByText(/yo/i).parentElement).toHaveStyle('z-index: 0');
562 rerender(
563 <Offcanvas isOpen zIndex={1}>
564 Yo!
565 </Offcanvas>,
566 );
567 expect(screen.getByText(/yo/i).parentElement).toHaveStyle('z-index: 1');
568 });
569
570 it('should allow focus on only focusable elements', () => {
571 render(
572 <Offcanvas isOpen toggle={toggle}>
573 <OffcanvasHeader toggle={toggle}>Offcanvas title</OffcanvasHeader>
574 <OffcanvasBody>
575 <a alt="test" href="/">
576 First Test
577 </a>
578 <map name="test">
579 <area alt="test" href="/" coords="200,5,200,30" />
580 </map>
581 <input type="text" aria-label="test text input" />
582 <input type="hidden" />
583 <input type="text" disabled value="Test" />
584 <select name="test" id="select_test">
585 <option>Second item</option>
586 </select>
587 <select name="test" id="select_test_disabled" disabled>
588 <option>Third item</option>
589 </select>
590 <textarea
591 name="textarea_test"
592 id="textarea_test"
593 cols="30"
594 rows="10"
595 aria-label="test text area"
596 />
597 <textarea
598 name="textarea_test_disabled"
599 id="textarea_test_disabled"
600 cols="30"
601 rows="10"
602 disabled
603 />
604 <object>Test</object>
605 <span tabIndex="0">test tab index</span>
606 </OffcanvasBody>
607 </Offcanvas>,
608 );
609
610 user.tab();
611 expect(screen.getByLabelText(/close/i)).toHaveFocus();
612 user.tab();
613 expect(screen.getByText(/first test/i)).toHaveFocus();
614 user.tab();
615 expect(screen.getByLabelText(/test text input/i)).toHaveFocus();
616 user.tab();
617 expect(screen.getByText(/second item/i).parentElement).toHaveFocus();
618 user.tab();
619 expect(screen.getByLabelText(/test text area/i)).toHaveFocus();
620 user.tab();
621 expect(screen.getByText(/test tab index/i)).toHaveFocus();
622 user.tab();
623 expect(screen.getByLabelText(/close/i)).toHaveFocus();
624 });
625
626 it('should return the focus to the last focused element before the offcanvas has opened', () => {
627 const { rerender } = render(
628 <>
629 <button className="focus">Focused</button>
630 <Offcanvas isOpen={false}>
631 <OffcanvasBody>Whatever</OffcanvasBody>
632 </Offcanvas>
633 </>,
634 );
635
636 user.tab();
637 expect(screen.getByText(/focused/i)).toHaveFocus();
638
639 rerender(
640 <>
641 <button className="focus">Focused</button>
642 <Offcanvas isOpen>
643 <OffcanvasBody>Whatever</OffcanvasBody>
644 </Offcanvas>
645 </>,
646 );
647
648 expect(screen.getByText(/focused/i)).not.toHaveFocus();
649
650 rerender(
651 <>
652 <button className="focus">Focused</button>
653 <Offcanvas isOpen={false}>
654 <OffcanvasBody>Whatever</OffcanvasBody>
655 </Offcanvas>
656 </>,
657 );
658
659 jest.runAllTimers();
660 expect(screen.getByText(/focused/i)).toHaveFocus();
661 });
662
663 it('should not return the focus to the last focused element before the offcanvas has opened when "returnFocusAfterClose" is false', () => {
664 const { rerender } = render(
665 <>
666 <button className="focus">Focused</button>
667 <Offcanvas returnFocusAfterClose={false} isOpen={false}>
668 <OffcanvasBody>Whatever</OffcanvasBody>
669 </Offcanvas>
670 </>,
671 );
672
673 user.tab();
674 expect(screen.getByText(/focused/i)).toHaveFocus();
675
676 rerender(
677 <>
678 <button className="focus">Focused</button>
679 <Offcanvas returnFocusAfterClose={false} isOpen>
680 <OffcanvasBody>Whatever</OffcanvasBody>
681 </Offcanvas>
682 </>,
683 );
684
685 expect(screen.getByText(/focused/i)).not.toHaveFocus();
686
687 rerender(
688 <>
689 <button className="focus">Focused</button>
690 <Offcanvas returnFocusAfterClose={false} isOpen={false}>
691 <OffcanvasBody>Whatever</OffcanvasBody>
692 </Offcanvas>
693 </>,
694 );
695
696 jest.runAllTimers();
697 expect(screen.getByText(/focused/i)).not.toHaveFocus();
698 });
699
700 it('should return the focus to the last focused element before the offcanvas has opened when "unmountOnClose" is false', () => {
701 const { rerender } = render(
702 <>
703 <button className="focus">Focused</button>
704 <Offcanvas unmountOnClose={false} isOpen={false}>
705 <OffcanvasBody>Whatever</OffcanvasBody>
706 </Offcanvas>
707 </>,
708 );
709
710 user.tab();
711 expect(screen.getByText(/focused/i)).toHaveFocus();
712
713 rerender(
714 <>
715 <button className="focus">Focused</button>
716 <Offcanvas unmountOnClose={false} isOpen>
717 <OffcanvasBody>Whatever</OffcanvasBody>
718 </Offcanvas>
719 </>,
720 );
721
722 expect(screen.getByText(/focused/i)).not.toHaveFocus();
723
724 rerender(
725 <>
726 <button className="focus">Focused</button>
727 <Offcanvas unmountOnClose={false} isOpen={false}>
728 <OffcanvasBody>Whatever</OffcanvasBody>
729 </Offcanvas>
730 </>,
731 );
732
733 jest.runAllTimers();
734 expect(screen.getByText(/focused/i)).toHaveFocus();
735 });
736
737 it('should not return the focus to the last focused element before the offcanvas has opened when "returnFocusAfterClose" is false and "unmountOnClose" is false', () => {
738 const { rerender } = render(
739 <>
740 <button className="focus">Focused</button>
741 <Offcanvas
742 returnFocusAfterClose={false}
743 unmountOnClose={false}
744 isOpen={false}
745 >
746 <OffcanvasBody>Whatever</OffcanvasBody>
747 </Offcanvas>
748 </>,
749 );
750
751 user.tab();
752 expect(screen.getByText(/focused/i)).toHaveFocus();
753
754 rerender(
755 <>
756 <button className="focus">Focused</button>
757 <Offcanvas returnFocusAfterClose={false} unmountOnClose={false} isOpen>
758 <OffcanvasBody>Whatever</OffcanvasBody>
759 </Offcanvas>
760 </>,
761 );
762
763 expect(screen.getByText(/focused/i)).not.toHaveFocus();
764
765 rerender(
766 <>
767 <button className="focus">Focused</button>
768 <Offcanvas
769 returnFocusAfterClose={false}
770 unmountOnClose={false}
771 isOpen={false}
772 >
773 <OffcanvasBody>Whatever</OffcanvasBody>
774 </Offcanvas>
775 </>,
776 );
777
778 jest.runAllTimers();
779 expect(screen.getByText(/focused/i)).not.toHaveFocus();
780 });
781
782 it('should attach/detach trapFocus for dialogs', () => {
783 const addEventListener = jest.spyOn(document, 'addEventListener');
784 const removeEventListener = jest.spyOn(document, 'removeEventListener');
785
786 const { unmount } = render(
787 <Offcanvas isOpen toggle={toggle}>
788 Yo!
789 </Offcanvas>,
790 );
791
792 expect(addEventListener).toHaveBeenCalledTimes(1);
793 expect(addEventListener).toHaveBeenCalledWith(
794 'focus',
795 expect.any(Function),
796 true,
797 );
798
799 unmount();
800
801 expect(removeEventListener).toHaveBeenCalledTimes(1);
802 expect(removeEventListener).toHaveBeenCalledWith(
803 'focus',
804 expect.any(Function),
805 true,
806 );
807
808 addEventListener.mockRestore();
809 removeEventListener.mockRestore();
810 });
811
812 it('should trap focus inside the open dialog', () => {
813 render(
814 <>
815 <Button className="first">Focused</Button>
816 <Offcanvas isOpen trapFocus>
817 <OffcanvasBody>
818 Something else to see
819 <Button className="focus">focusable element</Button>
820 </OffcanvasBody>
821 </Offcanvas>
822 </>,
823 );
824 user.tab();
825 expect(screen.getByText(/focusable element/i)).toHaveFocus();
826
827 user.tab();
828 expect(screen.getByText(/focusable element/i)).toHaveFocus();
829 });
830});