@@ -2247,14 +2247,11 @@ describe('ReactDOMFizzServer', () => {
2247
2247
) ;
2248
2248
}
2249
2249
await act ( async ( ) => {
2250
- const { pipe} = ReactDOMFizzServer . renderToPipeableStream (
2251
- < App fallbackText = "Loading..." /> ,
2252
- {
2253
- onError ( error ) {
2254
- Scheduler . unstable_yieldValue ( '[s!] ' + error . message ) ;
2255
- } ,
2250
+ const { pipe} = ReactDOMFizzServer . renderToPipeableStream ( < App /> , {
2251
+ onError ( error ) {
2252
+ Scheduler . unstable_yieldValue ( '[s!] ' + error . message ) ;
2256
2253
} ,
2257
- ) ;
2254
+ } ) ;
2258
2255
pipe ( writable ) ;
2259
2256
} ) ;
2260
2257
expect ( Scheduler ) . toHaveYielded ( [ '[s!] Oops.' ] ) ;
@@ -2302,6 +2299,102 @@ describe('ReactDOMFizzServer', () => {
2302
2299
) ;
2303
2300
} ) ;
2304
2301
2302
+ // @gate experimental
2303
+ it (
2304
+ 'does not recreate the fallback if server errors and hydration suspends ' +
2305
+ 'and root receives a transition' ,
2306
+ async ( ) => {
2307
+ let isClient = false ;
2308
+
2309
+ function Child ( { color} ) {
2310
+ if ( isClient ) {
2311
+ readText ( 'Yay!' ) ;
2312
+ } else {
2313
+ throw Error ( 'Oops.' ) ;
2314
+ }
2315
+ Scheduler . unstable_yieldValue ( 'Yay! (' + color + ')' ) ;
2316
+ return 'Yay! (' + color + ')' ;
2317
+ }
2318
+
2319
+ const fallbackRef = React . createRef ( ) ;
2320
+ function App ( { color} ) {
2321
+ return (
2322
+ < div >
2323
+ < Suspense fallback = { < p ref = { fallbackRef } > Loading...</ p > } >
2324
+ < span >
2325
+ < Child color = { color } />
2326
+ </ span >
2327
+ </ Suspense >
2328
+ </ div >
2329
+ ) ;
2330
+ }
2331
+ await act ( async ( ) => {
2332
+ const { pipe} = ReactDOMFizzServer . renderToPipeableStream (
2333
+ < App color = "red" /> ,
2334
+ {
2335
+ onError ( error ) {
2336
+ Scheduler . unstable_yieldValue ( '[s!] ' + error . message ) ;
2337
+ } ,
2338
+ } ,
2339
+ ) ;
2340
+ pipe ( writable ) ;
2341
+ } ) ;
2342
+ expect ( Scheduler ) . toHaveYielded ( [ '[s!] Oops.' ] ) ;
2343
+
2344
+ // The server could not complete this boundary, so we'll retry on the client.
2345
+ const serverFallback = container . getElementsByTagName ( 'p' ) [ 0 ] ;
2346
+ expect ( serverFallback . innerHTML ) . toBe ( 'Loading...' ) ;
2347
+
2348
+ // Hydrate the tree. This will suspend.
2349
+ isClient = true ;
2350
+ const root = ReactDOMClient . hydrateRoot ( container , < App color = "red" /> , {
2351
+ onRecoverableError ( error ) {
2352
+ Scheduler . unstable_yieldValue ( '[c!] ' + error . message ) ;
2353
+ } ,
2354
+ } ) ;
2355
+ // This should not report any errors yet.
2356
+ expect ( Scheduler ) . toFlushAndYield ( [ ] ) ;
2357
+ expect ( getVisibleChildren ( container ) ) . toEqual (
2358
+ < div >
2359
+ < p > Loading...</ p >
2360
+ </ div > ,
2361
+ ) ;
2362
+
2363
+ // Normally, hydrating after server error would force a clean client render.
2364
+ // However, it suspended so at best we'd only get the same fallback anyway.
2365
+ // We don't want to recreate the same fallback in the DOM again because
2366
+ // that's extra work and would restart animations etc. Check we don't do that.
2367
+ const clientFallback = container . getElementsByTagName ( 'p' ) [ 0 ] ;
2368
+ expect ( serverFallback ) . toBe ( clientFallback ) ;
2369
+
2370
+ // Transition updates shouldn't recreate the fallback either.
2371
+ React . startTransition ( ( ) => {
2372
+ root . render ( < App color = "blue" /> ) ;
2373
+ } ) ;
2374
+ Scheduler . unstable_flushAll ( ) ;
2375
+ jest . runAllTimers ( ) ;
2376
+ const clientFallback2 = container . getElementsByTagName ( 'p' ) [ 0 ] ;
2377
+ expect ( clientFallback2 ) . toBe ( serverFallback ) ;
2378
+
2379
+ // When we're able to fully hydrate, we expect a clean client render.
2380
+ await act ( async ( ) => {
2381
+ resolveText ( 'Yay!' ) ;
2382
+ } ) ;
2383
+ expect ( Scheduler ) . toFlushAndYield ( [
2384
+ 'Yay! (red)' ,
2385
+ '[c!] The server could not finish this Suspense boundary, ' +
2386
+ 'likely due to an error during server rendering. ' +
2387
+ 'Switched to client rendering.' ,
2388
+ 'Yay! (blue)' ,
2389
+ ] ) ;
2390
+ expect ( getVisibleChildren ( container ) ) . toEqual (
2391
+ < div >
2392
+ < span > Yay! (blue)</ span >
2393
+ </ div > ,
2394
+ ) ;
2395
+ } ,
2396
+ ) ;
2397
+
2305
2398
// @gate experimental
2306
2399
it (
2307
2400
'recreates the fallback if server errors and hydration suspends but ' +
0 commit comments