@@ -33,8 +33,8 @@ describe('useFocusTrap', () => {
3333 } )
3434
3535 it ( 'preserves provided refs' , ( ) => {
36- const containerRef = React . createRef < HTMLElement > ( )
37- const initialFocusRef = React . createRef < HTMLElement > ( )
36+ const containerRef = React . createRef < HTMLDivElement > ( )
37+ const initialFocusRef = React . createRef < HTMLButtonElement > ( )
3838 const { result} = renderHook ( ( ) => useFocusTrap ( { containerRef, initialFocusRef, disabled : true } ) )
3939
4040 expect ( result . current . containerRef ) . toBe ( containerRef )
@@ -43,11 +43,11 @@ describe('useFocusTrap', () => {
4343
4444 it ( 'passes generated ref elements to the focus trap' , ( ) => {
4545 const TestComponent = ( ) => {
46- const { containerRef, initialFocusRef} = useFocusTrap ( )
46+ const { containerRef, initialFocusRef} = useFocusTrap < HTMLDivElement , HTMLButtonElement > ( )
4747
4848 return (
49- < div ref = { containerRef as React . RefObject < HTMLDivElement | null > } >
50- < button ref = { initialFocusRef as React . RefObject < HTMLButtonElement | null > } />
49+ < div ref = { containerRef } >
50+ < button ref = { initialFocusRef } />
5151 </ div >
5252 )
5353 }
@@ -56,4 +56,57 @@ describe('useFocusTrap', () => {
5656
5757 expect ( mockFocusTrap ) . toHaveBeenCalledWith ( container . querySelector ( 'div' ) , container . querySelector ( 'button' ) )
5858 } )
59+
60+ it ( 'starts and aborts the focus trap when disabled changes' , ( ) => {
61+ const abortController = new AbortController ( )
62+ const abortSpy = jest . spyOn ( abortController , 'abort' )
63+ mockFocusTrap . mockReturnValue ( abortController )
64+
65+ const TestComponent = ( { disabled} : { disabled : boolean } ) => {
66+ const { containerRef} = useFocusTrap < HTMLDivElement > ( { disabled} )
67+ return < div ref = { containerRef } />
68+ }
69+
70+ const { rerender} = render ( < TestComponent disabled /> )
71+
72+ expect ( mockFocusTrap ) . not . toHaveBeenCalled ( )
73+
74+ rerender ( < TestComponent disabled = { false } /> )
75+
76+ expect ( mockFocusTrap ) . toHaveBeenCalledTimes ( 1 )
77+
78+ rerender ( < TestComponent disabled /> )
79+
80+ expect ( abortSpy ) . toHaveBeenCalled ( )
81+ } )
82+
83+ it ( 'captures fresh focus after cleaning up a non-HTMLElement active element' , ( ) => {
84+ const svg = document . createElementNS ( 'http://www.w3.org/2000/svg' , 'svg' )
85+ svg . setAttribute ( 'tabindex' , '0' )
86+ document . body . append ( svg )
87+ svg . focus ( )
88+
89+ const nextFocusedElement = document . createElement ( 'button' )
90+ document . body . append ( nextFocusedElement )
91+
92+ const TestComponent = ( { disabled} : { disabled : boolean } ) => {
93+ const { containerRef} = useFocusTrap < HTMLDivElement > ( { disabled, restoreFocusOnCleanUp : true } )
94+ return < div ref = { containerRef } />
95+ }
96+
97+ const { rerender} = render ( < TestComponent disabled = { false } /> )
98+
99+ rerender ( < TestComponent disabled /> )
100+ nextFocusedElement . focus ( )
101+
102+ const focusSpy = jest . spyOn ( nextFocusedElement , 'focus' )
103+
104+ rerender ( < TestComponent disabled = { false } /> )
105+ rerender ( < TestComponent disabled /> )
106+
107+ expect ( focusSpy ) . toHaveBeenCalled ( )
108+
109+ svg . remove ( )
110+ nextFocusedElement . remove ( )
111+ } )
59112} )
0 commit comments