Skip to content

Jest Mock Function Not Called Fix

DodaTech Updated 2026-06-24 3 min read

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() in beforeEach
  • 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

  1. Using head and tail instead of pattern matching, causing runtime errors on empty lists
  2. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
  3. Using return to 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

### Why does my mock function show 0 calls when I just called it?

The mock and the implementation reference different function instances. If the code under test imported the original module before you created the mock, it holds a reference to the real function. Use jest.mock() which is hoisted before imports.

Should I use jest.fn() or jest.spyOn()?

Use jest.fn() for standalone mock functions you pass as arguments. Use jest.spyOn() when you want to wrap an existing method on an object and optionally call through to the real implementation.

How do I reset call counts between tests without losing mock implementations?

Use jest.clearAllMocks() in beforeEach to reset call counts and instances. Use jest.resetAllMocks() to also clear implementations. Use jest.restoreAllMocks() to restore originals — useful for spyOn.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro