@@ -30,6 +30,7 @@ let React;
30
30
let ReactDOMClient ;
31
31
let ReactServerDOMWriter ;
32
32
let ReactServerDOMReader ;
33
+ let Suspense ;
33
34
34
35
describe ( 'ReactFlightDOM' , ( ) => {
35
36
beforeEach ( ( ) => {
@@ -42,6 +43,7 @@ describe('ReactFlightDOM', () => {
42
43
ReactDOMClient = require ( 'react-dom/client' ) ;
43
44
ReactServerDOMWriter = require ( 'react-server-dom-webpack/writer.node.server' ) ;
44
45
ReactServerDOMReader = require ( 'react-server-dom-webpack' ) ;
46
+ Suspense = React . Suspense ;
45
47
} ) ;
46
48
47
49
function getTestStream ( ) {
@@ -92,6 +94,11 @@ describe('ReactFlightDOM', () => {
92
94
}
93
95
}
94
96
97
+ const theInfinitePromise = new Promise ( ( ) => { } ) ;
98
+ function InfiniteSuspend ( ) {
99
+ throw theInfinitePromise ;
100
+ }
101
+
95
102
it ( 'should resolve HTML using Node streams' , async ( ) => {
96
103
function Text ( { children} ) {
97
104
return < span > { children } </ span > ;
@@ -133,8 +140,6 @@ describe('ReactFlightDOM', () => {
133
140
} ) ;
134
141
135
142
it ( 'should resolve the root' , async ( ) => {
136
- const { Suspense} = React ;
137
-
138
143
// Model
139
144
function Text ( { children} ) {
140
145
return < span > { children } </ span > ;
@@ -184,8 +189,6 @@ describe('ReactFlightDOM', () => {
184
189
} ) ;
185
190
186
191
it ( 'should not get confused by $' , async ( ) => {
187
- const { Suspense} = React ;
188
-
189
192
// Model
190
193
function RootModel ( ) {
191
194
return { text : '$1' } ;
@@ -220,8 +223,6 @@ describe('ReactFlightDOM', () => {
220
223
} ) ;
221
224
222
225
it ( 'should not get confused by @' , async ( ) => {
223
- const { Suspense} = React ;
224
-
225
226
// Model
226
227
function RootModel ( ) {
227
228
return { text : '@div' } ;
@@ -257,7 +258,6 @@ describe('ReactFlightDOM', () => {
257
258
258
259
it ( 'should progressively reveal server components' , async ( ) => {
259
260
let reportedErrors = [ ] ;
260
- const { Suspense} = React ;
261
261
262
262
// Client Components
263
263
@@ -460,8 +460,6 @@ describe('ReactFlightDOM', () => {
460
460
} ) ;
461
461
462
462
it ( 'should preserve state of client components on refetch' , async ( ) => {
463
- const { Suspense} = React ;
464
-
465
463
// Client
466
464
467
465
function Page ( { response} ) {
@@ -545,4 +543,64 @@ describe('ReactFlightDOM', () => {
545
543
expect ( inputB . tagName ) . toBe ( 'INPUT' ) ;
546
544
expect ( inputB . value ) . toBe ( 'goodbye' ) ;
547
545
} ) ;
546
+
547
+ it ( 'should be able to complete after aborting and throw the reason client-side' , async ( ) => {
548
+ const reportedErrors = [ ] ;
549
+
550
+ class ErrorBoundary extends React . Component {
551
+ state = { hasError : false , error : null } ;
552
+ static getDerivedStateFromError ( error ) {
553
+ return {
554
+ hasError : true ,
555
+ error,
556
+ } ;
557
+ }
558
+ render ( ) {
559
+ if ( this . state . hasError ) {
560
+ return this . props . fallback ( this . state . error ) ;
561
+ }
562
+ return this . props . children ;
563
+ }
564
+ }
565
+
566
+ const { writable, readable} = getTestStream ( ) ;
567
+ const { pipe, abort} = ReactServerDOMWriter . renderToPipeableStream (
568
+ < div >
569
+ < InfiniteSuspend />
570
+ </ div > ,
571
+ webpackMap ,
572
+ {
573
+ onError ( x ) {
574
+ reportedErrors . push ( x ) ;
575
+ } ,
576
+ } ,
577
+ ) ;
578
+ pipe ( writable ) ;
579
+ const response = ReactServerDOMReader . createFromReadableStream ( readable ) ;
580
+
581
+ const container = document . createElement ( 'div' ) ;
582
+ const root = ReactDOMClient . createRoot ( container ) ;
583
+
584
+ function App ( { res} ) {
585
+ return res . readRoot ( ) ;
586
+ }
587
+
588
+ await act ( async ( ) => {
589
+ root . render (
590
+ < ErrorBoundary fallback = { e => < p > { e . message } </ p > } >
591
+ < Suspense fallback = { < p > (loading)</ p > } >
592
+ < App res = { response } />
593
+ </ Suspense >
594
+ </ ErrorBoundary > ,
595
+ ) ;
596
+ } ) ;
597
+ expect ( container . innerHTML ) . toBe ( '<p>(loading)</p>' ) ;
598
+
599
+ await act ( async ( ) => {
600
+ abort ( 'for reasons' ) ;
601
+ } ) ;
602
+ expect ( container . innerHTML ) . toBe ( '<p>Error: for reasons</p>' ) ;
603
+
604
+ expect ( reportedErrors ) . toEqual ( [ 'for reasons' ] ) ;
605
+ } ) ;
548
606
} ) ;
0 commit comments