@@ -440,4 +440,92 @@ describe('ReactFlightDOM', () => {
440440 '<p>Game over</p>' , // TODO: should not have message in prod.
441441 ) ;
442442 } ) ;
443+
444+ // @gate experimental
445+ it ( 'should preserve state of client components on refetch' , async ( ) => {
446+ const { Suspense} = React ;
447+
448+ // Client
449+
450+ function Page ( { response} ) {
451+ return response . readRoot ( ) ;
452+ }
453+
454+ function Input ( ) {
455+ return < input /> ;
456+ }
457+
458+ const InputClient = moduleReference ( Input ) ;
459+
460+ // Server
461+
462+ function App ( { color} ) {
463+ // Verify both DOM and Client children.
464+ return (
465+ < div style = { { color} } >
466+ < input />
467+ < InputClient />
468+ </ div >
469+ ) ;
470+ }
471+
472+ const container = document . createElement ( 'div' ) ;
473+ const root = ReactDOM . unstable_createRoot ( container ) ;
474+
475+ const stream1 = getTestStream ( ) ;
476+ ReactTransportDOMServer . pipeToNodeWritable (
477+ < App color = "red" /> ,
478+ stream1 . writable ,
479+ webpackMap ,
480+ ) ;
481+ const response1 = ReactTransportDOMClient . createFromReadableStream (
482+ stream1 . readable ,
483+ ) ;
484+ await act ( async ( ) => {
485+ root . render (
486+ < Suspense fallback = { < p > (loading)</ p > } >
487+ < Page response = { response1 } />
488+ </ Suspense > ,
489+ ) ;
490+ } ) ;
491+ expect ( container . children . length ) . toBe ( 1 ) ;
492+ expect ( container . children [ 0 ] . tagName ) . toBe ( 'DIV' ) ;
493+ expect ( container . children [ 0 ] . style . color ) . toBe ( 'red' ) ;
494+
495+ // Change the DOM state for both inputs.
496+ const inputA = container . children [ 0 ] . children [ 0 ] ;
497+ expect ( inputA . tagName ) . toBe ( 'INPUT' ) ;
498+ inputA . value = 'hello' ;
499+ const inputB = container . children [ 0 ] . children [ 1 ] ;
500+ expect ( inputB . tagName ) . toBe ( 'INPUT' ) ;
501+ inputB . value = 'goodbye' ;
502+
503+ const stream2 = getTestStream ( ) ;
504+ ReactTransportDOMServer . pipeToNodeWritable (
505+ < App color = "blue" /> ,
506+ stream2 . writable ,
507+ webpackMap ,
508+ ) ;
509+ const response2 = ReactTransportDOMClient . createFromReadableStream (
510+ stream2 . readable ,
511+ ) ;
512+ await act ( async ( ) => {
513+ root . render (
514+ < Suspense fallback = { < p > (loading)</ p > } >
515+ < Page response = { response2 } />
516+ </ Suspense > ,
517+ ) ;
518+ } ) ;
519+ expect ( container . children . length ) . toBe ( 1 ) ;
520+ expect ( container . children [ 0 ] . tagName ) . toBe ( 'DIV' ) ;
521+ expect ( container . children [ 0 ] . style . color ) . toBe ( 'blue' ) ;
522+
523+ // Verify we didn't destroy the DOM for either input.
524+ expect ( inputA === container . children [ 0 ] . children [ 0 ] ) . toBe ( true ) ;
525+ expect ( inputA . tagName ) . toBe ( 'INPUT' ) ;
526+ expect ( inputA . value ) . toBe ( 'hello' ) ;
527+ expect ( inputB === container . children [ 0 ] . children [ 1 ] ) . toBe ( true ) ;
528+ expect ( inputB . tagName ) . toBe ( 'INPUT' ) ;
529+ expect ( inputB . value ) . toBe ( 'goodbye' ) ;
530+ } ) ;
443531} ) ;
0 commit comments