@@ -28,3 +28,51 @@ it('closes without consuming Tab when the overlay ref is omitted', () => {
2828 trigger . remove ( ) ;
2929 }
3030} ) ;
31+
32+ it . each ( [ false , true ] ) (
33+ 'leaves a portaled nested menu Escape to its owner (wrapped: %s)' ,
34+ ( wrapped ) => {
35+ const trigger = document . createElement ( 'button' ) ;
36+ const wrapper = document . createElement ( 'div' ) ;
37+ const root = document . createElement ( 'ul' ) ;
38+ const submenu = document . createElement ( 'ul' ) ;
39+ const child = document . createElement ( 'li' ) ;
40+ root . setAttribute ( 'role' , 'menu' ) ;
41+ submenu . setAttribute ( 'role' , 'menu' ) ;
42+ child . tabIndex = - 1 ;
43+ submenu . appendChild ( child ) ;
44+ wrapper . appendChild ( root ) ;
45+ document . body . append ( trigger , wrapper , submenu ) ;
46+ const onOpenChange = jest . fn ( ) ;
47+ const { unmount } = renderHook ( ( ) =>
48+ useAccessibility ( {
49+ open : true ,
50+ triggerRef : { current : trigger } ,
51+ onOpenChange,
52+ overlayRef : { current : wrapped ? wrapper : { list : root } } ,
53+ } ) ,
54+ ) ;
55+ try {
56+ child . focus ( ) ;
57+ act ( ( ) =>
58+ child . dispatchEvent (
59+ new KeyboardEvent ( 'keydown' , { keyCode : 27 , bubbles : true } ) ,
60+ ) ,
61+ ) ;
62+ expect ( onOpenChange ) . not . toHaveBeenCalled ( ) ;
63+ expect ( document . activeElement ) . toBe ( child ) ;
64+ act ( ( ) =>
65+ root . dispatchEvent (
66+ new KeyboardEvent ( 'keydown' , { keyCode : 27 , bubbles : true } ) ,
67+ ) ,
68+ ) ;
69+ expect ( onOpenChange ) . toHaveBeenCalledWith ( false ) ;
70+ expect ( document . activeElement ) . toBe ( trigger ) ;
71+ } finally {
72+ unmount ( ) ;
73+ trigger . remove ( ) ;
74+ wrapper . remove ( ) ;
75+ submenu . remove ( ) ;
76+ }
77+ } ,
78+ ) ;
0 commit comments