How to Reset, Clear, and Restore Mocks in Jest in JavaScript
In Jest, maintaining test isolation is critical. A mock's behavior or call history from one test should not leak into another, as this can lead to flaky and unpredictable test results. To ensure each test runs from a "clean slate," Jest provides several functions to reset mocks to their initial state.
This guide will clarify the three distinct levels of resetting mocks: clearing, resetting, and restoring. You will learn the difference between mockClear(), mockReset(), and mockRestore(), and how to configure Jest to perform these actions automatically before each test.
The Core Problem: Test Isolation
When you use a mock function across multiple tests, its internal state (like the number of times it was called) persists.
Example of code with problems:
const myMock = jest.fn();
test('first test', () => {
myMock();
expect(myMock).toHaveBeenCalledTimes(1); // Passes
});
test('second test', () => {
// This test fails because myMock was already called in the first test.
// The call count is now 2, not 1.
myMock();
expect(myMock).toHaveBeenCalledTimes(1); // Fails! Expected 1, received 2.
});
To fix this, we need to reset the mock's history between tests.
Three Levels of Reset: A Quick Comparison
Jest offers three "levels" of resetting. Understanding the difference is key to choosing the right one.
| Method | What it Resets | When to Use |
|---|---|---|
mockClear() | Resets usage stats (.mock.calls, .mock.instances). | The most common case. Use when you want a clean slate for toHaveBeenCalled() checks but want to preserve a mocked implementation. |
mockReset() | Does everything mockClear() does, plus removes any mocked implementations or return values. | Use when you need to completely reset a mock to a simple jest.fn(), wiping both its usage and its behavior. |
mockRestore() | Does everything mockReset() does, plus restores the original function implementation. | Only for spies (jest.spyOn()). Use when you want to completely undo the mock and revert to the real function. |
Level 1: Clearing Mock Usage (.mockClear())
This is the most common form of reset. It wipes the call history of a mock but leaves any custom implementation intact.
Solution: By calling mockClear() in a beforeEach or afterEach hook, you ensure each test starts with a fresh call history.
const myMock = jest.fn();
beforeEach(() => {
myMock.mockClear(); // Clears the call history before each test
});
test('first test', () => {
myMock();
expect(myMock).toHaveBeenCalledTimes(1); // Passes
});
test('second test', () => {
myMock();
expect(myMock).toHaveBeenCalledTimes(1); // Passes now!
});
To clear all mocks at once, you can use jest.clearAllMocks() in the hook.
Level 2: Resetting Mock Implementation (.mockReset())
This is a "harder" reset. It clears the call history and removes any fake implementation you might have provided with mockReturnValue() or mockImplementation().
Solution: this is useful when different tests need to provide different mock implementations.
const myMock = jest.fn();
beforeEach(() => {
myMock.mockReset(); // Resets the mock to its initial state
});
test('mock returns a specific value', () => {
myMock.mockReturnValue('tutorialreference.com');
expect(myMock()).toBe('tutorialreference.com');
expect(myMock).toHaveBeenCalledTimes(1);
});
test('mock is a simple, empty function', () => {
// Because of mockReset(), the previous mockReturnValue is gone.
expect(myMock()).toBe(undefined);
expect(myMock).toHaveBeenCalledTimes(1);
});
To reset all mocks this way, you can use jest.resetAllMocks().
Level 3: Restoring the Original Implementation (.mockRestore())
This is the "hardest" reset and is only relevant for mocks created with jest.spyOn(). It completely undoes the spy, restoring the original, non-mocked function.
Solution:
const video = {
play() {
return 'original implementation';
},
};
let playSpy;
beforeEach(() => {
// If a spy already exists, restore it before creating a new one.
if (playSpy) {
playSpy.mockRestore();
}
});
test('play() implementation is mocked', () => {
playSpy = jest.spyOn(video, 'play').mockImplementation(() => 'mocked implementation');
expect(video.play()).toBe('mocked implementation');
});
test('play() has its original implementation', () => {
// Because of mockRestore(), the spy is gone.
// We are now calling the original video.play() method.
expect(video.play()).toBe('original implementation');
});
To restore all spies at once, you can use jest.restoreAllMocks().
Automating Resets: Configuration and Command-Line
Instead of adding a beforeEach hook to every test file, you can configure Jest to do this for you automatically. This is the recommended best practice for maintaining consistency across a project.
jest.config.js
Add one of the following boolean properties to your jest.config.js file:
// jest.config.js
module.exports = {
// Option 1: Clears mocks before each test (Level 1)
clearMocks: true,
// Option 2: Resets mocks before each test (Level 2)
resetMocks: true,
// Option 3: Restores mocks before each test (Level 3)
restoreMocks: true,
};
You can only set one of these to true. resetMocks is often the best balance of safety and isolation.
Command-Line Flags
You can also enable this behavior for a single run using a command-line flag:
# Level 1
npx jest --clearMocks
# Level 2
npx jest --resetMocks
# Level 3
npx jest --restoreMocks
Conclusion
Properly resetting mocks is essential for reliable tests. Jest provides a clear hierarchy of tools for this purpose.
mockClear()is for resetting call history while keeping a mocked implementation.mockReset()is for wiping both call history and the implementation.mockRestore()is for completely undoing ajest.spyOn()and restoring the original function.
For most projects, configuring resetMocks: true in your jest.config.js provides the best balance of safety and convenience, ensuring every test starts with a completely fresh set of mocks.