@@ -138,6 +138,213 @@ describe('ReactFlight', () => {
138138 expect ( ReactNoop ) . toMatchRenderedOutput ( < span > Hello, Seb Smith</ span > ) ;
139139 } ) ;
140140
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+
141348 it ( 'should error if a non-serializable value is passed to a host component' , ( ) => {
142349 function EventHandlerProp ( ) {
143350 return (
0 commit comments