jestjs/jest · error · Error
Jasmine spies would overwrite the 'and' and 'calls' properti
Error message
Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon
What it means
createSpy() copies enumerable properties from the original function onto the spy, then assigns the spy's own `and` (SpyStrategy) and `calls` (CallTracker) properties. If the original function already has an `and` or `calls` own property, copying would clobber them — so createSpy throws to avoid silently overwriting user data and breaking the spy API.
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 f49721c78e)
Solutions
- Restore the previous spy (spy.mockRestore() / mockClear()) before spying again so the function no longer carries and/calls.
- Spy on a fresh copy of the function instead of an already-decorated one.
- Audit for double-spying: search for repeated spyOn on the same object/method across setup files.
- If you control the original function, rename its and/calls properties to avoid the reserved names.
Example fix
// before — re-spying a function that already has .and/.calls const s1 = jest.spyOn(obj, 'fn'); const s2 = jest.spyOn(obj, 'fn'); // createSpy sees existing .and/.calls -> throws // after — restore before re-spying const s1 = jest.spyOn(obj, 'fn'); s1.mockRestore(); const s2 = jest.spyOn(obj, 'fn');
Defensive patterns
Strategy: type-guard
Validate before calling
function canSpy(fn: { and?: unknown; calls?: unknown }): boolean {
return !('and' in fn) && !('calls' in fn);
}
if (!canSpy(originalFn)) {
throw new Error('target already has and/calls properties; restore the previous spy first');
} Type guard
function isSpyable(fn: object): boolean {
const own = Object.getOwnPropertyNames(fn);
return !own.includes('and') && !own.includes('calls');
} Prevention
- Always restore spies (mockRestore/mockClear) before re-spying the same target.
- Avoid spying on functions that other libraries have decorated with and/calls.
- Centralize spy setup in beforeEach with matching afterEach restore to prevent double-spying.
When it happens
Trigger: Calling createSpy(name, originalFn) where originalFn has an own property named 'and' or 'calls' (createSpy.ts:63-69). This happens when spying on a function that was already spied upon, or a function decorated with its own and/calls bookkeeping.
Common situations: Re-spying an already-spied function ( Jasmine spy already installed .and/.calls); spying on a method that another library decorated with and/calls; double jest.spyOn on the same target without restore; spying on a function returned by another spy factory.
Related errors
- Spies must be created in a before function or a spec
- Argument passed to callFake should be a function, got ${fn}
- could not find an object to spy upon for ${methodName}()
- No method name supplied
- ${methodName}() method does not exist
AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03).
Data as JSON: /data/errors/a0b03fe50c9926e5.json.
Report an issue: GitHub.