jestjs/jest · error · Error
${RECEIVED_COLOR('received')} value must be a mock or spy fu
Error message
${RECEIVED_COLOR('received')} value must be a mock or spy function What it means
Thrown by `ensureMockOrSpy` (spyMatchers.ts:1271), used by toHaveBeenCalled, toHaveBeenCalledTimes, toHaveBeenCalledWith, toHaveBeenLastCalledWith, and toHaveBeenNthCalledWith. It fires when the received value is neither a Jest mock (`_isMockFunction === true`) nor a Jasmine-style spy (has `.calls.all` and `.calls.count`). The call-counting matchers need `received.mock.calls`/`received.calls`, so a plain function is rejected.
Source
Thrown at packages/expect/src/spyMatchers.ts:1272
};
const isMock = (received: any) =>
received != null && received._isMockFunction === true;
const isSpy = (received: any) =>
received != null &&
received.calls != null &&
typeof received.calls.all === 'function' &&
typeof received.calls.count === 'function';
const ensureMockOrSpy = (
received: any,
matcherName: string,
expectedArgument: string,
options: MatcherHintOptions,
) => {
if (!isMock(received) && !isSpy(received)) {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, expectedArgument, options),
`${RECEIVED_COLOR('received')} value must be a mock or spy function`,
printWithType('Received', received, printReceived),
),
);
}
};
const ensureMock = (
received: any,
matcherName: string,
expectedArgument: string,
options: MatcherHintOptions,
) => {
if (!isMock(received)) {
throw new Error(
matcherErrorMessage(View on GitHub (pinned to 8e6d128e4a)
Solutions
- Create the function with jest.fn(): const fn = jest.fn(); then assert on fn.
- Spy on an existing method: const spy = jest.spyOn(obj, 'method'); then expect(spy).toHaveBeenCalled().
- Ensure you import/require the module fresh so the spy attaches to the instance actually used by the code under test.
- Verify the variable holds the mock, not the original (a common bug: spying then passing the wrong reference).
Example fix
// before
const handler = () => {};
doWork(handler);
expect(handler).toHaveBeenCalled(); // plain fn
// after
const handler = jest.fn();
doWork(handler);
expect(handler).toHaveBeenCalled();
// spying
const spy = jest.spyOn(service, 'save');
service.save();
expect(spy).toHaveBeenCalled(); Defensive patterns
Strategy: type-guard
Validate before calling
const fn = received;
if (!(fn != null && fn._isMockFunction === true) &&
!(fn != null && typeof fn.calls?.all === 'function')) {
throw new Error('call matchers require a jest.fn() or jest.spyOn() result');
}
expect(fn).toHaveBeenCalled(); Type guard
const isMockOrSpy = (v: unknown): boolean =>
v != null && (v._isMockFunction === true ||
(typeof (v as any).calls?.all === 'function' && typeof (v as any).calls?.count === 'function')); Prevention
- Always wrap callbacks with jest.fn() before passing them to the code under test.
- Use jest.spyOn(obj, 'method') and assert on the returned spy.
- Re-import modules after mocking so the spy attaches to the instance in use.
When it happens
Trigger: Calling `expect(plainFn).toHaveBeenCalled()` where plainFn is a normal function, an arrow function, undefined, a method reference that was not spied, or a function wrapped with a custom decorator instead of jest.fn()/jest.spyOn().
Common situations: Forgot to wrap with jest.fn() or jest.spyOn; spying on a method that doesn't exist on the object (spyOn returns nothing usable); the function was reassigned/lost its mock after a module re-import; testing a real implementation instead of the mock.
Related errors
- ${RECEIVED_COLOR('received')} value must be a mock function
- ${EXPECTED_COLOR('expected')} value must be a number
- ${RECEIVED_COLOR('received')} value must be a number
- ${EXPECTED_COLOR('expected')} value must be a function
- ${RECEIVED_COLOR('received')} value must not be null nor und
AI-assisted analysis of jestjs/jest@8e6d128e4a (2026-08-10).
Data as JSON: /api/errors/0cdee369173b1a3e.
Report an issue: GitHub.