jestjs/jest · error · TypeError

Argument passed to callFake should be a function, got ${fn}

Error message

Argument passed to callFake should be a function, got ${fn}

What it means

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.

Source

Thrown at packages/jest-jasmine2/src/jasmine/SpyStrategy.ts:92

      const values = Array.prototype.slice.call(arguments);
      plan = function () {
        return values.shift();
      };
      return getSpy();
    };

    this.throwError = function (something) {
      const error =
        something instanceof Error ? something : new Error(something);
      plan = function () {
        throw error;
      };
      return getSpy();
    };

    this.callFake = function (fn) {
      if (typeof fn !== 'function') {
        throw new TypeError(
          `Argument passed to callFake should be a function, got ${fn}`,
        );
      }
      plan = fn;
      return getSpy();
    };

    this.stub = function (_fn) {
      plan = function () {};
      return getSpy();
    };
  }
}

View on GitHub (pinned to f49721c78e)

Solutions

  1. Pass a function: spy.and.callFake(() => value) or spy.and.callFake(realFn).
  2. If you want a constant return, use spy.and.returnValue(value) instead of callFake.
  3. Inspect the interpolated fn in the message to find which non-function was passed and fix the binding.

Example fix

// before — value passed instead of function
spy.and.callFake({ status: 200 });

// after — wrap in a function (or use returnValue)
spy.and.callFake(() => ({ status: 200 }));
// or
spy.and.returnValue({ status: 200 });
Defensive patterns

Strategy: type-guard

Validate before calling

function callFakeSafe(spy: { and: { callFake: (fn: unknown) => unknown } }, fn: unknown) {
  if (typeof fn !== 'function') {
    throw new TypeError(`callFake expects a function, got ${typeof fn}`);
  }
  return spy.and.callFake(fn as Function);
}

Type guard

function isFn(v: unknown): v is Function { return typeof v === 'function'; }
if (!isFn(fn)) throw new TypeError('callFake needs a function');

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03). Data as JSON: /data/errors/94db76f62a1e6af4.json. Report an issue: GitHub.