Skip to content

Commit 9e08b12

Browse files
committed
Rewrite tests that depend on propTypes warnings (#28325)
In preparation for #28207. These tests aren't actually testing propTypes, they just use them to verify we can display a meaningful component name. We've mostly moved away from warnings that display component names directly in favor of component stacks. So let's just replace these with tests asserting the component names show up in stacks.
1 parent 81ec618 commit 9e08b12

File tree

2 files changed

+151
-198
lines changed

2 files changed

+151
-198
lines changed

packages/react-reconciler/src/__tests__/ReactMemo-test.js

+75-76
Original file line numberDiff line numberDiff line change
@@ -657,97 +657,96 @@ describe('memo', () => {
657657
});
658658
});
659659

660-
it('should fall back to showing something meaningful if no displayName or name are present', () => {
661-
const MemoComponent = React.memo(props => <div {...props} />);
662-
MemoComponent.propTypes = {
663-
required: PropTypes.string.isRequired,
664-
};
665-
666-
expect(() =>
667-
ReactNoop.render(<MemoComponent optional="foo" />),
668-
).toErrorDev(
669-
'Warning: Failed prop type: The prop `required` is marked as required in ' +
670-
'`Memo`, but its value is `undefined`.',
671-
// There's no component stack in this warning because the inner function is anonymous.
672-
// If we wanted to support this (for the Error frames / source location)
673-
// we could do this by updating ReactComponentStackFrame.
674-
{withoutStack: true},
660+
it('should skip memo in the stack if neither displayName nor name are present', async () => {
661+
const MemoComponent = React.memo(props => [<span />]);
662+
ReactNoop.render(
663+
<p>
664+
<MemoComponent />
665+
</p>,
666+
);
667+
await expect(async () => {
668+
await waitForAll([]);
669+
}).toErrorDev(
670+
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
671+
' in p (at **)',
675672
);
676673
});
677674

678-
it('should honor a displayName if set on the inner component in warnings', () => {
679-
function Component(props) {
680-
return <div {...props} />;
681-
}
682-
Component.displayName = 'Inner';
683-
const MemoComponent = React.memo(Component);
684-
MemoComponent.propTypes = {
685-
required: PropTypes.string.isRequired,
686-
};
687-
688-
expect(() =>
689-
ReactNoop.render(<MemoComponent optional="foo" />),
690-
).toErrorDev(
691-
'Warning: Failed prop type: The prop `required` is marked as required in ' +
692-
'`Inner`, but its value is `undefined`.\n' +
693-
' in Inner (at **)',
675+
it('should use the inner function name for the stack', async () => {
676+
const MemoComponent = React.memo(function Inner(props, ref) {
677+
return [<span />];
678+
});
679+
ReactNoop.render(
680+
<p>
681+
<MemoComponent />
682+
</p>,
683+
);
684+
await expect(async () => {
685+
await waitForAll([]);
686+
}).toErrorDev(
687+
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
688+
' in Inner (at **)\n' +
689+
' in p (at **)',
694690
);
695691
});
696692

697-
it('should honor a displayName if set on the memo wrapper in warnings', () => {
698-
const MemoComponent = React.memo(function Component(props) {
699-
return <div {...props} />;
700-
});
701-
MemoComponent.displayName = 'Outer';
702-
MemoComponent.propTypes = {
703-
required: PropTypes.string.isRequired,
693+
it('should use the inner displayName in the stack', async () => {
694+
const fn = (props, ref) => {
695+
return [<span />];
704696
};
705-
706-
expect(() =>
707-
ReactNoop.render(<MemoComponent optional="foo" />),
708-
).toErrorDev(
709-
'Warning: Failed prop type: The prop `required` is marked as required in ' +
710-
'`Outer`, but its value is `undefined`.\n' +
711-
' in Component (at **)',
697+
fn.displayName = 'Inner';
698+
const MemoComponent = React.memo(fn);
699+
ReactNoop.render(
700+
<p>
701+
<MemoComponent />
702+
</p>,
703+
);
704+
await expect(async () => {
705+
await waitForAll([]);
706+
}).toErrorDev(
707+
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
708+
' in Inner (at **)\n' +
709+
' in p (at **)',
712710
);
713711
});
714712

715-
it('should pass displayName to an anonymous inner component so it shows up in component stacks', () => {
716-
const MemoComponent = React.memo(props => {
717-
return <div {...props} />;
713+
it('can use the outer displayName in the stack', async () => {
714+
const MemoComponent = React.memo((props, ref) => {
715+
return [<span />];
718716
});
719-
MemoComponent.displayName = 'Memo';
720-
MemoComponent.propTypes = {
721-
required: PropTypes.string.isRequired,
722-
};
723-
724-
expect(() =>
725-
ReactNoop.render(<MemoComponent optional="foo" />),
726-
).toErrorDev(
727-
'Warning: Failed prop type: The prop `required` is marked as required in ' +
728-
'`Memo`, but its value is `undefined`.\n' +
729-
' in Memo (at **)',
717+
MemoComponent.displayName = 'Outer';
718+
ReactNoop.render(
719+
<p>
720+
<MemoComponent />
721+
</p>,
722+
);
723+
await expect(async () => {
724+
await waitForAll([]);
725+
}).toErrorDev(
726+
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
727+
' in Outer (at **)\n' +
728+
' in p (at **)',
730729
);
731730
});
732731

733-
it('should honor a outer displayName when wrapped component and memo component set displayName at the same time.', () => {
734-
function Component(props) {
735-
return <div {...props} />;
736-
}
737-
Component.displayName = 'Inner';
738-
739-
const MemoComponent = React.memo(Component);
740-
MemoComponent.displayName = 'Outer';
741-
MemoComponent.propTypes = {
742-
required: PropTypes.string.isRequired,
732+
it('should prefer the inner to the outer displayName in the stack', async () => {
733+
const fn = (props, ref) => {
734+
return [<span />];
743735
};
744-
745-
expect(() =>
746-
ReactNoop.render(<MemoComponent optional="foo" />),
747-
).toErrorDev(
748-
'Warning: Failed prop type: The prop `required` is marked as required in ' +
749-
'`Outer`, but its value is `undefined`.\n' +
750-
' in Inner (at **)',
736+
fn.displayName = 'Inner';
737+
const MemoComponent = React.memo(fn);
738+
MemoComponent.displayName = 'Outer';
739+
ReactNoop.render(
740+
<p>
741+
<MemoComponent />
742+
</p>,
743+
);
744+
await expect(async () => {
745+
await waitForAll([]);
746+
}).toErrorDev(
747+
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
748+
' in Inner (at **)\n' +
749+
' in p (at **)',
751750
);
752751
});
753752
}

packages/react/src/__tests__/forwardRef-test.js

+76-122
Original file line numberDiff line numberDiff line change
@@ -204,144 +204,98 @@ describe('forwardRef', () => {
204204
);
205205
});
206206

207-
it('should fall back to showing something meaningful if no displayName or name are present', () => {
208-
const Component = props => <div {...props} />;
209-
210-
const RefForwardingComponent = React.forwardRef((props, ref) => (
211-
<Component {...props} forwardedRef={ref} />
212-
));
213-
214-
RefForwardingComponent.propTypes = {
215-
optional: PropTypes.string,
216-
required: PropTypes.string.isRequired,
217-
};
218-
219-
RefForwardingComponent.defaultProps = {
220-
optional: 'default',
221-
};
222-
223-
const ref = React.createRef();
224-
225-
expect(() =>
226-
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />),
227-
).toErrorDev(
228-
'Warning: Failed prop type: The prop `required` is marked as required in ' +
229-
'`ForwardRef`, but its value is `undefined`.',
230-
// There's no component stack in this warning because the inner function is anonymous.
231-
// If we wanted to support this (for the Error frames / source location)
232-
// we could do this by updating ReactComponentStackFrame.
233-
{withoutStack: true},
207+
it('should skip forwardRef in the stack if neither displayName nor name are present', async () => {
208+
const RefForwardingComponent = React.forwardRef(function (props, ref) {
209+
return [<span />];
210+
});
211+
ReactNoop.render(
212+
<p>
213+
<RefForwardingComponent />
214+
</p>,
215+
);
216+
await expect(async () => {
217+
await waitForAll([]);
218+
}).toErrorDev(
219+
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
220+
' in p (at **)',
234221
);
235222
});
236223

237-
it('should honor a displayName if set on the forwardRef wrapper in warnings', () => {
238-
const Component = props => <div {...props} />;
239-
224+
it('should use the inner function name for the stack', async () => {
240225
const RefForwardingComponent = React.forwardRef(function Inner(props, ref) {
241-
<Component {...props} forwardedRef={ref} />;
226+
return [<span />];
242227
});
243-
RefForwardingComponent.displayName = 'Custom';
244-
245-
RefForwardingComponent.propTypes = {
246-
optional: PropTypes.string,
247-
required: PropTypes.string.isRequired,
248-
};
249-
250-
RefForwardingComponent.defaultProps = {
251-
optional: 'default',
252-
};
253-
254-
const ref = React.createRef();
255-
256-
expect(() =>
257-
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />),
258-
).toErrorDev(
259-
'Warning: Failed prop type: The prop `required` is marked as required in ' +
260-
'`Custom`, but its value is `undefined`.\n' +
261-
' in Inner (at **)',
228+
ReactNoop.render(
229+
<p>
230+
<RefForwardingComponent />
231+
</p>,
262232
);
263-
});
264-
265-
it('should pass displayName to an anonymous inner component so it shows up in component stacks', () => {
266-
const Component = props => <div {...props} />;
267-
268-
const RefForwardingComponent = React.forwardRef((props, ref) => (
269-
<Component {...props} forwardedRef={ref} />
270-
));
271-
RefForwardingComponent.displayName = 'Custom';
272-
273-
RefForwardingComponent.propTypes = {
274-
optional: PropTypes.string,
275-
required: PropTypes.string.isRequired,
276-
};
277-
278-
RefForwardingComponent.defaultProps = {
279-
optional: 'default',
280-
};
281-
282-
const ref = React.createRef();
283-
284-
expect(() =>
285-
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />),
286-
).toErrorDev(
287-
'Warning: Failed prop type: The prop `required` is marked as required in ' +
288-
'`Custom`, but its value is `undefined`.\n' +
289-
' in Custom (at **)',
233+
await expect(async () => {
234+
await waitForAll([]);
235+
}).toErrorDev(
236+
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
237+
' in Inner (at **)\n' +
238+
' in p (at **)',
290239
);
291240
});
292241

293-
it('should honor a displayName in stacks if set on the inner function', () => {
294-
const Component = props => <div {...props} />;
295-
296-
const inner = (props, ref) => <Component {...props} forwardedRef={ref} />;
297-
inner.displayName = 'Inner';
298-
const RefForwardingComponent = React.forwardRef(inner);
299-
300-
RefForwardingComponent.propTypes = {
301-
optional: PropTypes.string,
302-
required: PropTypes.string.isRequired,
242+
it('should use the inner displayName in the stack', async () => {
243+
const fn = (props, ref) => {
244+
return [<span />];
303245
};
304-
305-
RefForwardingComponent.defaultProps = {
306-
optional: 'default',
307-
};
308-
309-
const ref = React.createRef();
310-
311-
expect(() =>
312-
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />),
313-
).toErrorDev(
314-
'Warning: Failed prop type: The prop `required` is marked as required in ' +
315-
'`ForwardRef(Inner)`, but its value is `undefined`.\n' +
316-
' in Inner (at **)',
246+
fn.displayName = 'Inner';
247+
const RefForwardingComponent = React.forwardRef(fn);
248+
ReactNoop.render(
249+
<p>
250+
<RefForwardingComponent />
251+
</p>,
252+
);
253+
await expect(async () => {
254+
await waitForAll([]);
255+
}).toErrorDev(
256+
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
257+
' in Inner (at **)\n' +
258+
' in p (at **)',
317259
);
318260
});
319261

320-
it('should honor a outer displayName when wrapped component and memo component set displayName at the same time.', () => {
321-
const Component = props => <div {...props} />;
322-
323-
const inner = (props, ref) => <Component {...props} forwardedRef={ref} />;
324-
inner.displayName = 'Inner';
325-
const RefForwardingComponent = React.forwardRef(inner);
262+
it('can use the outer displayName in the stack', async () => {
263+
const RefForwardingComponent = React.forwardRef((props, ref) => {
264+
return [<span />];
265+
});
326266
RefForwardingComponent.displayName = 'Outer';
267+
ReactNoop.render(
268+
<p>
269+
<RefForwardingComponent />
270+
</p>,
271+
);
272+
await expect(async () => {
273+
await waitForAll([]);
274+
}).toErrorDev(
275+
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
276+
' in Outer (at **)\n' +
277+
' in p (at **)',
278+
);
279+
});
327280

328-
RefForwardingComponent.propTypes = {
329-
optional: PropTypes.string,
330-
required: PropTypes.string.isRequired,
331-
};
332-
333-
RefForwardingComponent.defaultProps = {
334-
optional: 'default',
281+
it('should prefer the inner to the outer displayName in the stack', async () => {
282+
const fn = (props, ref) => {
283+
return [<span />];
335284
};
336-
337-
const ref = React.createRef();
338-
339-
expect(() =>
340-
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />),
341-
).toErrorDev(
342-
'Warning: Failed prop type: The prop `required` is marked as required in ' +
343-
'`Outer`, but its value is `undefined`.\n' +
344-
' in Inner (at **)',
285+
fn.displayName = 'Inner';
286+
const RefForwardingComponent = React.forwardRef(fn);
287+
RefForwardingComponent.displayName = 'Outer';
288+
ReactNoop.render(
289+
<p>
290+
<RefForwardingComponent />
291+
</p>,
292+
);
293+
await expect(async () => {
294+
await waitForAll([]);
295+
}).toErrorDev(
296+
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
297+
' in Inner (at **)\n' +
298+
' in p (at **)',
345299
);
346300
});
347301

0 commit comments

Comments
 (0)