@@ -138,6 +138,213 @@ describe('ReactFlight', () => {
138
138
expect ( ReactNoop ) . toMatchRenderedOutput ( < span > Hello, Seb Smith</ span > ) ;
139
139
} ) ;
140
140
141
+ it ( 'can render a lazy component as a shared component on the server' , async ( ) => {
142
+ function SharedComponent ( { text} ) {
143
+ return (
144
+ < div >
145
+ shared< span > { text } </ span >
146
+ </ div >
147
+ ) ;
148
+ }
149
+
150
+ let load = null ;
151
+ const loadSharedComponent = ( ) => {
152
+ return new Promise ( res => {
153
+ load = ( ) => res ( { default : SharedComponent } ) ;
154
+ } ) ;
155
+ } ;
156
+
157
+ const LazySharedComponent = React . lazy ( loadSharedComponent ) ;
158
+
159
+ function ServerComponent ( ) {
160
+ return (
161
+ < React . Suspense fallback = { 'Loading...' } >
162
+ < LazySharedComponent text = { 'a' } />
163
+ </ React . Suspense >
164
+ ) ;
165
+ }
166
+
167
+ const transport = ReactNoopFlightServer . render ( < ServerComponent /> ) ;
168
+
169
+ act ( ( ) => {
170
+ const rootModel = ReactNoopFlightClient . read ( transport ) ;
171
+ ReactNoop . render ( rootModel ) ;
172
+ } ) ;
173
+ expect ( ReactNoop ) . toMatchRenderedOutput ( 'Loading...' ) ;
174
+ await load ( ) ;
175
+
176
+ act ( ( ) => {
177
+ const rootModel = ReactNoopFlightClient . read ( transport ) ;
178
+ ReactNoop . render ( rootModel ) ;
179
+ } ) ;
180
+ expect ( ReactNoop ) . toMatchRenderedOutput (
181
+ < div >
182
+ shared< span > a</ span >
183
+ </ div > ,
184
+ ) ;
185
+ } ) ;
186
+
187
+ it ( 'errors on a Lazy element being used in Component position' , async ( ) => {
188
+ function SharedComponent ( { text} ) {
189
+ return (
190
+ < div >
191
+ shared< span > { text } </ span >
192
+ </ div >
193
+ ) ;
194
+ }
195
+
196
+ let load = null ;
197
+
198
+ const LazyElementDisguisedAsComponent = React . lazy ( ( ) => {
199
+ return new Promise ( res => {
200
+ load = ( ) => res ( { default : < SharedComponent text = { 'a' } /> } ) ;
201
+ } ) ;
202
+ } ) ;
203
+
204
+ function ServerComponent ( ) {
205
+ return (
206
+ < React . Suspense fallback = { 'Loading...' } >
207
+ < LazyElementDisguisedAsComponent text = { 'b' } />
208
+ </ React . Suspense >
209
+ ) ;
210
+ }
211
+
212
+ const transport = ReactNoopFlightServer . render ( < ServerComponent /> ) ;
213
+
214
+ act ( ( ) => {
215
+ const rootModel = ReactNoopFlightClient . read ( transport ) ;
216
+ ReactNoop . render ( rootModel ) ;
217
+ } ) ;
218
+ expect ( ReactNoop ) . toMatchRenderedOutput ( 'Loading...' ) ;
219
+ spyOnDevAndProd ( console , 'error' ) ;
220
+ await load ( ) ;
221
+ expect ( console . error ) . toHaveBeenCalledTimes ( 1 ) ;
222
+ } ) ;
223
+
224
+ it ( 'can render a lazy element' , async ( ) => {
225
+ function SharedComponent ( { text} ) {
226
+ return (
227
+ < div >
228
+ shared< span > { text } </ span >
229
+ </ div >
230
+ ) ;
231
+ }
232
+
233
+ let load = null ;
234
+
235
+ const lazySharedElement = React . lazy ( ( ) => {
236
+ return new Promise ( res => {
237
+ load = ( ) => res ( { default : < SharedComponent text = { 'a' } /> } ) ;
238
+ } ) ;
239
+ } ) ;
240
+
241
+ function ServerComponent ( ) {
242
+ return (
243
+ < React . Suspense fallback = { 'Loading...' } >
244
+ { lazySharedElement }
245
+ </ React . Suspense >
246
+ ) ;
247
+ }
248
+
249
+ const transport = ReactNoopFlightServer . render ( < ServerComponent /> ) ;
250
+
251
+ act ( ( ) => {
252
+ const rootModel = ReactNoopFlightClient . read ( transport ) ;
253
+ ReactNoop . render ( rootModel ) ;
254
+ } ) ;
255
+ expect ( ReactNoop ) . toMatchRenderedOutput ( 'Loading...' ) ;
256
+ await load ( ) ;
257
+
258
+ act ( ( ) => {
259
+ const rootModel = ReactNoopFlightClient . read ( transport ) ;
260
+ ReactNoop . render ( rootModel ) ;
261
+ } ) ;
262
+ expect ( ReactNoop ) . toMatchRenderedOutput (
263
+ < div >
264
+ shared< span > a</ span >
265
+ </ div > ,
266
+ ) ;
267
+ } ) ;
268
+
269
+ it ( 'errors with lazy value in element position that resolves to Component' , async ( ) => {
270
+ function SharedComponent ( { text} ) {
271
+ return (
272
+ < div >
273
+ shared< span > { text } </ span >
274
+ </ div >
275
+ ) ;
276
+ }
277
+
278
+ let load = null ;
279
+
280
+ const componentDisguisedAsElement = React . lazy ( ( ) => {
281
+ return new Promise ( res => {
282
+ load = ( ) => res ( { default : SharedComponent } ) ;
283
+ } ) ;
284
+ } ) ;
285
+
286
+ function ServerComponent ( ) {
287
+ return (
288
+ < React . Suspense fallback = { 'Loading...' } >
289
+ { componentDisguisedAsElement }
290
+ </ React . Suspense >
291
+ ) ;
292
+ }
293
+
294
+ const transport = ReactNoopFlightServer . render ( < ServerComponent /> ) ;
295
+
296
+ act ( ( ) => {
297
+ const rootModel = ReactNoopFlightClient . read ( transport ) ;
298
+ ReactNoop . render ( rootModel ) ;
299
+ } ) ;
300
+ expect ( ReactNoop ) . toMatchRenderedOutput ( 'Loading...' ) ;
301
+ spyOnDevAndProd ( console , 'error' ) ;
302
+ await load ( ) ;
303
+ expect ( console . error ) . toHaveBeenCalledTimes ( 1 ) ;
304
+ } ) ;
305
+
306
+ it ( 'can render a lazy module reference' , async ( ) => {
307
+ function ClientComponent ( ) {
308
+ return < div > I am client</ div > ;
309
+ }
310
+
311
+ const ClientComponentReference = moduleReference ( ClientComponent ) ;
312
+
313
+ let load = null ;
314
+ const loadClientComponentReference = ( ) => {
315
+ return new Promise ( res => {
316
+ load = ( ) => res ( { default : ClientComponentReference } ) ;
317
+ } ) ;
318
+ } ;
319
+
320
+ const LazyClientComponentReference = React . lazy (
321
+ loadClientComponentReference ,
322
+ ) ;
323
+
324
+ function ServerComponent ( ) {
325
+ return (
326
+ < React . Suspense fallback = { 'Loading...' } >
327
+ < LazyClientComponentReference />
328
+ </ React . Suspense >
329
+ ) ;
330
+ }
331
+
332
+ const transport = ReactNoopFlightServer . render ( < ServerComponent /> ) ;
333
+
334
+ act ( ( ) => {
335
+ const rootModel = ReactNoopFlightClient . read ( transport ) ;
336
+ ReactNoop . render ( rootModel ) ;
337
+ } ) ;
338
+ expect ( ReactNoop ) . toMatchRenderedOutput ( 'Loading...' ) ;
339
+ await load ( ) ;
340
+
341
+ act ( ( ) => {
342
+ const rootModel = ReactNoopFlightClient . read ( transport ) ;
343
+ ReactNoop . render ( rootModel ) ;
344
+ } ) ;
345
+ expect ( ReactNoop ) . toMatchRenderedOutput ( < div > I am client</ div > ) ;
346
+ } ) ;
347
+
141
348
it ( 'should error if a non-serializable value is passed to a host component' , ( ) => {
142
349
function EventHandlerProp ( ) {
143
350
return (
0 commit comments