Using Jest to mock a React component with props
Solution 1
There's a note at the bottom of the docs for jest.mock()
for preventing the hoisting behavior:
Note: When using
babel-jest
, calls tomock
will automatically be hoisted to the top of the code block. UsedoMock
if you want to explicitly avoid this behavior.
Then you can do as you described: return a function that is a stub of the component you don't need to test.
jest.doMock('./ComponentToMock', () => {
const ComponentToMock = () => <div />;
return ComponentToMock;
});
const ComponentToTest = require('./ComponentToTest').default;
It's helpful to name the stub component since it gets rendered in snapshots.
Solution 2
I've learned a little more since I asked this question. Here's an alternative (better?) way of dealing with mocking components that need to be passed props: using module mock files.
First create a file with the same name as the component to mock in a __mocks__
folder under the component's folder e.g.
.
|- /ComponentToMock.js
└- /__mocks__/ComponentToMock.js <-- create this folder/file!
Note: It seems as of the time of writing, the folder must be called __mocks__
(you will need to create __mocks__
in each folder you need to mock components for. If the underscores upset you, just pretend they aren't there ;) )
Next, in this mock file, you can write the file as you wish, e.g.
// This code would live in ./__mocks__/ComponentToMock.js
import React from 'react';
const ComponentToMock = ({ testProp }) => <div>A mock with '{testProp}' passed!</div>;
export default ComponentToMock;
Then in the test file, change the Jest mock statement to: jest.mock('./ComponentToMock');
When Jest encounters a .mock()
without the second function parameter, it automatically looks for a __mocks__
folder. However, even though the mock statement gets hoisted in the component being tested, this doesn't affect the imports of the mock itself - hence why it's able to import and compile a React component!
This seems to work well for mocked components that need to be passed props, and would otherwise produce prop warnings if a nulled function was returned (but which is perfectly acceptable to continue using if the component does not receive props). I hope this helps some people out there.
Solution 3
Addition to accepted answer, If you are using multiple exports then mocking can be done as follows:
// Component.jsx
export { A, B };
// Component-test.js
jest.mock("../src/Component", () => {
return {
A: true,
B: () => {
return <></>;
},
};
})
Reference Blog: https://thoughtbot.com/blog/mocking-react-components-with-jest
Mike Hopkins
I like front end dev, digital design and awesome things. As visual designer as I am coder. Mostly self-taught. Been writing HTML since 1996, and every day there's something new to learn (or unlearn!). Wrote ActionScript for a spell, from before it was even called ActionScript, all the way up to AS3... I kind of wish JavaScript was more like AS3. I like its language structure, even if the Flash runtime is not so great these days. Hardest language I've ever tried to learn was x86 assembly. Could get a picture to blit to the screen, but then my brain imploded.
Updated on August 27, 2021Comments
-
Mike Hopkins over 2 years
I have a React component which contains some other components that depend on access to a Redux store etc., which cause issues when doing a full Enzyme mount. Let's say a structure like this:
import ComponentToMock from './ComponentToMock'; <ComponentToTest> ...some stuff <ComponentToMock testProp="This throws a warning" /> </ComponentToTest>
I want to use Jest's
.mock()
method to mock out the sub-component, so that it is not a concern for the test.I'm aware that I can mock out a straight component with something like:
jest.mock('./ComponentToMock', () => 'ComponentToMock');
However, as this component would normally receive props, React gets upset, giving a warning about unknown props (in this case,
testProp
) being passed to<ComponentToMock />
.I've tried to return a function instead, however you can't return JSX (from what I could tell) in a Jest mock, due to it being hoisted. It throws an error in this case.
So my question is how can I either
a) get
ComponentToMock
to ignore props passed to it, orb) return a React component that can be used to mock the child component that I'm not worried about testing.
Or... is there a better way?
-
Mike Hopkins almost 7 yearsThis is good to know! The docs mention it a little off-handedly. However, I tried this and it still didn't work out. Because the import of <ComponentToMock /> happens when the <ComponentToTest /> is brought in, unless Jest's mock is hoisted to be first, it happens after the fact and the mock does not work.
-
Mike Reifman almost 7 yearsI updated the snippet: you have to do the mocking and then require the component to test.
-
Mike Hopkins almost 7 yearsI've managed to get this working in a basic sense. It does require the use of... require, ahem, not import. That may be worth considering for anyone with a similar situation. I've got a more complex setup that seems to not be working with the fix, but that could just be some interfering HOCs. Thanks for your help!
-
Christof Kälin over 6 yearsSame here, this solution does not work out, it throws a
Invariant Violation: getNodeFromInstance: Invalid argument.
Seems that we should live with the warnings upon test output. -
aoh over 4 yearsDepending on the way your component is exported/imported you might need to do
return {ComponentToMock}
-
Filip Kowal about 3 yearsThe part about pretending not to see the underscores was very helpful. I will!