jestjs/jest · error · Error

Jasmine spies would overwrite the 'and' and 'calls'…

Error message

Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon

What it means

When jasmine creates a spy, it copies enumerable properties from the original function onto the spy, then sets `spy.and` (the strategy) and `spy.calls` (the call tracker). If the original function ALREADY has its own `and` or `calls` property, jasmine would overwrite it and lose data — so createSpy throws this Error at createSpy.ts:65 to prevent silent clobbering.

Solutions

  1. Do not spy on an existing spy — spy on the original source function once.
  2. Remove or rename the `and`/`calls` property on the target function before spying.
  3. If you need to reset a spy, use `mockClear()`/`mockReset()` instead of re-creating it.
  4. Pass a plain function (without those properties) as originalFn to createSpy.

Example fix

// before
const spy1 = jasmine.createSpy('fn', fn);
const spy2 = jasmine.createSpy('fn', spy1); // spy1 has .and/.calls → throws
// after — reuse the existing spy
const spy = jasmine.createSpy('fn', fn);
spy.mockClear(); // reset instead of re-spying
Defensive patterns

Strategy: validation

Validate before calling

// Before spying, check the target does not already expose and/calls.
function isSafeToSpy(fn: Record<string, unknown>): boolean {
  return !('and' in fn) && !('calls' in fn);
}
// Usage:
if (isSafeToSpy(targetFn)) {
  spy = spyOn(obj, 'method');
} else {
  // target is already a spy or has conflicting props — reset instead
}

Type guard

function hasReservedProps(fn: Record<string, unknown>): boolean {
  return 'and' in fn || 'calls' in fn;
}

Prevention

When it happens

Trigger: Calling `jasmine.createSpy(name, fn)` where `fn` has an own property named `and` or `calls`. The loop at createSpy.ts:63 iterates `for (const prop in originalFn)` and checks `prop === 'and' || prop === 'calls'` at line 64.

Common situations: Spying on a function that is ITSELF already a spy (double-spying); spying on a function augmented with an `and` or `calls` property by another library; passing an object that masquerades as a function and has those keys; chaining createSpy on the output of createSpy.

Related errors


AI-assisted analysis of jestjs/jest@8e6d128e4a (2026-08-10). Data as JSON: /api/errors/a0b03fe50c9926e5. Report an issue: GitHub.

Appendix: source

Thrown at packages/jest-jasmine2/src/jasmine/createSpy.ts:65

    },
  });
  const callTracker = new CallTracker();
  const spy: Spy = function (...args) {
    const callData: Context = {
      object: this,
      args: Array.prototype.slice.apply(arguments),
    };

    callTracker.track(callData);
    const returnValue = spyStrategy.exec.apply(this, args);
    callData.returnValue = returnValue;

    return returnValue;
  };

  for (const prop in originalFn) {
    if (prop === 'and' || prop === 'calls') {
      throw new Error(
        "Jasmine spies would overwrite the 'and' and 'calls' properties " +
          'on the object being spied upon',
      );
    }

    spy[prop] = originalFn[prop];
  }

  spy.and = spyStrategy;
  spy.calls = callTracker;

  return spy;
}

export default createSpy;

View on GitHub (pinned to 8e6d128e4a)