@@ -201,14 +201,7 @@ describe('ReactOffscreen', () => {
201
201
} ) ;
202
202
// No layout effect.
203
203
expect ( Scheduler ) . toHaveYielded ( [ 'Child' ] ) ;
204
- if ( gate ( flags => flags . persistent ) ) {
205
- expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } prop = "Child" /> ) ;
206
- } else {
207
- // TODO: Offscreen does not yet hide/unhide children correctly in mutation
208
- // mode. Until we do, it should only be used inside a host component
209
- // wrapper whose visibility is toggled simultaneously.
210
- expect ( root ) . toMatchRenderedOutput ( < span prop = "Child" /> ) ;
211
- }
204
+ expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } prop = "Child" /> ) ;
212
205
213
206
// Unhide the tree. The layout effect is mounted.
214
207
await act ( async ( ) => {
@@ -255,14 +248,7 @@ describe('ReactOffscreen', () => {
255
248
) ;
256
249
} ) ;
257
250
expect ( Scheduler ) . toHaveYielded ( [ 'Unmount layout' , 'Child' ] ) ;
258
- if ( gate ( flags => flags . persistent ) ) {
259
- expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } prop = "Child" /> ) ;
260
- } else {
261
- // TODO: Offscreen does not yet hide/unhide children correctly in mutation
262
- // mode. Until we do, it should only be used inside a host component
263
- // wrapper whose visibility is toggled simultaneously.
264
- expect ( root ) . toMatchRenderedOutput ( < span prop = "Child" /> ) ;
265
- }
251
+ expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } prop = "Child" /> ) ;
266
252
267
253
// Unhide the tree. The layout effect is re-mounted.
268
254
await act ( async ( ) => {
@@ -299,14 +285,7 @@ describe('ReactOffscreen', () => {
299
285
) ;
300
286
} ) ;
301
287
expect ( Scheduler ) . toHaveYielded ( [ 'Child' ] ) ;
302
- if ( gate ( flags => flags . persistent ) ) {
303
- expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } prop = "Child" /> ) ;
304
- } else {
305
- // TODO: Offscreen does not yet hide/unhide children correctly in mutation
306
- // mode. Until we do, it should only be used inside a host component
307
- // wrapper whose visibility is toggled simultaneously.
308
- expect ( root ) . toMatchRenderedOutput ( < span prop = "Child" /> ) ;
309
- }
288
+ expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } prop = "Child" /> ) ;
310
289
311
290
// Show the tree. The layout effect is mounted.
312
291
await act ( async ( ) => {
@@ -328,14 +307,7 @@ describe('ReactOffscreen', () => {
328
307
) ;
329
308
} ) ;
330
309
expect ( Scheduler ) . toHaveYielded ( [ 'Unmount layout' , 'Child' ] ) ;
331
- if ( gate ( flags => flags . persistent ) ) {
332
- expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } prop = "Child" /> ) ;
333
- } else {
334
- // TODO: Offscreen does not yet hide/unhide children correctly in mutation
335
- // mode. Until we do, it should only be used inside a host component
336
- // wrapper whose visibility is toggled simultaneously.
337
- expect ( root ) . toMatchRenderedOutput ( < span prop = "Child" /> ) ;
338
- }
310
+ expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } prop = "Child" /> ) ;
339
311
} ) ;
340
312
341
313
// @gate experimental || www
@@ -385,4 +357,78 @@ describe('ReactOffscreen', () => {
385
357
} ) ;
386
358
expect ( Scheduler ) . toHaveYielded ( [ 'Unmount layout' ] ) ;
387
359
} ) ;
360
+
361
+ it ( 'hides new insertions into an already hidden tree' , async ( ) => {
362
+ const root = ReactNoop . createRoot ( ) ;
363
+ await act ( async ( ) => {
364
+ root . render (
365
+ < Offscreen mode = "hidden" >
366
+ < span > Hi</ span >
367
+ </ Offscreen > ,
368
+ ) ;
369
+ } ) ;
370
+ expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } > Hi</ span > ) ;
371
+
372
+ // Insert a new node into the hidden tree
373
+ await act ( async ( ) => {
374
+ root . render (
375
+ < Offscreen mode = "hidden" >
376
+ < span > Hi</ span >
377
+ < span > Something new</ span >
378
+ </ Offscreen > ,
379
+ ) ;
380
+ } ) ;
381
+ expect ( root ) . toMatchRenderedOutput (
382
+ < >
383
+ < span hidden = { true } > Hi</ span >
384
+ { /* This new node should also be hidden */ }
385
+ < span hidden = { true } > Something new</ span >
386
+ </ > ,
387
+ ) ;
388
+ } ) ;
389
+
390
+ it ( 'hides updated nodes inside an already hidden tree' , async ( ) => {
391
+ const root = ReactNoop . createRoot ( ) ;
392
+ await act ( async ( ) => {
393
+ root . render (
394
+ < Offscreen mode = "hidden" >
395
+ < span > Hi</ span >
396
+ </ Offscreen > ,
397
+ ) ;
398
+ } ) ;
399
+ expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } > Hi</ span > ) ;
400
+
401
+ // Set the `hidden` prop to on an already hidden node
402
+ await act ( async ( ) => {
403
+ root . render (
404
+ < Offscreen mode = "hidden" >
405
+ < span hidden = { false } > Hi</ span >
406
+ </ Offscreen > ,
407
+ ) ;
408
+ } ) ;
409
+ // It should still be hidden, because the Offscreen container overrides it
410
+ expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } > Hi</ span > ) ;
411
+
412
+ // Unhide the boundary
413
+ await act ( async ( ) => {
414
+ root . render (
415
+ < Offscreen mode = "visible" >
416
+ < span hidden = { true } > Hi</ span >
417
+ </ Offscreen > ,
418
+ ) ;
419
+ } ) ;
420
+ // It should still be hidden, because of the prop
421
+ expect ( root ) . toMatchRenderedOutput ( < span hidden = { true } > Hi</ span > ) ;
422
+
423
+ // Remove the `hidden` prop
424
+ await act ( async ( ) => {
425
+ root . render (
426
+ < Offscreen mode = "visible" >
427
+ < span > Hi</ span >
428
+ </ Offscreen > ,
429
+ ) ;
430
+ } ) ;
431
+ // Now it's visible
432
+ expect ( root ) . toMatchRenderedOutput ( < span > Hi</ span > ) ;
433
+ } ) ;
388
434
} ) ;
0 commit comments