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, or
b) 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?
To mock a React component, the most straightforward approach is to use the jest. mock function. You mock the file that exports the component and replace it with a custom implementation. Since a component is basically a function, the mock should also return a function.
You can use it like this: imoprt { activeListItem } from './utils'; let spy; beforeAll(() => { spy = jest. spyOn(document, 'getElementById'); }); describe('activeListItem', () => { describe('with found element', () => { let mockElement; beforeAll(() => { // here you create the element that the document.
Both Jest and Enzyme are meant to test the react applications. Jest can be used with any other Javascript framework, but Enzyme is meant to run on react only. Jest can be used without Enzyme, and snapshots can be created and tested perfectly fine. But the Enzyme adds additional functionality to it.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With