{"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":"exception","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/f49721c78e195558b40913977c9230f5b7f559d8/packages/jest-jasmine2/src/jasmine/SpyStrategy.ts#L74-L106","documentation":"SpyStrategy.callFake(fn) replaces the spy's behavior with a user-supplied function. SpyStrategy.ts:90-95 throws a TypeError if fn is not a function, because the exec plan calls plan.apply(this, arguments) and a non-function would fail with a confusing error at call time. The guard fails fast with the offending value in the message.","triggerScenarios":"Calling `spy.and.callFake(someValue)` where someValue is not a function — e.g. a result object, undefined, a number, or a config. The `typeof fn !== 'function'` check at SpyStrategy.ts:91 throws TypeError at line 92.","commonSituations":"Passing the return value instead of the function (callFake(apiResponse) vs callFake(() => apiResponse)); a binding that resolved to undefined; refactor that changed the fake from a function to a value; passing an async function shape incorrectly.","solutions":["Pass a function: spy.and.callFake(() => value) or spy.and.callFake(realFn).","If you want a constant return, use spy.and.returnValue(value) instead of callFake.","Inspect the interpolated fn in the message to find which non-function was passed and fix the binding."],"exampleFix":"// before — value passed instead of function\nspy.and.callFake({ status: 200 });\n\n// after — wrap in a function (or use returnValue)\nspy.and.callFake(() => ({ status: 200 }));\n// or\nspy.and.returnValue({ status: 200 });","handlingStrategy":"type-guard","validationCode":"function callFakeSafe(spy: { and: { callFake: (fn: unknown) => unknown } }, fn: unknown) {\n  if (typeof fn !== 'function') {\n    throw new TypeError(`callFake expects a function, got ${typeof fn}`);\n  }\n  return spy.and.callFake(fn as Function);\n}","typeGuard":"function isFn(v: unknown): v is Function { return typeof v === 'function'; }\nif (!isFn(fn)) throw new TypeError('callFake needs a function');","tryCatchPattern":null,"preventionTips":["Use spy.and.returnValue(value) for constant returns instead of callFake(() => value) when no logic is needed.","Type your spy helpers so a non-function callFake is a compile error.","Double-check that you are passing the function itself, not its invocation result."],"tags":["jasmine2","spy","callfake","typeerror","spy-strategy"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}