@@ -103,6 +103,7 @@ describe('ReactDOMFizzServer', () => {
103103 if (
104104 node . tagName !== 'SCRIPT' &&
105105 node . tagName !== 'TEMPLATE' &&
106+ node . tagName !== 'template' &&
106107 ! node . hasAttribute ( 'hidden' ) &&
107108 ! node . hasAttribute ( 'aria-hidden' )
108109 ) {
@@ -153,7 +154,6 @@ describe('ReactDOMFizzServer', () => {
153154 }
154155 }
155156
156- /*
157157 function rejectText ( text , error ) {
158158 const record = textCache . get ( text ) ;
159159 if ( record === undefined ) {
@@ -169,7 +169,6 @@ describe('ReactDOMFizzServer', () => {
169169 thenable . pings . forEach ( t => t ( ) ) ;
170170 }
171171 }
172- */
173172
174173 function readText ( text ) {
175174 const record = textCache . get ( text ) ;
@@ -800,4 +799,79 @@ describe('ReactDOMFizzServer', () => {
800799 </ div > ,
801800 ) ;
802801 } ) ;
802+
803+ it ( 'client renders a boundary if it errors before finishing the fallback' , async ( ) => {
804+ function App ( { isClient} ) {
805+ return (
806+ < Suspense fallback = "Loading root..." >
807+ < div >
808+ < Suspense fallback = { < AsyncText text = "Loading..." /> } >
809+ < h1 >
810+ { isClient ? < Text text = "Hello" /> : < AsyncText text = "Hello" /> }
811+ </ h1 >
812+ </ Suspense >
813+ </ div >
814+ </ Suspense >
815+ ) ;
816+ }
817+
818+ const loggedErrors = [ ] ;
819+ let controls ;
820+ await act ( async ( ) => {
821+ controls = ReactDOMFizzServer . pipeToNodeWritable (
822+ < App isClient = { false } /> ,
823+ writable ,
824+ {
825+ onError ( x ) {
826+ loggedErrors . push ( x ) ;
827+ } ,
828+ } ,
829+ ) ;
830+ controls . startWriting ( ) ;
831+ } ) ;
832+
833+ // We're still showing a fallback.
834+
835+ // Attempt to hydrate the content.
836+ const root = ReactDOM . unstable_createRoot ( container , { hydrate : true } ) ;
837+ root . render ( < App isClient = { true } /> ) ;
838+ Scheduler . unstable_flushAll ( ) ;
839+
840+ // We're still loading because we're waiting for the server to stream more content.
841+ expect ( getVisibleChildren ( container ) ) . toEqual ( 'Loading root...' ) ;
842+
843+ expect ( loggedErrors ) . toEqual ( [ ] ) ;
844+
845+ const theError = new Error ( 'Test' ) ;
846+ // Error the content, but we don't have a fallback yet.
847+ await act ( async ( ) => {
848+ rejectText ( 'Hello' , theError ) ;
849+ } ) ;
850+
851+ expect ( loggedErrors ) . toEqual ( [ theError ] ) ;
852+
853+ // We still can't render it on the client because we haven't unblocked the parent.
854+ Scheduler . unstable_flushAll ( ) ;
855+ expect ( getVisibleChildren ( container ) ) . toEqual ( 'Loading root...' ) ;
856+
857+ // Unblock the loading state
858+ await act ( async ( ) => {
859+ resolveText ( 'Loading...' ) ;
860+ } ) ;
861+
862+ // Now we're able to show the inner boundary.
863+ expect ( getVisibleChildren ( container ) ) . toEqual ( < div > Loading...</ div > ) ;
864+
865+ // That will let us client render it instead.
866+ Scheduler . unstable_flushAll ( ) ;
867+
868+ // The client rendered HTML is now in place.
869+ expect ( getVisibleChildren ( container ) ) . toEqual (
870+ < div >
871+ < h1 > Hello</ h1 >
872+ </ div > ,
873+ ) ;
874+
875+ expect ( loggedErrors ) . toEqual ( [ theError ] ) ;
876+ } ) ;
803877} ) ;
0 commit comments