@@ -217,14 +217,43 @@ describe('forwardRef', () => {
217217 ) ;
218218 } ) ;
219219
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 ' , ( ) => {
221221 const Component = props => < div { ...props } /> ;
222222
223223 const RefForwardingComponent = React . forwardRef ( ( props , ref ) => (
224224 < Component { ...props } forwardedRef = { ref } />
225225 ) ) ;
226226
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' ;
228257
229258 RefForwardingComponent . propTypes = {
230259 optional : PropTypes . string ,
@@ -241,17 +270,73 @@ describe('forwardRef', () => {
241270 ReactNoop . render ( < RefForwardingComponent ref = { ref } optional = "foo" /> ) ,
242271 ) . toErrorDev (
243272 '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 **)' ,
246303 ) ;
247304 } ) ;
248305
249306 it ( 'should honor a displayName in stacks if set on the inner function' , ( ) => {
250307 const Component = props => < div { ...props } /> ;
251308
252309 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' ;
254338 const RefForwardingComponent = React . forwardRef ( inner ) ;
339+ RefForwardingComponent . displayName = 'Outer' ;
255340
256341 RefForwardingComponent . propTypes = {
257342 optional : PropTypes . string ,
@@ -268,8 +353,8 @@ describe('forwardRef', () => {
268353 ReactNoop . render ( < RefForwardingComponent ref = { ref } optional = "foo" /> ) ,
269354 ) . toErrorDev (
270355 '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 **)' ,
273358 ) ;
274359 } ) ;
275360
0 commit comments