@@ -18,6 +18,7 @@ let ReactNoop;
1818let  ReactNoopFlightServer ; 
1919let  ReactNoopFlightServerRuntime ; 
2020let  ReactNoopFlightClient ; 
21+ let  ErrorBoundary ; 
2122
2223describe ( 'ReactFlight' ,  ( )  =>  { 
2324  beforeEach ( ( )  =>  { 
@@ -29,6 +30,27 @@ describe('ReactFlight', () => {
2930    ReactNoopFlightServerRuntime  =  require ( 'react-noop-renderer/flight-server-runtime' ) ; 
3031    ReactNoopFlightClient  =  require ( 'react-noop-renderer/flight-client' ) ; 
3132    act  =  ReactNoop . act ; 
33+ 
34+     ErrorBoundary  =  class  extends  React . Component  { 
35+       state  =  { hasError : false ,  error : null } ; 
36+       static  getDerivedStateFromError ( error )  { 
37+         return  { 
38+           hasError : true , 
39+           error, 
40+         } ; 
41+       } 
42+       componentDidMount ( )  { 
43+         expect ( this . state . hasError ) . toBe ( true ) ; 
44+         expect ( this . state . error ) . toBeTruthy ( ) ; 
45+         expect ( this . state . error . message ) . toContain ( this . props . expectedMessage ) ; 
46+       } 
47+       render ( )  { 
48+         if  ( this . state . hasError )  { 
49+           return  this . state . error . message ; 
50+         } 
51+         return  this . props . children ; 
52+       } 
53+     } ; 
3254  } ) ; 
3355
3456  function  block ( render ,  load )  { 
@@ -127,4 +149,103 @@ describe('ReactFlight', () => {
127149      expect ( ReactNoop ) . toMatchRenderedOutput ( < span > Hello, Seb Smith</ span > ) ; 
128150    } ) ; 
129151  } 
152+ 
153+   it ( 'should error if a non-serializable value is passed to a host component' ,  ( )  =>  { 
154+     function  EventHandlerProp ( )  { 
155+       return  ( 
156+         < div  className = "foo"  onClick = { function ( )  { } } > 
157+           Test
158+         </ div > 
159+       ) ; 
160+     } 
161+     function  FunctionProp ( )  { 
162+       return  < div > { ( )  =>  { } } </ div > ; 
163+     } 
164+     function  SymbolProp ( )  { 
165+       return  < div  foo = { Symbol ( 'foo' ) }  /> ; 
166+     } 
167+ 
168+     const  event  =  ReactNoopFlightServer . render ( < EventHandlerProp  /> ) ; 
169+     const  fn  =  ReactNoopFlightServer . render ( < FunctionProp  /> ) ; 
170+     const  symbol  =  ReactNoopFlightServer . render ( < SymbolProp  /> ) ; 
171+ 
172+     function  Client ( { transport} )  { 
173+       return  ReactNoopFlightClient . read ( transport ) ; 
174+     } 
175+ 
176+     act ( ( )  =>  { 
177+       ReactNoop . render ( 
178+         < > 
179+           < ErrorBoundary  expectedMessage = "Event handlers cannot be passed to client component props." > 
180+             < Client  transport = { event }  /> 
181+           </ ErrorBoundary > 
182+           < ErrorBoundary  expectedMessage = "Functions cannot be passed directly to client components because they're not serializable." > 
183+             < Client  transport = { fn }  /> 
184+           </ ErrorBoundary > 
185+           < ErrorBoundary  expectedMessage = "Symbol values (foo) cannot be passed to client components." > 
186+             < Client  transport = { symbol }  /> 
187+           </ ErrorBoundary > 
188+         </ > , 
189+       ) ; 
190+     } ) ; 
191+   } ) ; 
192+ 
193+   it ( 'should warn in DEV if a toJSON instance is passed to a host component' ,  ( )  =>  { 
194+     expect ( ( )  =>  { 
195+       const  transport  =  ReactNoopFlightServer . render ( 
196+         < input  value = { new  Date ( ) }  /> , 
197+       ) ; 
198+       act ( ( )  =>  { 
199+         ReactNoop . render ( ReactNoopFlightClient . read ( transport ) ) ; 
200+       } ) ; 
201+     } ) . toErrorDev ( 
202+       'Only plain objects can be passed to client components from server components. ' , 
203+       { withoutStack : true } , 
204+     ) ; 
205+   } ) ; 
206+ 
207+   it ( 'should warn in DEV if a special object is passed to a host component' ,  ( )  =>  { 
208+     expect ( ( )  =>  { 
209+       const  transport  =  ReactNoopFlightServer . render ( < input  value = { Math }  /> ) ; 
210+       act ( ( )  =>  { 
211+         ReactNoop . render ( ReactNoopFlightClient . read ( transport ) ) ; 
212+       } ) ; 
213+     } ) . toErrorDev ( 
214+       'Only plain objects can be passed to client components from server components. '  + 
215+         'Built-ins like Math are not supported.' , 
216+       { withoutStack : true } , 
217+     ) ; 
218+   } ) ; 
219+ 
220+   it ( 'should warn in DEV if an object with symbols is passed to a host component' ,  ( )  =>  { 
221+     expect ( ( )  =>  { 
222+       const  transport  =  ReactNoopFlightServer . render ( 
223+         < input  value = { { [ Symbol . iterator ] : { } } }  /> , 
224+       ) ; 
225+       act ( ( )  =>  { 
226+         ReactNoop . render ( ReactNoopFlightClient . read ( transport ) ) ; 
227+       } ) ; 
228+     } ) . toErrorDev ( 
229+       'Only plain objects can be passed to client components from server components. '  + 
230+         'Objects with symbol properties like Symbol.iterator are not supported.' , 
231+       { withoutStack : true } , 
232+     ) ; 
233+   } ) ; 
234+ 
235+   it ( 'should warn in DEV if a class instance is passed to a host component' ,  ( )  =>  { 
236+     class  Foo  { 
237+       method ( )  { } 
238+     } 
239+     expect ( ( )  =>  { 
240+       const  transport  =  ReactNoopFlightServer . render ( 
241+         < input  value = { new  Foo ( ) }  /> , 
242+       ) ; 
243+       act ( ( )  =>  { 
244+         ReactNoop . render ( ReactNoopFlightClient . read ( transport ) ) ; 
245+       } ) ; 
246+     } ) . toErrorDev ( 
247+       'Only plain objects can be passed to client components from server components. ' , 
248+       { withoutStack : true } , 
249+     ) ; 
250+   } ) ; 
130251} ) ; 
0 commit comments