Reputation: 151
I am trying to use jest and React Testing Library to mock a functional component that is wrapped in React.ForwardRef(), but I keep getting this warning (which is failing my test):
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
const ParentComponent = () => {
const childRef = useRef(null);
return (
<div data-testid="parent">
Parent
{/* want to mock this ChildComponent */}
<ChildComponent ref={childRef} />
</div>
);
};
const ChildComponent = forwardRef((props, ref) => (
<div ref={ref} {...props}>
Child
</div>
));
jest.mock("../ChildComponent", () => ({
__esModule: true,
default: () => <div>Mock Child</div>
}));
result: Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
jest.mock('../ChildComponent', () => {
const { forwardRef } = jest.requireActual('react');
return {
__esModule: true,
default: () => forwardRef((props, ref) => <div ref={ref} />),
};
});
result: Objects are not valid as a React child (found: object with keys {$$typeof, render})
Upvotes: 15
Views: 13047
Reputation: 7598
I had a similar issue to Ryan S, and used their answer with a slight modification.
In my problem, I had to test with enzyme that the exact child component was rendered, but without using enzyme's mount
only shallow
:
it('renders the child', () => {
expect(wrapper.exists(ChildComponent)).toBe(true);
})
My modification of the solution is thus:
jest.mock('../ChildComponent', () => {
const { forwardRef } = jest.requireActual('react');
const ChildComponentShim = jest.requireActual('../ChildComponent');
return {
__esModule: true,
default: forwardRef((props, ref) => <ChildComponentShim { ...props } ref={ref} />),
};
});
Which is merely to let the actual child component to be rendered, but makes sure the ref from forwardRef is used without mounting the parent or child component.
Upvotes: 3
Reputation: 201
Sweet, I just had this exact same issue and your last attempt where you imported forwardRef
within the mock function helped me figure this out. I had luck with this:
jest.mock('../../../client/components/visualizations/Visualizer', () => {
const { forwardRef } = jest.requireActual('react');
return {
__esModule: true,
default: forwardRef(() => <div></div>),
};
});
So using your example from above, I believe this should work:
jest.mock('../ChildComponent', () => {
const { forwardRef } = jest.requireActual('react');
return {
__esModule: true,
- default: () => forwardRef((props, ref) => <div ref={ref} />),
+ default: forwardRef((props, ref) => <div ref={ref} />),
};
});
Also including my own attempt below with the resulting error message in case it helps someone else find this post in the future:
jest.mock('../ChildComponent', () => ({
__esModule: true,
default: React.forwardRef(() => <div></div>),
}));
Resulted in error:
The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
Invalid variable access: React`
Upvotes: 19