Skip to content

fix(jest-mock): remove leftover own accessor when restoring spyOn of an inherited getter/setter#16226

Merged
SimenB merged 5 commits into
jestjs:mainfrom
LeSingh1:fix/spyon-inherited-accessor-restore
Jun 21, 2026
Merged

fix(jest-mock): remove leftover own accessor when restoring spyOn of an inherited getter/setter#16226
SimenB merged 5 commits into
jestjs:mainfrom
LeSingh1:fix/spyon-inherited-accessor-restore

Conversation

@LeSingh1

@LeSingh1 LeSingh1 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Summary

jest.spyOn(object, key, 'get' | 'set') supports spying on an accessor that lives on the prototype chain rather than on the object itself. When the accessor is inherited, the spy is installed by defining a new own property on the object via Object.defineProperty(object, propertyKey, descriptor). The restore step then re-defines that same own descriptor on the object instead of removing it.

The result is that after mockRestore, the object keeps an own accessor descriptor that shadows the prototype. The value read right after restore is still correct because the restored descriptor copied the prototype accessor, but the link to the prototype is gone, so later changes to the prototype accessor are no longer observed through the instance, and hasOwnProperty(key) stays true on something that was originally inherited.

The method branch of spyOn already handles this correctly: it tracks whether the method was an own property and deletes the own property on restore when it was inherited (see the existing isMethodOwner handling and the "should delete previously inexistent methods when restoring" test). This change applies the same approach to the accessor branch in _spyOnProperty: when the spied accessor was inherited, restoring now deletes the own property so the original prototype accessor is exposed again.

Test plan

Added two tests under packages/jest-mock/src/__tests__/index.test.ts in the spyOnProperty block, covering an inherited getter and an inherited setter. Each test spies on the inherited accessor, restores, and asserts that no own descriptor is left on the instance and that the prototype accessor is still in effect (including after the prototype accessor is later replaced).

Both tests fail on main and pass with this change. The full jest-mock unit suite passes.

yarn jest packages/jest-mock/src/__tests__/index.test.ts
Tests:       161 passed, 161 total

@netlify

netlify Bot commented Jun 4, 2026

Copy link
Copy Markdown

Deploy Preview for jestjs ready!

Name Link
🔨 Latest commit eee1ef9
🔍 Latest deploy log https://app.netlify.com/projects/jestjs/deploys/6a37d7db93bb0300088fd1a4
😎 Deploy Preview https://deploy-preview-16226--jestjs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added the require-changelog If a PR does requires a changelog entry label Jun 4, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jun 4, 2026

Copy link
Copy Markdown

Open in StackBlitz

babel-jest

npm i https://pkg.pr.new/babel-jest@16226

babel-plugin-jest-hoist

npm i https://pkg.pr.new/babel-plugin-jest-hoist@16226

babel-preset-jest

npm i https://pkg.pr.new/babel-preset-jest@16226

create-jest

npm i https://pkg.pr.new/create-jest@16226

@jest/diff-sequences

npm i https://pkg.pr.new/@jest/diff-sequences@16226

expect

npm i https://pkg.pr.new/expect@16226

@jest/expect-utils

npm i https://pkg.pr.new/@jest/expect-utils@16226

jest

npm i https://pkg.pr.new/jest@16226

jest-changed-files

npm i https://pkg.pr.new/jest-changed-files@16226

jest-circus

npm i https://pkg.pr.new/jest-circus@16226

jest-cli

npm i https://pkg.pr.new/jest-cli@16226

jest-config

npm i https://pkg.pr.new/jest-config@16226

@jest/console

npm i https://pkg.pr.new/@jest/console@16226

@jest/core

npm i https://pkg.pr.new/@jest/core@16226

@jest/create-cache-key-function

npm i https://pkg.pr.new/@jest/create-cache-key-function@16226

jest-diff

npm i https://pkg.pr.new/jest-diff@16226

jest-docblock

npm i https://pkg.pr.new/jest-docblock@16226

jest-each

npm i https://pkg.pr.new/jest-each@16226

@jest/environment

npm i https://pkg.pr.new/@jest/environment@16226

jest-environment-jsdom

npm i https://pkg.pr.new/jest-environment-jsdom@16226

@jest/environment-jsdom-abstract

npm i https://pkg.pr.new/@jest/environment-jsdom-abstract@16226

jest-environment-node

npm i https://pkg.pr.new/jest-environment-node@16226

@jest/expect

npm i https://pkg.pr.new/@jest/expect@16226

@jest/fake-timers

npm i https://pkg.pr.new/@jest/fake-timers@16226

@jest/get-type

npm i https://pkg.pr.new/@jest/get-type@16226

@jest/globals

npm i https://pkg.pr.new/@jest/globals@16226

jest-haste-map

npm i https://pkg.pr.new/jest-haste-map@16226

jest-jasmine2

npm i https://pkg.pr.new/jest-jasmine2@16226

jest-leak-detector

npm i https://pkg.pr.new/jest-leak-detector@16226

jest-matcher-utils

npm i https://pkg.pr.new/jest-matcher-utils@16226

jest-message-util

npm i https://pkg.pr.new/jest-message-util@16226

jest-mock

npm i https://pkg.pr.new/jest-mock@16226

@jest/pattern

npm i https://pkg.pr.new/@jest/pattern@16226

jest-phabricator

npm i https://pkg.pr.new/jest-phabricator@16226

jest-regex-util

npm i https://pkg.pr.new/jest-regex-util@16226

@jest/reporters

npm i https://pkg.pr.new/@jest/reporters@16226

jest-resolve

npm i https://pkg.pr.new/jest-resolve@16226

jest-resolve-dependencies

npm i https://pkg.pr.new/jest-resolve-dependencies@16226

jest-runner

npm i https://pkg.pr.new/jest-runner@16226

jest-runtime

npm i https://pkg.pr.new/jest-runtime@16226

@jest/schemas

npm i https://pkg.pr.new/@jest/schemas@16226

jest-snapshot

npm i https://pkg.pr.new/jest-snapshot@16226

@jest/snapshot-utils

npm i https://pkg.pr.new/@jest/snapshot-utils@16226

@jest/source-map

npm i https://pkg.pr.new/@jest/source-map@16226

@jest/test-result

npm i https://pkg.pr.new/@jest/test-result@16226

@jest/test-sequencer

npm i https://pkg.pr.new/@jest/test-sequencer@16226

@jest/transform

npm i https://pkg.pr.new/@jest/transform@16226

@jest/types

npm i https://pkg.pr.new/@jest/types@16226

jest-util

npm i https://pkg.pr.new/jest-util@16226

jest-validate

npm i https://pkg.pr.new/jest-validate@16226

jest-watcher

npm i https://pkg.pr.new/jest-watcher@16226

jest-worker

npm i https://pkg.pr.new/jest-worker@16226

pretty-format

npm i https://pkg.pr.new/pretty-format@16226

commit: 98bfe06

@SimenB SimenB left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

@SimenB SimenB merged commit 55529e8 into jestjs:main Jun 21, 2026
6 checks passed
alexander-turner pushed a commit to alexander-turner/jest that referenced this pull request Jun 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

require-changelog If a PR does requires a changelog entry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants