A mock function is a fake function that automatically records how it was used: how many times it was called, with what arguments, and what it returned. This lesson explores mock functions and the assertions built around them.
What a Mock Function Tracks
Every mock function created with jest.fn() exposes a .mock property containing arrays like calls (the arguments passed on each call) and results (what the function returned or threw each time). You rarely inspect .mock directly — instead, you use expect() matchers built specifically for mock functions.
This tracking happens automatically for every mock, with no extra setup required beyond creating it with jest.fn().
.toHaveBeenCalled() only checks the function was invoked at least once.
.toHaveBeenCalledTimes(n) checks the exact number of invocations.
.toHaveBeenCalledWith(...) checks at least one call matched these exact arguments.
.toHaveBeenNthCalledWith(n, ...) checks the arguments of a specific call by position.
Mock Function Matchers Cheat Sheet
Every matcher for asserting on how a mock function was used.
Matcher
Checks
.toHaveBeenCalled()
Called at least once
.toHaveBeenCalledTimes(n)
Called exactly n times
.toHaveBeenCalledWith(...)
At least one call used these arguments
.toHaveBeenLastCalledWith(...)
Most recent call used these arguments
.toHaveBeenNthCalledWith(n, ...)
The nth call used these arguments
.toHaveReturnedWith(x)
At least one call returned this value
mockFn.mock.calls
Raw array of arguments for every call
Inspecting mock.calls Directly
For cases the built-in matchers don't cover neatly, you can inspect mockFn.mock.calls directly — it's a plain array of arrays, one entry per call, each containing the arguments passed that time.
Mock functions are the natural choice for testing code that accepts a callback, since you can pass a jest.fn() in place of a real callback and assert on how (and whether) it was invoked, without needing any real side effect to happen.
function processItems(items, onEach) {
items.forEach((item) => onEach(item));
}
test('calls onEach for every item', () => {
const onEach = jest.fn();
processItems(['a', 'b', 'c'], onEach);
expect(onEach).toHaveBeenCalledTimes(3);
expect(onEach).toHaveBeenNthCalledWith(2, 'b');
});
Common Mistakes
Using .toHaveBeenCalled() when you actually need to check specific arguments with .toHaveBeenCalledWith().
Forgetting mock call history persists across tests unless cleared, causing count assertions to fail unexpectedly.
Manually looping over mock.calls when a built-in matcher already does exactly what's needed.
Not testing the arguments passed to a callback, only that it was called at all.
Key Takeaways
Every jest.fn() mock automatically tracks its calls, arguments, and return values.
A family of toHaveBeenCalled... matchers covers nearly every common assertion need.
mockFn.mock.calls gives raw access to call arguments for custom checks.
Mock functions are ideal for testing code that accepts a callback.
Pro Tip
Reach for .toHaveBeenCalledWith() far more often than .toHaveBeenCalled() — checking the exact arguments catches far more real bugs than just confirming a function ran.
You now understand how mock functions track calls. Next, dig into jest.fn() itself and all the ways you can configure it.