Skip to content

fix(jest-util): prevent infinite recursion when writing to soft-deleted data property#16175

Open
jon-zawada wants to merge 3 commits into
jestjs:mainfrom
jon-zawada:fix/globals-cleanup-soft-setter-recursion
Open

fix(jest-util): prevent infinite recursion when writing to soft-deleted data property#16175
jon-zawada wants to merge 3 commits into
jestjs:mainfrom
jon-zawada:fix/globals-cleanup-soft-setter-recursion

Conversation

@jon-zawada
Copy link
Copy Markdown
Contributor

Summary

Fixes #16044.

When globalsCleanup: 'soft' is enabled, Jest replaces globals set between test files with accessor properties that emit a deprecation warning on access. For data properties the fallback setter was:

descriptor.set ?? (value => Reflect.set(obj, key, value))

After the property is redefined as an accessor, Reflect.set re-invokes that same setter → infinite recursion → RangeError: Maximum call stack size exceeded. Any project using globalsCleanup: 'soft' that re-assigns a global from a previous test file would hit this.

The fix introduces a closure variable (storedValue) that the getter reads from and the setter writes to directly, with no Reflect.set involved:

  let storedValue = descriptor.value;
  const originalGetter = descriptor.get ?? (() => storedValue);
  const originalSetter = descriptor.set ?? (value => { storedValue = value; });

This also fixes a secondary issue where the getter would always return the value captured at deletion time even after a successful write.

Test plan

Two new tests added to packages/jest-util/src/tests/garbage-collection-utils.test.ts:

yarn jest packages/jest-util/src/__tests__/garbage-collection-utils.test.ts

Tests: 3 passed, 3 total

  • "does not recurse infinitely when writing to a soft-deleted data property" — would have thrown RangeError before the fix
  • "reflects the updated value after writing to a soft-deleted data property" — verifies the written value is readable back after the write

@netlify
Copy link
Copy Markdown

netlify Bot commented May 13, 2026

Deploy Preview for jestjs ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 0015c5e
🔍 Latest deploy log https://app.netlify.com/projects/jestjs/deploys/6a03c1debb7a1a00080ca55d
😎 Deploy Preview https://deploy-preview-16175--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.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 13, 2026

Open in StackBlitz

babel-jest

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

babel-plugin-jest-hoist

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

babel-preset-jest

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

create-jest

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

@jest/diff-sequences

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

expect

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

@jest/expect-utils

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

jest

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

jest-changed-files

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

jest-circus

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

jest-cli

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

jest-config

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

@jest/console

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

@jest/core

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

@jest/create-cache-key-function

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

jest-diff

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

jest-docblock

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

jest-each

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

@jest/environment

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

jest-environment-jsdom

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

@jest/environment-jsdom-abstract

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

jest-environment-node

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

@jest/expect

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

@jest/fake-timers

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

@jest/get-type

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

@jest/globals

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

jest-haste-map

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

jest-jasmine2

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

jest-leak-detector

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

jest-matcher-utils

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

jest-message-util

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

jest-mock

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

@jest/pattern

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

jest-phabricator

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

jest-regex-util

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

@jest/reporters

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

jest-resolve

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

jest-resolve-dependencies

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

jest-runner

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

jest-runtime

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

@jest/schemas

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

jest-snapshot

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

@jest/snapshot-utils

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

@jest/source-map

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

@jest/test-result

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

@jest/test-sequencer

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

@jest/transform

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

@jest/types

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

jest-util

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

jest-validate

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

jest-watcher

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

jest-worker

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

pretty-format

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

commit: 0015c5e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: globalsCleanup 'soft' mode causes infinite setter recursion (RangeError: Maximum call stack size exceeded)

1 participant