@@ -17,6 +17,7 @@ let Scheduler;
1717let  ReactFeatureFlags ; 
1818let  Suspense ; 
1919let  SuspenseList ; 
20+ let  Offscreen ; 
2021let  act ; 
2122let  IdleEventPriority ; 
2223
@@ -106,6 +107,7 @@ describe('ReactDOMServerPartialHydration', () => {
106107    ReactDOMServer  =  require ( 'react-dom/server' ) ; 
107108    Scheduler  =  require ( 'scheduler' ) ; 
108109    Suspense  =  React . Suspense ; 
110+     Offscreen  =  React . unstable_Offscreen ; 
109111    if  ( gate ( flags  =>  flags . enableSuspenseList ) )  { 
110112      SuspenseList  =  React . SuspenseList ; 
111113    } 
@@ -3283,6 +3285,103 @@ describe('ReactDOMServerPartialHydration', () => {
32833285    expect ( ref . current . innerHTML ) . toBe ( 'Hidden child' ) ; 
32843286  } ) ; 
32853287
3288+   // @gate  enableOffscreen 
3289+   it ( 'a visible Offscreen component acts like a fragment' ,  async  ( )  =>  { 
3290+     const  ref  =  React . createRef ( ) ; 
3291+ 
3292+     function  App ( )  { 
3293+       return  ( 
3294+         < Offscreen  mode = "visible" > 
3295+           < span  ref = { ref } > Child</ span > 
3296+         </ Offscreen > 
3297+       ) ; 
3298+     } 
3299+ 
3300+     const  finalHTML  =  ReactDOMServer . renderToString ( < App  /> ) ; 
3301+     expect ( Scheduler ) . toHaveYielded ( [ ] ) ; 
3302+ 
3303+     const  container  =  document . createElement ( 'div' ) ; 
3304+     container . innerHTML  =  finalHTML ; 
3305+ 
3306+     // Visible Offscreen boundaries behave exactly like fragments: a 
3307+     // pure indirection. 
3308+     expect ( container ) . toMatchInlineSnapshot ( ` 
3309+       <div> 
3310+         <span> 
3311+           Child 
3312+         </span> 
3313+       </div> 
3314+     ` ) ; 
3315+ 
3316+     const  span  =  container . getElementsByTagName ( 'span' ) [ 0 ] ; 
3317+ 
3318+     // The tree successfully hydrates 
3319+     ReactDOMClient . hydrateRoot ( container ,  < App  /> ) ; 
3320+     expect ( Scheduler ) . toFlushAndYield ( [ ] ) ; 
3321+     expect ( ref . current ) . toBe ( span ) ; 
3322+   } ) ; 
3323+ 
3324+   // @gate  enableOffscreen 
3325+   it ( 'a hidden Offscreen component is skipped over during server rendering' ,  async  ( )  =>  { 
3326+     const  visibleRef  =  React . createRef ( ) ; 
3327+ 
3328+     function  HiddenChild ( )  { 
3329+       Scheduler . unstable_yieldValue ( 'HiddenChild' ) ; 
3330+       return  < span > Hidden</ span > ; 
3331+     } 
3332+ 
3333+     function  App ( )  { 
3334+       Scheduler . unstable_yieldValue ( 'App' ) ; 
3335+       return  ( 
3336+         < > 
3337+           < span  ref = { visibleRef } > Visible</ span > 
3338+           < Offscreen  mode = "hidden" > 
3339+             < HiddenChild  /> 
3340+           </ Offscreen > 
3341+         </ > 
3342+       ) ; 
3343+     } 
3344+ 
3345+     // During server rendering, the Child component should not be evaluated, 
3346+     // because it's inside a hidden tree. 
3347+     const  finalHTML  =  ReactDOMServer . renderToString ( < App  /> ) ; 
3348+     expect ( Scheduler ) . toHaveYielded ( [ 'App' ] ) ; 
3349+ 
3350+     const  container  =  document . createElement ( 'div' ) ; 
3351+     container . innerHTML  =  finalHTML ; 
3352+ 
3353+     // The hidden child is not part of the server rendered HTML 
3354+     expect ( container ) . toMatchInlineSnapshot ( ` 
3355+       <div> 
3356+         <span> 
3357+           Visible 
3358+         </span> 
3359+       </div> 
3360+     ` ) ; 
3361+ 
3362+     const  visibleSpan  =  container . getElementsByTagName ( 'span' ) [ 0 ] ; 
3363+ 
3364+     // The visible span successfully hydrates 
3365+     ReactDOMClient . hydrateRoot ( container ,  < App  /> ) ; 
3366+     expect ( Scheduler ) . toFlushUntilNextPaint ( [ 'App' ] ) ; 
3367+     expect ( visibleRef . current ) . toBe ( visibleSpan ) ; 
3368+ 
3369+     // Subsequently, the hidden child is prerendered on the client 
3370+     expect ( Scheduler ) . toFlushUntilNextPaint ( [ 'HiddenChild' ] ) ; 
3371+     expect ( container ) . toMatchInlineSnapshot ( ` 
3372+       <div> 
3373+         <span> 
3374+           Visible 
3375+         </span> 
3376+         <span 
3377+           style="display: none;" 
3378+         > 
3379+           Hidden 
3380+         </span> 
3381+       </div> 
3382+     ` ) ; 
3383+   } ) ; 
3384+ 
32863385  function  itHydratesWithoutMismatch ( msg ,  App )  { 
32873386    it ( 'hydrates without mismatch '  +  msg ,  ( )  =>  { 
32883387      const  container  =  document . createElement ( 'div' ) ; 
0 commit comments