{"record":{"id":"0cdee369173b1a3e","repo":"jestjs/jest","slug":"received-color-received-value-must-be-a-mock","errorCode":null,"errorMessage":"${RECEIVED_COLOR('received')} value must be a mock or spy function","messagePattern":"(.+?) value must be a mock or spy function","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/expect/src/spyMatchers.ts","lineNumber":1272,"sourceCode":"};\n\nconst isMock = (received: any) =>\n  received != null && received._isMockFunction === true;\n\nconst isSpy = (received: any) =>\n  received != null &&\n  received.calls != null &&\n  typeof received.calls.all === 'function' &&\n  typeof received.calls.count === 'function';\n\nconst ensureMockOrSpy = (\n  received: any,\n  matcherName: string,\n  expectedArgument: string,\n  options: MatcherHintOptions,\n) => {\n  if (!isMock(received) && !isSpy(received)) {\n    throw new Error(\n      matcherErrorMessage(\n        matcherHint(matcherName, undefined, expectedArgument, options),\n        `${RECEIVED_COLOR('received')} value must be a mock or spy function`,\n        printWithType('Received', received, printReceived),\n      ),\n    );\n  }\n};\n\nconst ensureMock = (\n  received: any,\n  matcherName: string,\n  expectedArgument: string,\n  options: MatcherHintOptions,\n) => {\n  if (!isMock(received)) {\n    throw new Error(\n      matcherErrorMessage(","sourceCodeStart":1254,"sourceCodeEnd":1290,"githubUrl":"https://github.com/jestjs/jest/blob/8e6d128e4a278059ecddecaa97400b04c8ae5fd9/packages/expect/src/spyMatchers.ts#L1254-L1290","documentation":"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.","triggerScenarios":"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().","commonSituations":"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.","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)."],"exampleFix":"// before\nconst handler = () => {};\ndoWork(handler);\nexpect(handler).toHaveBeenCalled(); // plain fn\n\n// after\nconst handler = jest.fn();\ndoWork(handler);\nexpect(handler).toHaveBeenCalled();\n// spying\nconst spy = jest.spyOn(service, 'save');\nservice.save();\nexpect(spy).toHaveBeenCalled();","handlingStrategy":"type-guard","validationCode":"const fn = received;\nif (!(fn != null && fn._isMockFunction === true) &&\n    !(fn != null && typeof fn.calls?.all === 'function')) {\n  throw new Error('call matchers require a jest.fn() or jest.spyOn() result');\n}\nexpect(fn).toHaveBeenCalled();","typeGuard":"const isMockOrSpy = (v: unknown): boolean =>\n  v != null && (v._isMockFunction === true ||\n    (typeof (v as any).calls?.all === 'function' && typeof (v as any).calls?.count === 'function'));","tryCatchPattern":null,"preventionTips":["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."],"tags":["jest","expect","matcher","spy","mock","type-error","tohavebeencalled"],"backgroundTag":null,"analyzedSha":"8e6d128e4a278059ecddecaa97400b04c8ae5fd9","analyzedAt":"2026-08-10T18:11:27.960Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}