{"record":{"id":"94db76f62a1e6af4","repo":"jestjs/jest","slug":"argument-passed-to-callfake-should-be-a-function","errorCode":null,"errorMessage":"Argument passed to callFake should be a function, got ${fn}","messagePattern":"Argument passed to callFake should be a function, got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/jest-jasmine2/src/jasmine/SpyStrategy.ts","lineNumber":92,"sourceCode":"      const values = Array.prototype.slice.call(arguments);\n      plan = function () {\n        return values.shift();\n      };\n      return getSpy();\n    };\n\n    this.throwError = function (something) {\n      const error =\n        something instanceof Error ? something : new Error(something);\n      plan = function () {\n        throw error;\n      };\n      return getSpy();\n    };\n\n    this.callFake = function (fn) {\n      if (typeof fn !== 'function') {\n        throw new TypeError(\n          `Argument passed to callFake should be a function, got ${fn}`,\n        );\n      }\n      plan = fn;\n      return getSpy();\n    };\n\n    this.stub = function (_fn) {\n      plan = function () {};\n      return getSpy();\n    };\n  }\n}\n","sourceCodeStart":74,"sourceCodeEnd":106,"githubUrl":"https://github.com/jestjs/jest/blob/8e6d128e4a278059ecddecaa97400b04c8ae5fd9/packages/jest-jasmine2/src/jasmine/SpyStrategy.ts#L74-L106","documentation":"A spy's `.callFake(fn)` replaces the spy's behavior with the given function. SpyStrategy.callFake validates that `fn` is a function at SpyStrategy.ts:91; if not, it throws a TypeError showing the actual value passed. Passing a non-function would silently break the spy's stub behavior, so jasmine fails fast.","triggerScenarios":"Calling `spy.and.callFake('not a function')`, `spy.and.callFake(undefined)`, or `spy.and.callFake({})` where a function was expected. The check `typeof fn !== 'function'` at line 91 triggers the throw at line 92.","commonSituations":"Passing the return value of a function instead of the function itself (e.g. `callFake(myFn())` instead of `callFake(myFn)`); passing an async value or a promise; a variable that was conditionally assigned and is undefined; refactoring that changed a function reference to an object.","solutions":["Pass the function reference, not its invocation: `spy.and.callFake(myFn)` (no parentheses).","If the fake should be async, pass an async function: `spy.and.callFake(async () => {...})`.","Check that the variable holding the function is defined before passing it."],"exampleFix":"// before\nspy.and.callFake(realImpl());\n// after\nspy.and.callFake(realImpl);","handlingStrategy":"type-guard","validationCode":"// Guard callFake calls with a type check.\nfunction safeCallFake(spy: { and: { callFake: (fn: Function) => unknown } }, fn: unknown) {\n  if (typeof fn !== 'function') {\n    throw new TypeError(`callFake requires a function, got ${typeof fn}`);\n  }\n  return spy.and.callFake(fn);\n}","typeGuard":"function isCallable(value: unknown): value is Function {\n  return typeof value === 'function';\n}","tryCatchPattern":null,"preventionTips":["Pass the function reference, not its return value: `callFake(fn)` not `callFake(fn())`.","For async fakes, pass an async arrow function.","Verify the function variable is defined before passing it."],"tags":["spy","callfake","typeerror","jasmine","api-misuse"],"backgroundTag":null,"analyzedSha":"8e6d128e4a278059ecddecaa97400b04c8ae5fd9","analyzedAt":"2026-08-10T18:11:27.960Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}