How to automatically reset mocks and restore spies in Jest
When I used jest for the first time for unit testing, it struck me that function mocks and spies were not automatically reset / restored before each unit test execution. This was quite unexpected to me, especially when you are used to automatic reset / restore functionality of Jasmine.
When using Jest it seemed to be a common approach to manually invoke
jest.resetAllMocks()
or jest.restoreAllMocks()
inside a beforeEach(
..)
or afterEach(
..)
const myMock = jest.fn();
describe('..', () => {
beforeEach(() => {
jest.resetAllMocks();
});
Configuring Jest to automatically reset / restore mocks and spies
As it seemed, it turned out Jest can be configured to do an automatic reset / restore before executing each unit test spec.
You can simply use these settings in the configuration of Jest:
“clearMocks”: true
: resets all the mocks usage data, but keeps the behaviour (e.g. return value) of the mocks
Is effectively the same as:
beforeEach(() => { jest.clearAllMocks(); });
“resetMocks”: true
: same as “clearMocks”: true but also resets the behaviour of the mocks
Is effectively the same as:
beforeEach(() => { jest.resetAllMocks(); });
“restoreMocks”: true
: restores methods that were spied usingjest.spyOn(
..)
to its original method.
This flag is independent of the clearMocks / resetMocks flags.
Is effective the same as:
beforeEach(() => { jest.restoreAllMocks(); });
The settings described above can be placed either:
- inside the
"jest""
entry in thepackage.json
- or in a Jest configuration file (typically called
jest.config.js
)
I personally configured Jest by placing the following in package.json
:
{
..
"jest": {
..
"resetMocks": true,
"restoreMocks": true
}
}
NOTE: when using Create React App the only officially supported way to configure Jest is through the package.json file.
How to properly spy on existing methods
Once in a while you need to replace a method of an existing (global) object with a Jest spy. For instance to be able to test if and how a method was called, or even to temporarily replace the behaviour of the method (e.g. returning a mocked return value).
The poor man's way to spy on a method would to simply monkey-patch an object, by
simply assigning the result of jest.fn(
..)
:
window.open = jest.fn(); // X do “not” do this !!!
However, when manually replacing an existing method with a jest.fn(
..)
,
you’re also responsible to restore the original method.
Instead, it’s much better to use jest.spyOn(
..)
, in which case Jest
automatically resets the spy when “restoreMocks”: true
is configured.
Since “restoreMocks”: true
automatically restores a spy prior to executing
each unit test spec (and prior to any custom beforeEach(..) ), it's best to only
use jest.spyOn(
..)
inside either:
- a
beforeEach(
..)
- a unit test spec
Whereas the following usage of jest.spyOn(
..)
will give issues:
jest.spyOn(window, 'open');
describe('...', () => {
it('...', () => { // you will get a fresh spy here
// ..
expect(window.open).toHaveBeenCalled();
}
it('...', () => { // X window.open is no longer a spy
// ..
expect(window.open).toHaveBeenCalled();
How to prevent method overrides with jest.fn()
To guard your codebase against the overriding a method by reassigning it with
jest.fn(
..)
, you could configure the ESLint linter to use the
prefer-spy-on
rule.