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
- Do not spy on an existing spy — spy on the original source function once.
- Remove or rename the `and`/`calls` property on the target function before spying.
- If you need to reset a spy, use `mockClear()`/`mockReset()` instead of re-creating it.
- 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
- Never spy on an existing spy; use mockReset/mockRestore to reset it.
- Check for `.and`/`.calls` properties on the target function before createSpy.
- Keep a single spy per source method; track and reuse it across tests.
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
- Argument passed to callFake should be a function, got
- describe does not expect any arguments
- Invalid first argument. It must be a callback function.
- Invalid second argument
- Invalid second argument
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)