jestjs/jest · error · Error

<spyOn> : ${propertyName} property does not exist Usage: spy

Error message

<spyOn> : ${propertyName} property does not exist
Usage: spyOn(<object>, <methodName>)

What it means

Thrown by SpyRegistry._spyOnProperty when no property descriptor is found for the named property (spyRegistry.ts:173-175). Property spying redefines the descriptor via Object.defineProperty, so a property with no existing accessor cannot be spied through the access-type path.

Source

Thrown at packages/jest-jasmine2/src/jasmine/spyRegistry.ts:174

          getErrorMsg(
            `could not find an object to spy upon for ${propertyName}`,
          ),
        );
      }

      if (!propertyName) {
        throw new Error(getErrorMsg('No property name supplied'));
      }

      let descriptor: PropertyDescriptor | undefined;
      try {
        descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
      } catch {
        // IE 8 doesn't support `definePropery` on non-DOM nodes
      }

      if (!descriptor) {
        throw new Error(getErrorMsg(`${propertyName} property does not exist`));
      }

      if (!descriptor.configurable) {
        throw new Error(
          getErrorMsg(`${propertyName} is not declared configurable`),
        );
      }

      if (!descriptor[accessType]) {
        throw new Error(
          getErrorMsg(
            `Property ${propertyName} does not have access type ${accessType}`,
          ),
        );
      }

      if (obj[propertyName] && isSpy(obj[propertyName])) {
        if (this.respy) {

View on GitHub (pinned to 8e6d128e4a)

Solutions

  1. Verify the descriptor exists: console.log(Object.getOwnPropertyDescriptor(obj, 'prop')).
  2. Spy on the correct object in the chain (prototype vs instance).
  3. Use the plain spyOn(obj, 'method') form for data fields rather than the property-access form.
  4. After a refactor, update the spy name to match the new property.

Example fix

// before
spyOn(store, 'cache', 'get'); // cache is a plain field, no getter
// after
spyOn(store, 'cache'); // or define a getter first
Defensive patterns

Strategy: validation

Validate before calling

if (!Object.getOwnPropertyDescriptor(obj, propertyName)) {
  throw new Error(`spyOn property: ${propertyName} has no descriptor on the target`);
}
spyOn(obj, propertyName, 'get');

Type guard

const hasPropertyDescriptor = (o: object, k: PropertyKey): boolean =>
  Object.getOwnPropertyDescriptor(o, k) !== undefined;

Prevention

When it happens

Trigger: spyOn(obj, 'missingProp', 'get') where the property does not exist on obj or its prototype chain, or spying on a plain data field (no getter) via the 'get' access type.

Common situations: Renamed property after a library upgrade; spying on a getter that is defined on a subclass while spying on the parent instance; prototype-only getters where the lookup at the instance level returns undefined; typos in property names.

Related errors


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