@@ -240,3 +240,91 @@ it('Should handle dynamic content', async () => {
240
240
241
241
controller ?. abort ( )
242
242
} )
243
+
244
+ it ( 'should keep the sentinel elements at the start/end of the inner container' , async ( ) => {
245
+ const user = userEvent . setup ( )
246
+ const { container} = render (
247
+ < div >
248
+ < div id = "trapContainer" >
249
+ < button tabIndex = { 0 } > Apple</ button >
250
+ < button tabIndex = { 0 } > Banana</ button >
251
+ < button tabIndex = { 0 } > Cantaloupe</ button >
252
+ </ div >
253
+ < button id = "durian" tabIndex = { 0 } >
254
+ Durian
255
+ </ button >
256
+ </ div > ,
257
+ )
258
+
259
+ const trapContainer = container . querySelector < HTMLElement > ( '#trapContainer' ) !
260
+ const [ firstButton , secondButton ] = trapContainer . querySelectorAll ( 'button' )
261
+ const controller = focusTrap ( trapContainer )
262
+
263
+ secondButton . focus ( )
264
+ await user . tab ( )
265
+ await user . tab ( )
266
+ expect ( document . activeElement ) . toEqual ( firstButton )
267
+
268
+ trapContainer . insertAdjacentHTML ( 'afterbegin' , '<button id="first" tabindex="0">New first button</button>' )
269
+ const newFirstButton = trapContainer . querySelector ( '#first' )
270
+
271
+ const sentinelStart = trapContainer . querySelector ( '.sentinel' )
272
+
273
+ await user . tab ( { shift : true } )
274
+ expect ( trapContainer . firstElementChild ) . toEqual ( sentinelStart )
275
+ expect ( document . activeElement ) . toEqual ( newFirstButton )
276
+
277
+ trapContainer . insertAdjacentHTML ( 'beforeend' , '<button id="last" tabindex="0">New last button</button>' )
278
+ const newLastButton = trapContainer . querySelector ( '#last' )
279
+
280
+ const sentinelEnd = trapContainer . querySelector ( '.sentinel' )
281
+
282
+ await user . tab ( { shift : true } )
283
+ expect ( trapContainer . lastElementChild ) . toEqual ( sentinelEnd )
284
+ expect ( document . activeElement ) . toEqual ( newLastButton )
285
+
286
+ controller ?. abort ( )
287
+ } )
288
+
289
+ it ( 'should remove the mutation observer when the focus trap is released' , async ( ) => {
290
+ const user = userEvent . setup ( )
291
+ const { container} = render (
292
+ < div >
293
+ < div id = "trapContainer" >
294
+ < button tabIndex = { 0 } > Apple</ button >
295
+ < button tabIndex = { 0 } > Banana</ button >
296
+ < button tabIndex = { 0 } > Cantaloupe</ button >
297
+ </ div >
298
+ < button id = "durian" tabIndex = { 0 } >
299
+ Durian
300
+ </ button >
301
+ </ div > ,
302
+ )
303
+
304
+ const trapContainer = container . querySelector < HTMLElement > ( '#trapContainer' ) !
305
+ const [ firstButton , secondButton ] = trapContainer . querySelectorAll ( 'button' )
306
+ const controller = focusTrap ( trapContainer )
307
+
308
+ secondButton . focus ( )
309
+ await user . tab ( )
310
+ await user . tab ( )
311
+ expect ( document . activeElement ) . toEqual ( firstButton )
312
+
313
+ trapContainer . insertAdjacentHTML ( 'afterbegin' , '<button id="first" tabindex="0">New first button</button>' )
314
+ const newFirstButton = trapContainer . querySelector ( '#first' )
315
+
316
+ const sentinelStart = trapContainer . querySelector ( '.sentinel' )
317
+
318
+ await user . tab ( { shift : true } )
319
+ expect ( trapContainer . firstElementChild ) . toEqual ( sentinelStart )
320
+ expect ( document . activeElement ) . toEqual ( newFirstButton )
321
+
322
+ controller ?. abort ( )
323
+
324
+ trapContainer . insertAdjacentHTML ( 'beforeend' , '<button id="last" tabindex="0">New last button</button>' )
325
+ const newLastButton = trapContainer . querySelector ( '#last' )
326
+
327
+ await user . tab ( { shift : true } )
328
+ expect ( document . activeElement ) . not . toEqual ( newLastButton )
329
+ expect ( trapContainer . lastElementChild ) . toEqual ( newLastButton )
330
+ } )
0 commit comments