Skip to content

Commit

Permalink
Rewrite tests that depend on propTypes warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
gaearon committed Feb 14, 2024
1 parent 64e755d commit 6fc39bb
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 198 deletions.
151 changes: 75 additions & 76 deletions packages/react-reconciler/src/__tests__/ReactMemo-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -657,97 +657,96 @@ describe('memo', () => {
});
});

it('should fall back to showing something meaningful if no displayName or name are present', () => {
const MemoComponent = React.memo(props => <div {...props} />);
MemoComponent.propTypes = {
required: PropTypes.string.isRequired,
};

expect(() =>
ReactNoop.render(<MemoComponent optional="foo" />),
).toErrorDev(
'Warning: Failed prop type: The prop `required` is marked as required in ' +
'`Memo`, but its value is `undefined`.',
// There's no component stack in this warning because the inner function is anonymous.
// If we wanted to support this (for the Error frames / source location)
// we could do this by updating ReactComponentStackFrame.
{withoutStack: true},
it('should skip memo in the stack if neither displayName nor name are present', async () => {
const MemoComponent = React.memo(props => [<span />]);
ReactNoop.render(
<p>
<MemoComponent />
</p>,
);
await expect(async () => {
await waitForAll([]);
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
' in p (at **)',
);
});

it('should honor a displayName if set on the inner component in warnings', () => {
function Component(props) {
return <div {...props} />;
}
Component.displayName = 'Inner';
const MemoComponent = React.memo(Component);
MemoComponent.propTypes = {
required: PropTypes.string.isRequired,
};

expect(() =>
ReactNoop.render(<MemoComponent optional="foo" />),
).toErrorDev(
'Warning: Failed prop type: The prop `required` is marked as required in ' +
'`Inner`, but its value is `undefined`.\n' +
' in Inner (at **)',
it('should use the inner function name for the stack', async () => {
const MemoComponent = React.memo(function Inner(props, ref) {
return [<span />];
});
ReactNoop.render(
<p>
<MemoComponent />
</p>,
);
await expect(async () => {
await waitForAll([]);
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
' in Inner (at **)\n' +
' in p (at **)',
);
});

it('should honor a displayName if set on the memo wrapper in warnings', () => {
const MemoComponent = React.memo(function Component(props) {
return <div {...props} />;
});
MemoComponent.displayName = 'Outer';
MemoComponent.propTypes = {
required: PropTypes.string.isRequired,
it('should use the inner displayName in the stack', async () => {
const fn = (props, ref) => {
return [<span />];
};

expect(() =>
ReactNoop.render(<MemoComponent optional="foo" />),
).toErrorDev(
'Warning: Failed prop type: The prop `required` is marked as required in ' +
'`Outer`, but its value is `undefined`.\n' +
' in Component (at **)',
fn.displayName = 'Inner';
const MemoComponent = React.memo(fn);
ReactNoop.render(
<p>
<MemoComponent />
</p>,
);
await expect(async () => {
await waitForAll([]);
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
' in Inner (at **)\n' +
' in p (at **)',
);
});

it('should pass displayName to an anonymous inner component so it shows up in component stacks', () => {
const MemoComponent = React.memo(props => {
return <div {...props} />;
it('can use the outer displayName in the stack', async () => {
const MemoComponent = React.memo((props, ref) => {
return [<span />];
});
MemoComponent.displayName = 'Memo';
MemoComponent.propTypes = {
required: PropTypes.string.isRequired,
};

expect(() =>
ReactNoop.render(<MemoComponent optional="foo" />),
).toErrorDev(
'Warning: Failed prop type: The prop `required` is marked as required in ' +
'`Memo`, but its value is `undefined`.\n' +
' in Memo (at **)',
MemoComponent.displayName = 'Outer';
ReactNoop.render(
<p>
<MemoComponent />
</p>,
);
await expect(async () => {
await waitForAll([]);
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
' in Outer (at **)\n' +
' in p (at **)',
);
});

it('should honor a outer displayName when wrapped component and memo component set displayName at the same time.', () => {
function Component(props) {
return <div {...props} />;
}
Component.displayName = 'Inner';

const MemoComponent = React.memo(Component);
MemoComponent.displayName = 'Outer';
MemoComponent.propTypes = {
required: PropTypes.string.isRequired,
it('should prefer the inner to the outer displayName in the stack', async () => {
const fn = (props, ref) => {
return [<span />];
};

expect(() =>
ReactNoop.render(<MemoComponent optional="foo" />),
).toErrorDev(
'Warning: Failed prop type: The prop `required` is marked as required in ' +
'`Outer`, but its value is `undefined`.\n' +
' in Inner (at **)',
fn.displayName = 'Inner';
const MemoComponent = React.memo(fn);
MemoComponent.displayName = 'Outer';
ReactNoop.render(
<p>
<MemoComponent />
</p>,
);
await expect(async () => {
await waitForAll([]);
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
' in Inner (at **)\n' +
' in p (at **)',
);
});
}
Expand Down
198 changes: 76 additions & 122 deletions packages/react/src/__tests__/forwardRef-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,144 +204,98 @@ describe('forwardRef', () => {
);
});

it('should fall back to showing something meaningful if no displayName or name are present', () => {
const Component = props => <div {...props} />;

const RefForwardingComponent = React.forwardRef((props, ref) => (
<Component {...props} forwardedRef={ref} />
));

RefForwardingComponent.propTypes = {
optional: PropTypes.string,
required: PropTypes.string.isRequired,
};

RefForwardingComponent.defaultProps = {
optional: 'default',
};

const ref = React.createRef();

expect(() =>
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />),
).toErrorDev(
'Warning: Failed prop type: The prop `required` is marked as required in ' +
'`ForwardRef`, but its value is `undefined`.',
// There's no component stack in this warning because the inner function is anonymous.
// If we wanted to support this (for the Error frames / source location)
// we could do this by updating ReactComponentStackFrame.
{withoutStack: true},
it('should skip forwardRef in the stack if neither displayName nor name are present', async () => {
const RefForwardingComponent = React.forwardRef(function (props, ref) {
return [<span />];
});
ReactNoop.render(
<p>
<RefForwardingComponent />
</p>,
);
await expect(async () => {
await waitForAll([]);
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
' in p (at **)',
);
});

it('should honor a displayName if set on the forwardRef wrapper in warnings', () => {
const Component = props => <div {...props} />;

it('should use the inner function name for the stack', async () => {
const RefForwardingComponent = React.forwardRef(function Inner(props, ref) {
<Component {...props} forwardedRef={ref} />;
return [<span />];
});
RefForwardingComponent.displayName = 'Custom';

RefForwardingComponent.propTypes = {
optional: PropTypes.string,
required: PropTypes.string.isRequired,
};

RefForwardingComponent.defaultProps = {
optional: 'default',
};

const ref = React.createRef();

expect(() =>
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />),
).toErrorDev(
'Warning: Failed prop type: The prop `required` is marked as required in ' +
'`Custom`, but its value is `undefined`.\n' +
' in Inner (at **)',
ReactNoop.render(
<p>
<RefForwardingComponent />
</p>,
);
});

it('should pass displayName to an anonymous inner component so it shows up in component stacks', () => {
const Component = props => <div {...props} />;

const RefForwardingComponent = React.forwardRef((props, ref) => (
<Component {...props} forwardedRef={ref} />
));
RefForwardingComponent.displayName = 'Custom';

RefForwardingComponent.propTypes = {
optional: PropTypes.string,
required: PropTypes.string.isRequired,
};

RefForwardingComponent.defaultProps = {
optional: 'default',
};

const ref = React.createRef();

expect(() =>
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />),
).toErrorDev(
'Warning: Failed prop type: The prop `required` is marked as required in ' +
'`Custom`, but its value is `undefined`.\n' +
' in Custom (at **)',
await expect(async () => {
await waitForAll([]);
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
' in Inner (at **)\n' +
' in p (at **)',
);
});

it('should honor a displayName in stacks if set on the inner function', () => {
const Component = props => <div {...props} />;

const inner = (props, ref) => <Component {...props} forwardedRef={ref} />;
inner.displayName = 'Inner';
const RefForwardingComponent = React.forwardRef(inner);

RefForwardingComponent.propTypes = {
optional: PropTypes.string,
required: PropTypes.string.isRequired,
it('should use the inner displayName in the stack', async () => {
const fn = (props, ref) => {
return [<span />];
};

RefForwardingComponent.defaultProps = {
optional: 'default',
};

const ref = React.createRef();

expect(() =>
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />),
).toErrorDev(
'Warning: Failed prop type: The prop `required` is marked as required in ' +
'`ForwardRef(Inner)`, but its value is `undefined`.\n' +
' in Inner (at **)',
fn.displayName = 'Inner';
const RefForwardingComponent = React.forwardRef(fn);
ReactNoop.render(
<p>
<RefForwardingComponent />
</p>,
);
await expect(async () => {
await waitForAll([]);
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
' in Inner (at **)\n' +
' in p (at **)',
);
});

it('should honor a outer displayName when wrapped component and memo component set displayName at the same time.', () => {
const Component = props => <div {...props} />;

const inner = (props, ref) => <Component {...props} forwardedRef={ref} />;
inner.displayName = 'Inner';
const RefForwardingComponent = React.forwardRef(inner);
it('can use the outer displayName in the stack', async () => {
const RefForwardingComponent = React.forwardRef((props, ref) => {
return [<span />];
});
RefForwardingComponent.displayName = 'Outer';
ReactNoop.render(
<p>
<RefForwardingComponent />
</p>,
);
await expect(async () => {
await waitForAll([]);
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
' in Outer (at **)\n' +
' in p (at **)',
);
});

RefForwardingComponent.propTypes = {
optional: PropTypes.string,
required: PropTypes.string.isRequired,
};

RefForwardingComponent.defaultProps = {
optional: 'default',
it('should prefer the inner to the outer displayName in the stack', async () => {
const fn = (props, ref) => {
return [<span />];
};

const ref = React.createRef();

expect(() =>
ReactNoop.render(<RefForwardingComponent ref={ref} optional="foo" />),
).toErrorDev(
'Warning: Failed prop type: The prop `required` is marked as required in ' +
'`Outer`, but its value is `undefined`.\n' +
' in Inner (at **)',
fn.displayName = 'Inner';
const RefForwardingComponent = React.forwardRef(fn);
RefForwardingComponent.displayName = 'Outer';
ReactNoop.render(
<p>
<RefForwardingComponent />
</p>,
);
await expect(async () => {
await waitForAll([]);
}).toErrorDev(
'Each child in a list should have a unique "key" prop. See https://reactjs.org/link/warning-keys for more information.\n' +
' in Inner (at **)\n' +
' in p (at **)',
);
});

Expand Down

0 comments on commit 6fc39bb

Please sign in to comment.