Jest Mock Function Not Called Fix
In this tutorial, you'll learn about Jest Mock Function Not Called Fix. We cover key concepts, practical examples, and best practices.
Your test asserts expect(mockFn).toHaveBeenCalled() but it fails — the mock function was never invoked. This usually means your test and implementation reference different function instances.
The Problem
// WRONG — mock created after implementation is already imported
const sendEmail = jest.fn();
const notifyUser = () => {
sendEmail('user@example.com', 'Welcome!');
};
notifyUser();
expect(sendEmail).toHaveBeenCalled();
expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: 1
Received number of calls: 0
Your test creates a new mock after notifyUser already captures the original sendEmail in its closure. The mock replaces a different reference.
Step-by-Step Fix
1. Use jest.mock for module-level mocking
// RIGHT — mock the module before any imports
jest.mock('./emailService', () => ({
sendEmail: jest.fn()
}));
import { sendEmail } from './emailService';
import { notifyUser } from './notifyUser';
test('sends welcome email', () => {
notifyUser('user@example.com');
expect(sendEmail).toHaveBeenCalledWith('user@example.com', 'Welcome!');
});
jest.mock is hoisted to the top of the file by Jest's transform. This ensures the mock exists before any module imports execute.
2. Spy on object methods
// WRONG — replacing the method on the wrong instance
const emailer = { send: () => {} };
emailer.send = jest.fn();
// RIGHT — use spyOn to track calls
jest.spyOn(emailer, 'send');
emailer.send('test@example.com');
expect(emailer.send).toHaveBeenCalled();
3. Check async execution order
// WRONG — assertion runs before async callback
jest.mock('./api');
import { fetchData } from './api';
fetchData.mockResolvedValue({ ok: true });
const handler = () => fetchData().then(data => console.log(data));
handler();
expect(fetchData).toHaveBeenCalled(); // passes
expect(console.log).toHaveBeenCalled(); // FAILS — promise hasn't resolved yet
// RIGHT — await the promise
test('logs fetched data', async () => {
fetchData.mockResolvedValue({ ok: true });
const handler = async () => {
const data = await fetchData();
console.log(data);
};
await handler();
expect(console.log).toHaveBeenCalledWith({ ok: true });
});
4. Reset mocks between tests
beforeEach(() => {
jest.clearAllMocks();
});
Without clearing, call counts accumulate across tests. A test that passes in isolation might fail when run in sequence because a previous test already called the mock.
Expected output:
PASS tests/notifyUser.test.js
✓ sends welcome email (12 ms)
✓ handles async callback (8 ms)
Prevention Tips
- Use
jest.mock()at the top of the file for module mocking - Call
jest.clearAllMocks()inbeforeEach - Use
jest.spyOn()instead of manual mock assignment - Await promises inside tests before asserting
- Verify mock references with
jest.isMockFunction(fn)
Common Mistakes with mock not called
- Using
headandtailinstead of pattern matching, causing runtime errors on empty lists - Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
- Using
returnto exit a function early instead of wrapping a pure value in the monad
These mistakes appear frequently in real-world JEST code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro