Thanks to Black Illustrations for this cover image!
Recently, I was writing some tests for a few React components at work, and I had to mock a module from another part of my app in order to properly set things up.
The following is a short guide for how to mock a module with Jest...written for myself as a reference for the next time I have to do this so I don't need ask the senior dev on my team again. I still find testing React components challenging, so any help for future me (or other interested folks!) is a good thing.
For anyone unfamiliar: Jest is shipped automatically with create-react-app, so it is a commonly used testing framework in React apps, and it's what I'm using at work.
Three steps to mock an import:
1) Import what you need as a module object:
import * as FooModule from '../relative/path/to/foo';
2) Tell Jest to watch the path to that module. Above your 'describe' block, add:
jest.mock('../relative/path/to/foo');
3) In the test, access the exported function that you need from the module (they are all replaced with mock functions now) and tell it what to return or assert if it has been called:
FooModule.methodName.mockReturnValue(); // or .mockImplementation()
When using mocks, you typically want to mimic the original behavior of the function.
Final notes:
Make sure to clear the mocked module in a beforeEach block:
beforeEach(() => {
FooModule.methodName.mockClear();
});
...and clear all mocks in an afterEach block:
afterEach(() => {
jest.restoreAllMocks();
});
Link to more information about Jest module mocks
Interesting side note: I was seeing strange, intermittently failing tests after I thought I had properly set everything up to mock the module in question. Turns out I had a sneaky, hidden dependency in several child components! I was testing an overly large component which had several child components depending on the module I needed to mock. I was mocking it in the child component tests, but not in the parent's test because the parent component did not use the module. Once I mocked the module in the parent's spec file, all seemed well. What a great argument for smaller components!
Top comments (1)
Actually
restoreAllMocks
after each test is not necessary for mocking modules.mockClear
is necessary if you are making the mocked method to return different values in different tests. CallingmockClear
basically "resets" the mocked function so its internal state (call count, mocked implementations, etc.) doesn't leak to other tests.If we don't care if the mocked function is called, or we want it to behave the same for all the tests in the same test file, we can skip the
import * as
part as well, then instead of usingmockReturnValue
ormockImplementation
- we can just use a simple function to replace the original one:now in the tests all calls to
methodName
will get42
as return value.