@@ -217,14 +217,43 @@ describe('forwardRef', () => {
217
217
) ;
218
218
} ) ;
219
219
220
- it ( 'should honor a displayName if set on the forwardRef wrapper in warnings ' , ( ) => {
220
+ it ( 'should fall back to showing something meaningful if no displayName or name are present ' , ( ) => {
221
221
const Component = props => < div { ...props } /> ;
222
222
223
223
const RefForwardingComponent = React . forwardRef ( ( props , ref ) => (
224
224
< Component { ...props } forwardedRef = { ref } />
225
225
) ) ;
226
226
227
- RefForwardingComponent . displayName = 'Foo' ;
227
+ RefForwardingComponent . propTypes = {
228
+ optional : PropTypes . string ,
229
+ required : PropTypes . string . isRequired ,
230
+ } ;
231
+
232
+ RefForwardingComponent . defaultProps = {
233
+ optional : 'default' ,
234
+ } ;
235
+
236
+ const ref = React . createRef ( ) ;
237
+
238
+ expect ( ( ) =>
239
+ ReactNoop . render ( < RefForwardingComponent ref = { ref } optional = "foo" /> ) ,
240
+ ) . toErrorDev (
241
+ 'Warning: Failed prop type: The prop `required` is marked as required in ' +
242
+ '`ForwardRef`, but its value is `undefined`.' ,
243
+ // There's no component stack in this warning because the inner function is anonymous.
244
+ // If we wanted to support this (for the Error frames / source location)
245
+ // we could do this by updating ReactComponentStackFrame.
246
+ { withoutStack : true } ,
247
+ ) ;
248
+ } ) ;
249
+
250
+ it ( 'should honor a displayName if set on the forwardRef wrapper in warnings' , ( ) => {
251
+ const Component = props => < div { ...props } /> ;
252
+
253
+ const RefForwardingComponent = React . forwardRef ( function Inner ( props , ref ) {
254
+ < Component { ...props } forwardedRef = { ref } /> ;
255
+ } ) ;
256
+ RefForwardingComponent . displayName = 'Custom' ;
228
257
229
258
RefForwardingComponent . propTypes = {
230
259
optional : PropTypes . string ,
@@ -241,17 +270,73 @@ describe('forwardRef', () => {
241
270
ReactNoop . render ( < RefForwardingComponent ref = { ref } optional = "foo" /> ) ,
242
271
) . toErrorDev (
243
272
'Warning: Failed prop type: The prop `required` is marked as required in ' +
244
- '`Foo`, but its value is `undefined`.\n' +
245
- ' in Foo (at **)' ,
273
+ '`Custom`, but its value is `undefined`.\n' +
274
+ ' in Inner (at **)' ,
275
+ ) ;
276
+ } ) ;
277
+
278
+ it ( 'should pass displayName to an anonymous inner component so it shows up in component stacks' , ( ) => {
279
+ const Component = props => < div { ...props } /> ;
280
+
281
+ const RefForwardingComponent = React . forwardRef ( ( props , ref ) => (
282
+ < Component { ...props } forwardedRef = { ref } />
283
+ ) ) ;
284
+ RefForwardingComponent . displayName = 'Custom' ;
285
+
286
+ RefForwardingComponent . propTypes = {
287
+ optional : PropTypes . string ,
288
+ required : PropTypes . string . isRequired ,
289
+ } ;
290
+
291
+ RefForwardingComponent . defaultProps = {
292
+ optional : 'default' ,
293
+ } ;
294
+
295
+ const ref = React . createRef ( ) ;
296
+
297
+ expect ( ( ) =>
298
+ ReactNoop . render ( < RefForwardingComponent ref = { ref } optional = "foo" /> ) ,
299
+ ) . toErrorDev (
300
+ 'Warning: Failed prop type: The prop `required` is marked as required in ' +
301
+ '`Custom`, but its value is `undefined`.\n' +
302
+ ' in Custom (at **)' ,
246
303
) ;
247
304
} ) ;
248
305
249
306
it ( 'should honor a displayName in stacks if set on the inner function' , ( ) => {
250
307
const Component = props => < div { ...props } /> ;
251
308
252
309
const inner = ( props , ref ) => < Component { ...props } forwardedRef = { ref } /> ;
253
- inner . displayName = 'Foo' ;
310
+ inner . displayName = 'Inner' ;
311
+ const RefForwardingComponent = React . forwardRef ( inner ) ;
312
+
313
+ RefForwardingComponent . propTypes = {
314
+ optional : PropTypes . string ,
315
+ required : PropTypes . string . isRequired ,
316
+ } ;
317
+
318
+ RefForwardingComponent . defaultProps = {
319
+ optional : 'default' ,
320
+ } ;
321
+
322
+ const ref = React . createRef ( ) ;
323
+
324
+ expect ( ( ) =>
325
+ ReactNoop . render ( < RefForwardingComponent ref = { ref } optional = "foo" /> ) ,
326
+ ) . toErrorDev (
327
+ 'Warning: Failed prop type: The prop `required` is marked as required in ' +
328
+ '`ForwardRef(Inner)`, but its value is `undefined`.\n' +
329
+ ' in Inner (at **)' ,
330
+ ) ;
331
+ } ) ;
332
+
333
+ it ( 'should honor a outer displayName when wrapped component and memo component set displayName at the same time.' , ( ) => {
334
+ const Component = props => < div { ...props } /> ;
335
+
336
+ const inner = ( props , ref ) => < Component { ...props } forwardedRef = { ref } /> ;
337
+ inner . displayName = 'Inner' ;
254
338
const RefForwardingComponent = React . forwardRef ( inner ) ;
339
+ RefForwardingComponent . displayName = 'Outer' ;
255
340
256
341
RefForwardingComponent . propTypes = {
257
342
optional : PropTypes . string ,
@@ -268,8 +353,8 @@ describe('forwardRef', () => {
268
353
ReactNoop . render ( < RefForwardingComponent ref = { ref } optional = "foo" /> ) ,
269
354
) . toErrorDev (
270
355
'Warning: Failed prop type: The prop `required` is marked as required in ' +
271
- '`ForwardRef(Foo) `, but its value is `undefined`.\n' +
272
- ' in Foo (at **)' ,
356
+ '`Outer `, but its value is `undefined`.\n' +
357
+ ' in Inner (at **)' ,
273
358
) ;
274
359
} ) ;
275
360
0 commit comments