Skip to content

fix(jest-runtime): do not treat a leading # as a fragment delimiter - #16413

Merged
SimenB merged 3 commits into
jestjs:mainfrom
HuzaifaChaudary:fix/esm-package-imports-specifier
Sep 1, 2026
Merged

SimenB merged 3 commits into
jestjs:mainfrom
HuzaifaChaudary:fix/esm-package-imports-specifier

Conversation

@HuzaifaChaudary

Copy link
Copy Markdown
Contributor

Summary

Fixes #16412.

Every subpath in a package's imports field starts with #, and on 30.5.0 none of them resolve under ESM. import { value } from '#dep' fails with The requested module '#dep' does not provide an export named 'value'.

splitQueryAndFragment in packages/jest-runtime/src/internals/EsmLoader.ts looks for the first # and treats it as a fragment delimiter:

const hashIndex = specifier.indexOf('#');

For #dep that index is 0, so the specifier splits into pathOrSpecifier: '' and suffix: '#dep'. The resolver is then handed an empty string and the specifier never reaches the imports map at all, which is also why a custom resolver in the jest config does not see it.

A leading # is not a fragment delimiter. In Node's resolution algorithm a specifier starting with # is a package-imports specifier and goes to PACKAGE_IMPORTS_RESOLVE against the nearest package.json. So it passes through whole, next to the existing data: carve-out:

if (specifier.startsWith('data:') || specifier.startsWith('#')) {
  return {pathOrSpecifier: specifier, suffix: ''};
}

git log -S splitQueryAndFragment gives one commit, 30ce9da (#16375), first released in 30.5.0, so this is a regression from 30.4.2 and the change restores the earlier behaviour rather than adding anything.

The reporter found the cause and the one line guard. I checked it against Node, wrote the tests, and checked the other direction.

checked against node 24 first

I wanted to know whether the whole specifier is the key or only the part before a ?, because that decides whether the suffix has to stay attached:

specifier node 24.20
#dep resolves
#lib/wild.mjs through "#lib/*" resolves
#dep?v=2 ERR_PACKAGE_IMPORT_NOT_DEFINED

Node looks up the whole thing, so returning an empty suffix is right and the query must not be split off either. The wildcard form starts with # too, so it was broken the same way and is covered.

one thing I deliberately did not change

#dep?v=2 is not a package-imports key in Node, but jest reaches a different error for it. unstable_importModule ends at:

ENOENT: no such file or directory, open '.../imports-dep.mjs?v=2'

so the resolver matches the key and carries the query into the resolved path, and FileCache then tries to open a file with ?v=2 in its name. That is not new, it is what 30.4.2 does as well since the specifier reached the resolver whole there too, and it is unrelated to this bug. I found it while writing a test for the boundary and then dropped the test rather than pin a behaviour that is arguably its own small bug. Happy to open a separate issue if it is worth one.

Test plan

Two tests in runtime_esm_sync_graph.test.ts, one going through a module that imports both the plain and the wildcard form, one importing #imports-dep directly as the entry specifier. Fixtures add an imports map to test_esm_sync_graph_root/package.json.

yarn jest packages/jest-runtime/src/__tests__/runtime_esm_sync_graph.test.ts:

Tests: 154 passed, 154 total

with the guard taken back out and nothing else changed:

Tests: 2 failed, 152 passed, 154 total

SyntaxError: The requested module '#imports-dep' does not provide an export named 'value'

which is the error from the issue.

The opposite direction, a # that is a real fragment, is already covered in the same file by ./stateful.mjs#frag, ./url-reporter.mjs?#frag, ./url-reporter.mjs?tag=1#frag and the import.meta.resolve case, and all of them still pass, so the guard is not swallowing fragments that should split.

Also run: yarn build:ts clean, yarn typecheck:tests exit 0, eslint clean on the changed files.

yarn jest packages/jest-runtime reports 6 pre-existing failures in this environment, all ENAMETOOLONG from jest-haste-map writing a cache filename built out of my checkout path. Same 6 on a clean checkout with no changes, 578 tests there against 581 here, so the only difference is the 2 added tests plus the fixture module.

Copilot AI lite review requested due to automatic review settings August 31, 2026 13:34
@netlify

netlify Bot commented Aug 31, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for jestjs ready!

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

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

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

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@linux-foundation-easycla

linux-foundation-easycla Bot commented Aug 31, 2026 •

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: HuzaifaChaudary / name: Huzaifa Iftikhar (0cc9b7e, a6b57a3)
  • ✅ login: SimenB / name: Simen Bekkhus (ae22975)

a specifier that starts with # is a package imports specifier that node
resolves against the nearest package.json rather than a url with a
fragment. splitQueryAndFragment found the # at index 0 and split #dep
into an empty path plus a #dep suffix so the resolver got nothing and
the specifier never reached the imports map.
@HuzaifaChaudary
HuzaifaChaudary force-pushed the fix/esm-package-imports-specifier branch from 8ecf50c to 0cc9b7e Compare August 31, 2026 13:36
@pkg-pr-new

pkg-pr-new Bot commented Aug 31, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

babel-jest

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

babel-plugin-jest-hoist

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

babel-preset-jest

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

create-jest

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

@jest/diff-sequences

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

expect

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

@jest/expect-utils

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

jest

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

jest-changed-files

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

jest-circus

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

jest-cli

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

jest-config

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

@jest/console

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

@jest/core

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

@jest/create-cache-key-function

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

jest-diff

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

jest-docblock

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

jest-each

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

@jest/environment

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

jest-environment-jsdom

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

@jest/environment-jsdom-abstract

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

jest-environment-node

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

@jest/expect

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

@jest/fake-timers

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

@jest/get-type

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

@jest/globals

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

jest-haste-map

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

jest-jasmine2

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

jest-leak-detector

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

jest-matcher-utils

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

jest-message-util

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

jest-mock

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

@jest/pattern

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

jest-phabricator

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

jest-regex-util

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

@jest/reporters

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

jest-resolve

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

jest-resolve-dependencies

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

jest-runner

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

jest-runtime

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

@jest/schemas

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

jest-snapshot

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

@jest/snapshot-utils

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

@jest/source-map

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

@jest/test-result

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

@jest/test-sequencer

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

@jest/transform

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

@jest/types

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

jest-util

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

jest-validate

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

jest-watcher

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

jest-worker

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

pretty-format

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

commit: ae22975

A leading `#` opens a package-imports specifier, so it is not a fragment
delimiter - but the rest of the specifier still splits as usual. Skipping
the split for the whole string leaves `?v=2` glued to the resolved path,
which `pathToFileURL` percent-encodes into a filename that does not exist:

    ENOENT: no such file or directory, open '.../url-reporter.mjs?v=2'

So start the delimiter scan at index 1 for a `#` specifier. Node reaches
the same instance by the other route - its wildcard substitution puts the
query in the target URL - so `#lib/a.mjs?v=2` loads `a.mjs` under its own
module instance with the query on `import.meta.url`.

Two divergences stay, both predating this: jest-resolve strips the query
before the `imports` lookup, so `#dep?v=2` resolves where Node raises
ERR_PACKAGE_IMPORT_NOT_DEFINED, and a wildcard target with the `*` in the
middle (`./lib/pre-*.mjs`) resolves where Node raises ERR_MODULE_NOT_FOUND.

@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 for the PR! I had started fixing this before seeing your PR, so I pushed up my changes next to yours 🙂

@SimenB
SimenB requested a balanced review from Copilot August 31, 2026 14:07
@SimenB

SimenB commented Aug 31, 2026

Copy link
Copy Markdown
Member

Can you sign the CLA? Otherwise I can't merge it

@HuzaifaChaudary

Copy link
Copy Markdown
Contributor Author

the one red job here is a pre-existing flake and not this change. writing down what i checked so nobody has to repeat it.

macOS with shard 2/3 / Node LTS using jest-jasmine2 failed, and it failed with a different suite on each retry:

attempt 1  notify > does not report --notify flag   e2e/__tests__/detectOpenHandles.ts
attempt 2  notify > does not report --notify flag   e2e/__tests__/detectOpenHandles.ts
attempt 3  Test suite failed to run                 e2e/__tests__/locationInResults.test.ts

the same job fails on main. run 33081301530 on 3aa9b8b from 27 august, which is before this branch existed, same job name and the same first test:

notify > does not report --notify flag
FAIL packages/jest-haste-map/src/crawlers/__tests__/watchman.test.js
FAIL packages/jest-core/src/__tests__/TestScheduler.test.js
FAIL packages/jest-jasmine2/src/__tests__/collectSpecs.test.ts

again a different set each retry. 6 of the last 12 Node CI runs on main are failures.

none of those suites touch esm specifier resolution, and the change here is four lines inside splitQueryAndFragment. the runtime esm suite that does cover it is green, and packages/jest-runtime passes on every other shard in this run. everything else here is green, 69 of 69, with the 28 cancelled ones being the fail-fast on that shard.

separately, EasyCLA is still red on my side. i have passed the signing link to the account holder, it is not something i can action myself.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

@HuzaifaChaudary

Copy link
Copy Markdown
Contributor Author

your version is better than mine and i can show why rather than just agree.

my measurement was right but i only tested half of it. i checked #dep?v=2 against an exact imports key, got ERR_PACKAGE_IMPORT_NOT_DEFINED, and concluded the whole string is the key so nothing should split. i never tested the wildcard form. node 24.20:

#dep?v=2                  ->  ERR_PACKAGE_IMPORT_NOT_DEFINED
#lib/urlrep.mjs?v=2       ->  ok, import.meta.url = .../lib/urlrep.mjs?v=2

and the two are distinct instances:

same namespace? false   urls: urlrep.mjs   urlrep.mjs?v=2

so for an exact key the query really is part of the key and there is nothing to reach, but for a wildcard key the * substitution puts urlrep.mjs?v=2 into the target and node does reach the module with the query on import.meta.url. exactly what your test asserts. scanFrom = 1 gets both right where my early return only got the first one, and it is also why the ENOENT i wrote about above is a real bug and not just a wart to leave alone. i had called that out of scope, which was the wrong call.

155 passed locally on ae22975 with yarn jest packages/jest-runtime/src/__tests__/runtime_esm_sync_graph.test.ts.

on the CLA, that is with the account holder now, not something i can sign myself. should be done shortly.

@HuzaifaChaudary

Copy link
Copy Markdown
Contributor Author

cla is signed, sorry for the lag on that. it sat with me and i just forgot to go and do it, no better reason than that.

EasyCLA is green now and the rest is 100 of 100 with the state reading clean, so it is ready whenever you are. thanks for taking the scanFrom = 1 version further than i had it.

@SimenB
SimenB merged commit cda97a3 into jestjs:main Sep 1, 2026
105 checks passed
renovate Bot added a commit to andrei-picus-tink/auto-renovate that referenced this pull request Sep 6, 2026
| datasource | package | from   | to     |
| ---------- | ------- | ------ | ------ |
| npm        | jest    | 30.4.2 | 30.5.1 |


## [v30.5.1](https://github.com/jestjs/jest/blob/HEAD/CHANGELOG.md#3051)

##### Fixes

- `[jest-config]` Don't warn about global-only options in the config that supplies the global config - the root config a project resolves to, or the first entry of `--projects` when no root config is passed ([#16411](jestjs/jest#16411))
- `[jest-config, jest-types]` Stop accepting `reporters`, `coverageReporters`, `workerIdleMemoryLimit`, `cwd` and `runnerOptions` in a project config - they were silently ignored, and now warn like the other global-only options ([#16411](jestjs/jest#16411))
- `[jest-config, jest-validate]` Warn about `maxWorkers` and `coverageThreshold` in a project config instead of dropping them without a word ([#16411](jestjs/jest#16411))
- `[jest-resolve]` Match `moduleNameMapper` patterns against the specifier as written again (reverting [#16390](jestjs/jest#16390)) ([#16417](jestjs/jest#16417))
- `[jest-runtime]` Resolve package `imports` specifiers like `#dep` under ESM again ([#16413](jestjs/jest#16413))

##### Chore & Maintenance

- `[jest-util]` Name the `testEnvironmentOptions.globalsCleanup` option and link the docs from the `JEST-01` deprecation warning, and document the option's modes ([#16404](jestjs/jest#16404))


## [v30.5.0](https://github.com/jestjs/jest/blob/HEAD/CHANGELOG.md#3050)

##### Features

- `[@jest/expect-utils, jest-mock]` Add `mockFn.whenCalledWith(...args)` for configuring return values per argument list, with first-class asymmetric-matcher support ([#16053](jestjs/jest#16053))
- `[@jest/expect-utils]` Export `AsymmetricMatcher` and `FunctionParameters` types (previously private to `expect`) ([#16053](jestjs/jest#16053))
- `[jest-circus, jest-core, jest-jasmine2, jest-test-result, jest-types]` `--collectTests` now expands `test.each`/`describe.each` cases and reports per-status counts (skipped/todo via the new `wouldRun` flag for selected tests) plus a summary line that match a real run, including under `--testNamePattern` and `.only`/`fdescribe` focus on both the circus and jasmine2 runners ([#16259](jestjs/jest#16259))
- `[jest-circus, jest-environment, jest-runtime, jest-types]` Add describe-level retries via `jest.retryTimes(..., {entireDescribe: true})` ([#16322](jestjs/jest#16322))
- `[jest-circus, jest-message-util, jest-reporters, jest-types]` Add `retryMessages` to `AssertionResult` and export `formatErrorStack`, so the retry log renders nested `cause` and `AggregateError` sections with code frames instead of serialized `[cause]:`/`[errors]:` markers ([#16316](jestjs/jest#16316))
- `[jest-circus, jest-types]` Add `unhandledErrorsDetailed` to `Circus.RunResult`, so an unhandled rejection reports its `cause` chain and `AggregateError` entries with code frames instead of a pre-serialized stack ([#16316](jestjs/jest#16316))
- `[jest-haste-map]` Replace `NodeWatcher` and `FSEventsWatcher` with `@parcel/watcher` for the non-watchman watch path ([#16188](jestjs/jest#16188))
- `[jest-resolve]` Bump `unrs-resolver` to 1.12.1, remove `jest-pnp-resolver` and unnecessary checks ([#15721](jestjs/jest#15721))
- `[jest-resolve]` Honor Node's `--preserve-symlinks` / `NODE_PRESERVE_SYMLINKS` in the default resolver by passing `symlinks: false` to `unrs-resolver` ([#16260](jestjs/jest#16260))
- `[jest-runtime]` Apply automocking and manual `__mocks__` files to synchronously evaluable ESM graphs on Node 24.9+ - static imports, dynamic `import()` and `require()` of an ESM file now generate an automock from the real module's namespace instead of failing with "Attempting to import a mock without a factory". Graphs that need async evaluation (top-level await) or an async-only resolver or transformer still throw ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Route `process.getBuiltinModule` through the sandbox, so it returns the sandbox `process` and the hooked `node:module` instead of the host's ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Throw an actionable error from `module.register()` and `module.registerHooks()` inside a test - the hooks attached to the loader running Jest itself, never saw the sandboxed requires they were meant for, and stayed registered for every later test file in the worker ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Surface resolution and import-attribute errors in an ESM graph before executing any of its CJS dependencies on Node 24.9+, matching Node's run-nothing-on-a-broken-graph behavior; the legacy loader on older versions keeps its linking-time execution order ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Throw `ERR_SOURCE_PHASE_NOT_DEFINED` with an actionable message for `import source` and `import.source()`, instead of failing at instantiation with V8's bare "Source phase import object is not defined" ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Emit the JSON-without-import-attribute deprecation warning once per test file instead of once per worker, so it is no longer silently swallowed for every file after the first ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Set `import.meta.main` to `true` in the test file and `false` in every module it loads, matching Node 24+ ([#16367](jestjs/jest#16367))
- `[jest-runtime]` Resolve the `module-sync` export condition, so a package that exposes its ESM entry point for `require()` loads the same file Node would ([#16336](jestjs/jest#16336))
- `[jest-snapshot]` Add external snapshot paths to custom reporter failure details ([#16374](jestjs/jest#16374))

##### Fixes

- `[jest-console, jest-reporters]` `CustomConsole` now buffers console output so `TestResult.console` is populated for reporters when `verbose` is enabled, while `GitHubActionsReporter` avoids replaying buffered output in verbose mode ([#16155](jestjs/jest#16155))
- `[expect, jest-message-util, jest-pattern, jest-regex-util, jest-util]` Revert `node:` protocol imports to restore webpack/browser-bundle compatibility ([#16167](jestjs/jest#16167))
- `[expect]` Widen `toMatchObject` and `objectContaining` parameter type from `Record<string, unknown>` to `object` so class instances are accepted ([#16196](jestjs/jest#16196))
- `[jest-circus]` Call a generator test body with the shared test context, so `this` matches what a regular test function receives ([#16347](jestjs/jest#16347))
- `[jest-circus]` Capture the error listeners of the parent process instead of the in-sandbox `process`, so listeners registered before the test file survive teardown and sandbox listeners no longer leak onto the parent ([#16347](jestjs/jest#16347))
- `[jest-circus]` Clear `currentlyRunningTest` after skipped and todo tests ([#16342](jestjs/jest#16342))
- `[jest-circus]` Prevent late `done()` callbacks from affecting later test or hook invocations ([#16343](jestjs/jest#16343))
- `[jest-circus, jest-jasmine2]` Honor `--expand` when formatting `node:assert` failures, instead of always collapsing the diff ([#16347](jestjs/jest#16347))
- `[jest-circus, jest-jasmine2, jest-message-util]` Serialize the inner errors of an `AggregateError` into `failureMessages`, `retryReasons` and `unhandledErrors`, so `--json` output and reporter annotations include them ([#16316](jestjs/jest#16316))
- `[jest-circus, jest-snapshot]` Keep snapshot state and counts correct when a test retries ([#16344](jestjs/jest#16344))
- `[@jest/create-cache-key-function]` Include the caller support flags in the generated key, so a transformer that emits ESM or CJS based on them no longer shares one cache entry between the two ([#16331](jestjs/jest#16331))
- `[@jest/create-cache-key-function]` Include the stringified project config in the generated key, so editing a transformer's own settings invalidates what it cached ([#16331](jestjs/jest#16331))
- `[@jest/transform]` Include the caller support flags in a transform's cache key, so a file transformed both as ESM and as CJS no longer serves one shape's output for the other ([#16331](jestjs/jest#16331))
- `[jest-config]` Add missing `findRelatedTests`, `outputFile`, and `replname` entries to `ValidConfig` so they no longer trigger spurious "Unknown option" warnings ([#16224](jestjs/jest#16224))
- `[jest-config]` Use `--config` for the global config when multiple `--projects` are specified ([#16273](jestjs/jest#16273))
- `[jest-core]` Serialize `bigint` values in `--json` and `--outputFile` output as their literal form (`4n`), instead of failing the run with `TypeError: Do not know how to serialize a BigInt` ([#16338](jestjs/jest#16338))
- `[jest-core]` Do not report a `CustomGC` async resource (used by N-API addons such as napi-rs for per-isolate GC bookkeeping) as an open handle, since it is `napi_unref`'d by the addon and can never keep the event loop alive ([#16379](jestjs/jest#16379))
- `[jest-each]` Keep a `$&`, `` $` ``, `$'` or `$$` inside a `%p` param value out of the replacement, so the title shows the value instead of the text around it ([#16338](jestjs/jest#16338))
- `[jest-each]` Interpolate a `bigint` into a `%j` title as its literal form (`"4n"`) at any depth, instead of throwing `TypeError: Do not know how to serialize a BigInt` while collecting the tests ([#16338](jestjs/jest#16338))
- `[jest-environment, jest-runtime]` Bind `sandboxInjectedGlobals` to the right values when `injectGlobals` is `false`, instead of shifting every one of them by a position ([#16377](jestjs/jest#16377))
- `[jest-environment-node, jest-util]` Only warn about a conflicting `globalsCleanup` mode when one was explicitly configured, and follow the mode that is actually in effect ([#16323](jestjs/jest#16323))
- `[jest-environment-node, jest-util]` Stop resolving lazy globals when setting up an environment, so Node 26's builtin module globals are no longer loaded (and no longer emit their deprecation warnings) for every test file ([#16324](jestjs/jest#16324))
- `[jest-haste-map]` Keep watch mode alive when an outside process briefly makes a file unreadable on Windows, instead of tearing the watcher down on `EPERM` ([#16295](jestjs/jest#16295))
- `[jest-haste-map]` Keep indexing when an outside process holds a file open on Windows, instead of failing the whole crawl on `EPERM` ([#16358](jestjs/jest#16358))
- `[jest-haste-map]` Keep a duplicated manual mock resolving when the file it pointed at is deleted in watch mode ([#16360](jestjs/jest#16360))
- `[jest-haste-map]` Shut the worker farm down when a duplicate manual mock aborts the build under `throwOnModuleCollision` ([#16354](jestjs/jest#16354))
- `[jest-haste-map]` Attach the watchman client's `error` listener before the first command, so a watchman failure falls back to the node crawler instead of crashing on an unhandled `error` event, and always end the client ([#16355](jestjs/jest#16355))
- `[jest-haste-map]` Stop delivering watch events after `WatchmanWatcher` is closed, and route its warnings through the configured console ([#16355](jestjs/jest#16355))
- `[jest-haste-map]` Restore the nested `duplicates` index correctly in `ModuleMap.fromJSON`, so a haste collision reported inside a test worker raises `DuplicateHasteCandidatesError` instead of a `TypeError` ([#16353](jestjs/jest#16353))
- `[jest-haste-map]` Match watched files on a full extension, so `moduleFileExtensions: ['js']` no longer accepts `foo.mjs` ([#16352](jestjs/jest#16352))
- `[jest-haste-map]` Delimit the fields that make up the haste map cache key, so two different option sets cannot hash to the same cache file ([#16352](jestjs/jest#16352))
- `[jest-message-util]` Print the inner errors of an `AggregateError` thrown inside a test ([#16316](jestjs/jest#16316))
- `[jest-message-util]` Indent nested `cause` and `AggregateError` sections of a test failure by one level per depth, so the nesting is legible instead of rendering flat ([#16316](jestjs/jest#16316))
- `[jest-message-util]` Color stack traces line by line so blank lines stay blank ([#16316](jestjs/jest#16316))
- `[jest-message-util]` Detect Jest's own frames without assuming the checkout directory's name, and cover `@jest/*` packages, so stack traces and code frames point at user code ([#16326](jestjs/jest#16326))
- `[jest-mock]` `mockResolvedValue` / `mockRejectedValue` now see all overload return types, so a Promise-returning overload survives even when a later overload returns a non-Promise (e.g. `pg.Client['end']`) ([#16237](jestjs/jest#16237))
- `[@jest-environment/jsdom-abstract]` Make `@types/jsdom` a peer dependency ([#16166](jestjs/jest#16166))
- `[jest-mock]` Remove the leftover own accessor descriptor when restoring a `spyOn` of an inherited getter or setter, so the instance keeps reflecting the prototype ([#16226](jestjs/jest#16226))
- `[jest-resolve]` Include `extensionsToTreatAsEsm` in the `shouldLoadAsEsm` cache key, so projects with different extension lists don't read each other's answers ([#16369](jestjs/jest#16369))
- `[jest-resolve]` Make `getModuleIDAsync` build and cache `data:` URI module IDs the same way as `getModuleID` ([#16370](jestjs/jest#16370))
- `[jest-resolve]` Keep the `node:` prefix when resolving a core module asynchronously, so a builtin that only exists prefixed (`node:sea`, `node:sqlite`, `node:test`, `node:test/reporters`) resolves instead of failing as a missing bare package ([#16388](jestjs/jest#16388))
- `[jest-resolve]` Look up manual mocks for `node:` protocol specifiers under the unprefixed name they are stored as ([#16388](jestjs/jest#16388))
- `[jest-resolve]` Apply `moduleNameMapper` consistently to both spellings of core module specifiers (`fs` vs `node:fs`) ([#16390](jestjs/jest#16390))
- `[jest-resolve]` Keep virtual and ordinary mock module IDs isolated across test files ([#16296](jestjs/jest#16296))
- `[jest-resolve]` Guard missing `require.resolve.paths` ([#16052](jestjs/jest#16052))
- `[jest-resolve, jest-config, jest-runner]` Support a user resolver written as an ES module ([#16332](jestjs/jest#16332))
- `[jest-resolve, jest-runtime]` Throw the CJS parse error for ESM syntax in a `"type": "commonjs"` package or a `.cjs` file instead of loading it as ESM, matching Node ([#16368](jestjs/jest#16368))
- `[@jest/source-map]` Keep source map sources that name a scheme, such as `webpack:///`, instead of resolving them into a path that does not exist ([#16327](jestjs/jest#16327))
- `[@jest/source-map]` Look up `--testLocationInResults` positions at the right column, and keep a mapping to the first column instead of discarding it ([#16327](jestjs/jest#16327))
- `[@jest/source-map]` Warn when a source map cannot be parsed, instead of silently leaving its frames untranslated ([#16327](jestjs/jest#16327))
- `[jest-runner, @jest/source-map]` Keep a source-mapped stack for an error thrown after the test environment was torn down ([#16327](jestjs/jest#16327))
- `[jest-runtime, @jest/source-map]` Keep source maps past teardown and past the next test file's `install`, so a stack from a file no earlier stack mentioned still points at the original source ([#16330](jestjs/jest#16330))
- `[jest-runtime]` Report that no coverage was collected when `getAllV8CoverageInfoCopy` is called after `teardown`, instead of returning an empty result ([#16385](jestjs/jest#16385))
- `[jest-runtime]` Cache a CJS module's parsed exports before walking its re-exports, so two modules that re-export each other no longer overflow the stack when imported from ESM ([#16363](jestjs/jest#16363))
- `[jest-runtime]` Keep a re-exported ES module's parse failure from marking the re-exporting CommonJS file as ESM, so `module.exports = require('./dep.mjs')` loads instead of failing with `module is not defined` ([#16363](jestjs/jest#16363))
- `[jest-runtime]` Scope module mocks instantiated inside `jest.isolateModules`/`isolateModulesAsync` to that block, so a mock first imported there no longer outlives it - matching how CommonJS mocks already behave ([#16365](jestjs/jest#16365))
- `[jest-runtime]` Suspend module isolation while generating an automock, so loading the real module to read its shape no longer populates the isolated registry ([#16365](jestjs/jest#16365))
- `[jest-runtime]` Check a cached ES module's status before `require()` returns it, so a module whose evaluation threw rethrows that error and one left linked by a failed sibling is evaluated instead of returning uninitialized bindings ([#16364](jestjs/jest#16364))
- `[jest-runtime]` Report the original `ERR_REQUIRE_ASYNC_MODULE` when a `require()` of a top-level-await graph is retried, instead of a spurious "concurrent `import()`" error ([#16364](jestjs/jest#16364))
- `[jest-runtime]` Throw the evaluation error when another caller's `import()` of the same module failed while we awaited it, instead of resolving with the errored module ([#16364](jestjs/jest#16364))
- `[jest-runtime]` Mark the result of `require()`ing an ES module that has a default export with `__esModule: true` through a live-binding facade, and serve the same object from `require.cache`, matching Node ([#16367](jestjs/jest#16367))
- `[jest-runtime]` Provide a CommonJS module's exports under the `'module.exports'` named export when imported from ESM, matching Node 23+ ([#16367](jestjs/jest#16367))
- `[jest-runtime]` Give the test file itself a non-null `require.main` ([#16367](jestjs/jest#16367))
- `[jest-runtime]` Populate `module.children` with the modules a file loads, matching Node ([#16368](jestjs/jest#16368))
- `[jest-runtime]` Provide `import.meta.resolve` and `import.meta.jest` in `data:` URI modules, accept any-case mediatype parameters, and use Node's error codes for invalid `data:` URIs ([#16368](jestjs/jest#16368))
- `[jest-runtime]` Key ES modules by full URL, so query and fragment suffixes create the same module instances as Node and show up in `import.meta.url` ([#16375](jestjs/jest#16375))
- `[jest-runtime]` Share modules between overlapping graphs when a CommonJS module `require()`s an ES module mid-load, instead of evaluating shared dependencies twice ([#16375](jestjs/jest#16375))
- `[jest-runtime]` Throw `ERR_REQUIRE_CYCLE_MODULE` like Node when a CommonJS module `require()`s an ES module that is still being loaded, instead of evaluating the module a second time ([#16366](jestjs/jest#16366))
- `[jest-runtime]` Key builtin modules in the ESM registry by one canonical specifier ([#16341](jestjs/jest#16341))
- `[jest-runtime]` `import.meta.resolve()` for a builtin uses its `node:` specifier ([#16341](jestjs/jest#16341))
- `[jest-runtime]` Fall back to native ESM when a `.js` file contains ESM syntax but has no `"type":"module"` marker ([#16152](jestjs/jest#16152))
- `[jest-runtime]` Allow `require()` of ESM-marked files on Node < 24.9 via transform fallback ([#16244](jestjs/jest#16244))
- `[jest-runtime, @jest/transform]` Surface actionable `ERR_REQUIRE_ESM` error for files with untransformed ESM syntax instead of the generic "unexpected token" message ([#16244](jestjs/jest#16244))
- `[jest-runtime]` Support older test environments whose `moduleMocker` does not implement `clearMocksOnScope` ([#16169](jestjs/jest#16169))
- `[jest-runtime]` Apply `jest.unstable_mockModule` when the mocked file itself is `require()`d, not only when it is imported as a dependency ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Apply `jest.unstable_mockModule` to statically imported `data:` URIs on Node 24.9+, matching dynamic `import()` ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Run an async `jest.unstable_mockModule` factory once per module instead of twice, and fail the import instead of crashing the worker when the factory rejects ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Hide a `require(esm)` module that failed to evaluate from `require.cache`, as Node does, instead of exposing a namespace with uninitialized bindings ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Strip the byte-order mark when importing a JSON module, matching `require()` and Node ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Throw `ERR_REQUIRE_ASYNC_MODULE` when `require(esm)` runs under an async-only custom resolver, instead of silently resolving with the default resolver ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Parse imported JSON modules with the test realm's `JSON`, so their objects pass `instanceof Object` inside the test like `require()`d JSON does ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Accept every `file:` URL string in the sandboxed `module.createRequire`, including one with a `localhost` authority, as Node does ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Point at `{virtual: true}` when `jest.mock` or `jest.unstable_mockModule` is given a module that cannot be resolved ([#16389](jestjs/jest#16389))
- `[jest-reporters]` Fix coverage report table formatting in CI/GitHub Actions environments where `process.stdout.columns` is undefined by falling back to the `COLUMNS` env var or `80` columns in CI, preserving existing behaviour in other non-TTY environments ([#16227](jestjs/jest#16227))
- `[jest-runtime]` Support CJS-in-ESM exports via `"module.exports"` named exports ([#16277](jestjs/jest#16277))
- `[jest-snapshot]` Keep a skipped or failed test's hinted snapshots, instead of reporting them obsolete ([#16348](jestjs/jest#16348))
- `[jest-util]` Stop `globsToMatcher` reusing a cached matcher compiled with different picomatch options, and keep its `dot: true` default when `dot` is passed as `undefined` ([#16381](jestjs/jest#16381))
- `[pretty-format]` Move the `react-is` aliases into the `@jest` scope, so they cannot be shadowed by unrelated packages published under the alias names ([#16333](jestjs/jest#16333))

##### Chore & Maintenance

- `[docs]` Document the intentional divergences from Node's module system in the ECMAScript Modules page ([#16368](jestjs/jest#16368))
- `[docs]` Note deprecation of `react-test-renderer` in React Native tutorial and `pretty-format` README ([#16294](jestjs/jest#16294))
- `[docs]` Use `@testing-library/react-native` in the React Native tutorial instead of the deprecated `react-test-renderer` ([#16318](jestjs/jest#16318))
- `[babel-jest, @jest/transform]` Update `babel-plugin-istanbul` to v8 ([#16049](jestjs/jest#16049))
- `[jest-config, @jest/reporters, jest-runtime]` Update `glob` to v13 ([#16397](jestjs/jest#16397))
- `[jest-haste-map]` Refactor massive class into multiple files ([#16180](jestjs/jest#16180))
- `[jest-haste-map]` Drop `walker` dependency; replace hand-rolled directory recursion in the JS crawler and watcher startup with `fdir` ([#16187](jestjs/jest#16187))
- `[jest-haste-map]` Reuse cached metadata for files whose haste name is a known duplicate, instead of re-reading and re-parsing them on every startup ([#16351](jestjs/jest#16351))
- `[jest-haste-map]` Cache the watchman socket path and replace the `watchman --version` probe with `get-sockname`, so warm runs spawn no watchman processes ([#16386](jestjs/jest#16386))
- `[jest-resolve]` Store the per-directory package-type lookup in the cache it reads, so it actually memoizes ([#16369](jestjs/jest#16369))
- `[jest-resolve, jest-runtime]` Cut repeated work on the resolution hot path: hoist the platform-extension list to construction, memoize `isCoreModule` and the options cache-key serialization, skip mapper preparation when no `moduleNameMapper` is configured, run each mapper regex once, and stop re-parsing `NODE_OPTIONS` on every default-resolver call ([#16371](jestjs/jest#16371))
- `[jest-resolve]` Cut warm resolution cost to about a third: reuse one `unrs-resolver` factory per options shape instead of cloning per resolution, compose the factory cache key from per-array cached strings instead of serializing options, and stop constructing an `Error` for misses that `findNodeModule` swallows; add a `__benchmarks__` suite for the default resolver ([#16373](jestjs/jest#16373))
- `[jest-runner, @jest/source-map]` Replace `source-map-support` with an implementation in `@jest/source-map` ([#16327](jestjs/jest#16327))
- `[jest-snapshot]` Load babel, semver and synckit lazily, so requiring the package (which every test process does through `@jest/expect`) no longer loads \~200 modules that only writing inline snapshots needs ([#16387](jestjs/jest#16387))
- `[jest-runtime]` Reduce per-require overhead: skip module ID resolution when no mock can apply, answer core modules before probing for a manual mock, share one `require.cache` proxy across modules, and cache empty files ([#16376](jestjs/jest#16376))
- `[@jest/source-map]` Deprecate `getCallsite` in favour of `SourceMapSupport#getCallsite` ([#16327](jestjs/jest#16327))
- `[jest-runtime]` Avoid magical `null` value in ESM loader ([#16160](jestjs/jest#16160))
renovate Bot added a commit to andrei-picus-tink/auto-renovate that referenced this pull request Sep 6, 2026
| datasource | package | from   | to     |
| ---------- | ------- | ------ | ------ |
| npm        | jest    | 30.4.2 | 30.5.1 |


## [v30.5.1](https://github.com/jestjs/jest/blob/HEAD/CHANGELOG.md#3051)

##### Fixes

- `[jest-config]` Don't warn about global-only options in the config that supplies the global config - the root config a project resolves to, or the first entry of `--projects` when no root config is passed ([#16411](jestjs/jest#16411))
- `[jest-config, jest-types]` Stop accepting `reporters`, `coverageReporters`, `workerIdleMemoryLimit`, `cwd` and `runnerOptions` in a project config - they were silently ignored, and now warn like the other global-only options ([#16411](jestjs/jest#16411))
- `[jest-config, jest-validate]` Warn about `maxWorkers` and `coverageThreshold` in a project config instead of dropping them without a word ([#16411](jestjs/jest#16411))
- `[jest-resolve]` Match `moduleNameMapper` patterns against the specifier as written again (reverting [#16390](jestjs/jest#16390)) ([#16417](jestjs/jest#16417))
- `[jest-runtime]` Resolve package `imports` specifiers like `#dep` under ESM again ([#16413](jestjs/jest#16413))

##### Chore & Maintenance

- `[jest-util]` Name the `testEnvironmentOptions.globalsCleanup` option and link the docs from the `JEST-01` deprecation warning, and document the option's modes ([#16404](jestjs/jest#16404))


## [v30.5.0](https://github.com/jestjs/jest/blob/HEAD/CHANGELOG.md#3050)

##### Features

- `[@jest/expect-utils, jest-mock]` Add `mockFn.whenCalledWith(...args)` for configuring return values per argument list, with first-class asymmetric-matcher support ([#16053](jestjs/jest#16053))
- `[@jest/expect-utils]` Export `AsymmetricMatcher` and `FunctionParameters` types (previously private to `expect`) ([#16053](jestjs/jest#16053))
- `[jest-circus, jest-core, jest-jasmine2, jest-test-result, jest-types]` `--collectTests` now expands `test.each`/`describe.each` cases and reports per-status counts (skipped/todo via the new `wouldRun` flag for selected tests) plus a summary line that match a real run, including under `--testNamePattern` and `.only`/`fdescribe` focus on both the circus and jasmine2 runners ([#16259](jestjs/jest#16259))
- `[jest-circus, jest-environment, jest-runtime, jest-types]` Add describe-level retries via `jest.retryTimes(..., {entireDescribe: true})` ([#16322](jestjs/jest#16322))
- `[jest-circus, jest-message-util, jest-reporters, jest-types]` Add `retryMessages` to `AssertionResult` and export `formatErrorStack`, so the retry log renders nested `cause` and `AggregateError` sections with code frames instead of serialized `[cause]:`/`[errors]:` markers ([#16316](jestjs/jest#16316))
- `[jest-circus, jest-types]` Add `unhandledErrorsDetailed` to `Circus.RunResult`, so an unhandled rejection reports its `cause` chain and `AggregateError` entries with code frames instead of a pre-serialized stack ([#16316](jestjs/jest#16316))
- `[jest-haste-map]` Replace `NodeWatcher` and `FSEventsWatcher` with `@parcel/watcher` for the non-watchman watch path ([#16188](jestjs/jest#16188))
- `[jest-resolve]` Bump `unrs-resolver` to 1.12.1, remove `jest-pnp-resolver` and unnecessary checks ([#15721](jestjs/jest#15721))
- `[jest-resolve]` Honor Node's `--preserve-symlinks` / `NODE_PRESERVE_SYMLINKS` in the default resolver by passing `symlinks: false` to `unrs-resolver` ([#16260](jestjs/jest#16260))
- `[jest-runtime]` Apply automocking and manual `__mocks__` files to synchronously evaluable ESM graphs on Node 24.9+ - static imports, dynamic `import()` and `require()` of an ESM file now generate an automock from the real module's namespace instead of failing with "Attempting to import a mock without a factory". Graphs that need async evaluation (top-level await) or an async-only resolver or transformer still throw ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Route `process.getBuiltinModule` through the sandbox, so it returns the sandbox `process` and the hooked `node:module` instead of the host's ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Throw an actionable error from `module.register()` and `module.registerHooks()` inside a test - the hooks attached to the loader running Jest itself, never saw the sandboxed requires they were meant for, and stayed registered for every later test file in the worker ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Surface resolution and import-attribute errors in an ESM graph before executing any of its CJS dependencies on Node 24.9+, matching Node's run-nothing-on-a-broken-graph behavior; the legacy loader on older versions keeps its linking-time execution order ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Throw `ERR_SOURCE_PHASE_NOT_DEFINED` with an actionable message for `import source` and `import.source()`, instead of failing at instantiation with V8's bare "Source phase import object is not defined" ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Emit the JSON-without-import-attribute deprecation warning once per test file instead of once per worker, so it is no longer silently swallowed for every file after the first ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Set `import.meta.main` to `true` in the test file and `false` in every module it loads, matching Node 24+ ([#16367](jestjs/jest#16367))
- `[jest-runtime]` Resolve the `module-sync` export condition, so a package that exposes its ESM entry point for `require()` loads the same file Node would ([#16336](jestjs/jest#16336))
- `[jest-snapshot]` Add external snapshot paths to custom reporter failure details ([#16374](jestjs/jest#16374))

##### Fixes

- `[jest-console, jest-reporters]` `CustomConsole` now buffers console output so `TestResult.console` is populated for reporters when `verbose` is enabled, while `GitHubActionsReporter` avoids replaying buffered output in verbose mode ([#16155](jestjs/jest#16155))
- `[expect, jest-message-util, jest-pattern, jest-regex-util, jest-util]` Revert `node:` protocol imports to restore webpack/browser-bundle compatibility ([#16167](jestjs/jest#16167))
- `[expect]` Widen `toMatchObject` and `objectContaining` parameter type from `Record<string, unknown>` to `object` so class instances are accepted ([#16196](jestjs/jest#16196))
- `[jest-circus]` Call a generator test body with the shared test context, so `this` matches what a regular test function receives ([#16347](jestjs/jest#16347))
- `[jest-circus]` Capture the error listeners of the parent process instead of the in-sandbox `process`, so listeners registered before the test file survive teardown and sandbox listeners no longer leak onto the parent ([#16347](jestjs/jest#16347))
- `[jest-circus]` Clear `currentlyRunningTest` after skipped and todo tests ([#16342](jestjs/jest#16342))
- `[jest-circus]` Prevent late `done()` callbacks from affecting later test or hook invocations ([#16343](jestjs/jest#16343))
- `[jest-circus, jest-jasmine2]` Honor `--expand` when formatting `node:assert` failures, instead of always collapsing the diff ([#16347](jestjs/jest#16347))
- `[jest-circus, jest-jasmine2, jest-message-util]` Serialize the inner errors of an `AggregateError` into `failureMessages`, `retryReasons` and `unhandledErrors`, so `--json` output and reporter annotations include them ([#16316](jestjs/jest#16316))
- `[jest-circus, jest-snapshot]` Keep snapshot state and counts correct when a test retries ([#16344](jestjs/jest#16344))
- `[@jest/create-cache-key-function]` Include the caller support flags in the generated key, so a transformer that emits ESM or CJS based on them no longer shares one cache entry between the two ([#16331](jestjs/jest#16331))
- `[@jest/create-cache-key-function]` Include the stringified project config in the generated key, so editing a transformer's own settings invalidates what it cached ([#16331](jestjs/jest#16331))
- `[@jest/transform]` Include the caller support flags in a transform's cache key, so a file transformed both as ESM and as CJS no longer serves one shape's output for the other ([#16331](jestjs/jest#16331))
- `[jest-config]` Add missing `findRelatedTests`, `outputFile`, and `replname` entries to `ValidConfig` so they no longer trigger spurious "Unknown option" warnings ([#16224](jestjs/jest#16224))
- `[jest-config]` Use `--config` for the global config when multiple `--projects` are specified ([#16273](jestjs/jest#16273))
- `[jest-core]` Serialize `bigint` values in `--json` and `--outputFile` output as their literal form (`4n`), instead of failing the run with `TypeError: Do not know how to serialize a BigInt` ([#16338](jestjs/jest#16338))
- `[jest-core]` Do not report a `CustomGC` async resource (used by N-API addons such as napi-rs for per-isolate GC bookkeeping) as an open handle, since it is `napi_unref`'d by the addon and can never keep the event loop alive ([#16379](jestjs/jest#16379))
- `[jest-each]` Keep a `$&`, `` $` ``, `$'` or `$$` inside a `%p` param value out of the replacement, so the title shows the value instead of the text around it ([#16338](jestjs/jest#16338))
- `[jest-each]` Interpolate a `bigint` into a `%j` title as its literal form (`"4n"`) at any depth, instead of throwing `TypeError: Do not know how to serialize a BigInt` while collecting the tests ([#16338](jestjs/jest#16338))
- `[jest-environment, jest-runtime]` Bind `sandboxInjectedGlobals` to the right values when `injectGlobals` is `false`, instead of shifting every one of them by a position ([#16377](jestjs/jest#16377))
- `[jest-environment-node, jest-util]` Only warn about a conflicting `globalsCleanup` mode when one was explicitly configured, and follow the mode that is actually in effect ([#16323](jestjs/jest#16323))
- `[jest-environment-node, jest-util]` Stop resolving lazy globals when setting up an environment, so Node 26's builtin module globals are no longer loaded (and no longer emit their deprecation warnings) for every test file ([#16324](jestjs/jest#16324))
- `[jest-haste-map]` Keep watch mode alive when an outside process briefly makes a file unreadable on Windows, instead of tearing the watcher down on `EPERM` ([#16295](jestjs/jest#16295))
- `[jest-haste-map]` Keep indexing when an outside process holds a file open on Windows, instead of failing the whole crawl on `EPERM` ([#16358](jestjs/jest#16358))
- `[jest-haste-map]` Keep a duplicated manual mock resolving when the file it pointed at is deleted in watch mode ([#16360](jestjs/jest#16360))
- `[jest-haste-map]` Shut the worker farm down when a duplicate manual mock aborts the build under `throwOnModuleCollision` ([#16354](jestjs/jest#16354))
- `[jest-haste-map]` Attach the watchman client's `error` listener before the first command, so a watchman failure falls back to the node crawler instead of crashing on an unhandled `error` event, and always end the client ([#16355](jestjs/jest#16355))
- `[jest-haste-map]` Stop delivering watch events after `WatchmanWatcher` is closed, and route its warnings through the configured console ([#16355](jestjs/jest#16355))
- `[jest-haste-map]` Restore the nested `duplicates` index correctly in `ModuleMap.fromJSON`, so a haste collision reported inside a test worker raises `DuplicateHasteCandidatesError` instead of a `TypeError` ([#16353](jestjs/jest#16353))
- `[jest-haste-map]` Match watched files on a full extension, so `moduleFileExtensions: ['js']` no longer accepts `foo.mjs` ([#16352](jestjs/jest#16352))
- `[jest-haste-map]` Delimit the fields that make up the haste map cache key, so two different option sets cannot hash to the same cache file ([#16352](jestjs/jest#16352))
- `[jest-message-util]` Print the inner errors of an `AggregateError` thrown inside a test ([#16316](jestjs/jest#16316))
- `[jest-message-util]` Indent nested `cause` and `AggregateError` sections of a test failure by one level per depth, so the nesting is legible instead of rendering flat ([#16316](jestjs/jest#16316))
- `[jest-message-util]` Color stack traces line by line so blank lines stay blank ([#16316](jestjs/jest#16316))
- `[jest-message-util]` Detect Jest's own frames without assuming the checkout directory's name, and cover `@jest/*` packages, so stack traces and code frames point at user code ([#16326](jestjs/jest#16326))
- `[jest-mock]` `mockResolvedValue` / `mockRejectedValue` now see all overload return types, so a Promise-returning overload survives even when a later overload returns a non-Promise (e.g. `pg.Client['end']`) ([#16237](jestjs/jest#16237))
- `[@jest-environment/jsdom-abstract]` Make `@types/jsdom` a peer dependency ([#16166](jestjs/jest#16166))
- `[jest-mock]` Remove the leftover own accessor descriptor when restoring a `spyOn` of an inherited getter or setter, so the instance keeps reflecting the prototype ([#16226](jestjs/jest#16226))
- `[jest-resolve]` Include `extensionsToTreatAsEsm` in the `shouldLoadAsEsm` cache key, so projects with different extension lists don't read each other's answers ([#16369](jestjs/jest#16369))
- `[jest-resolve]` Make `getModuleIDAsync` build and cache `data:` URI module IDs the same way as `getModuleID` ([#16370](jestjs/jest#16370))
- `[jest-resolve]` Keep the `node:` prefix when resolving a core module asynchronously, so a builtin that only exists prefixed (`node:sea`, `node:sqlite`, `node:test`, `node:test/reporters`) resolves instead of failing as a missing bare package ([#16388](jestjs/jest#16388))
- `[jest-resolve]` Look up manual mocks for `node:` protocol specifiers under the unprefixed name they are stored as ([#16388](jestjs/jest#16388))
- `[jest-resolve]` Apply `moduleNameMapper` consistently to both spellings of core module specifiers (`fs` vs `node:fs`) ([#16390](jestjs/jest#16390))
- `[jest-resolve]` Keep virtual and ordinary mock module IDs isolated across test files ([#16296](jestjs/jest#16296))
- `[jest-resolve]` Guard missing `require.resolve.paths` ([#16052](jestjs/jest#16052))
- `[jest-resolve, jest-config, jest-runner]` Support a user resolver written as an ES module ([#16332](jestjs/jest#16332))
- `[jest-resolve, jest-runtime]` Throw the CJS parse error for ESM syntax in a `"type": "commonjs"` package or a `.cjs` file instead of loading it as ESM, matching Node ([#16368](jestjs/jest#16368))
- `[@jest/source-map]` Keep source map sources that name a scheme, such as `webpack:///`, instead of resolving them into a path that does not exist ([#16327](jestjs/jest#16327))
- `[@jest/source-map]` Look up `--testLocationInResults` positions at the right column, and keep a mapping to the first column instead of discarding it ([#16327](jestjs/jest#16327))
- `[@jest/source-map]` Warn when a source map cannot be parsed, instead of silently leaving its frames untranslated ([#16327](jestjs/jest#16327))
- `[jest-runner, @jest/source-map]` Keep a source-mapped stack for an error thrown after the test environment was torn down ([#16327](jestjs/jest#16327))
- `[jest-runtime, @jest/source-map]` Keep source maps past teardown and past the next test file's `install`, so a stack from a file no earlier stack mentioned still points at the original source ([#16330](jestjs/jest#16330))
- `[jest-runtime]` Report that no coverage was collected when `getAllV8CoverageInfoCopy` is called after `teardown`, instead of returning an empty result ([#16385](jestjs/jest#16385))
- `[jest-runtime]` Cache a CJS module's parsed exports before walking its re-exports, so two modules that re-export each other no longer overflow the stack when imported from ESM ([#16363](jestjs/jest#16363))
- `[jest-runtime]` Keep a re-exported ES module's parse failure from marking the re-exporting CommonJS file as ESM, so `module.exports = require('./dep.mjs')` loads instead of failing with `module is not defined` ([#16363](jestjs/jest#16363))
- `[jest-runtime]` Scope module mocks instantiated inside `jest.isolateModules`/`isolateModulesAsync` to that block, so a mock first imported there no longer outlives it - matching how CommonJS mocks already behave ([#16365](jestjs/jest#16365))
- `[jest-runtime]` Suspend module isolation while generating an automock, so loading the real module to read its shape no longer populates the isolated registry ([#16365](jestjs/jest#16365))
- `[jest-runtime]` Check a cached ES module's status before `require()` returns it, so a module whose evaluation threw rethrows that error and one left linked by a failed sibling is evaluated instead of returning uninitialized bindings ([#16364](jestjs/jest#16364))
- `[jest-runtime]` Report the original `ERR_REQUIRE_ASYNC_MODULE` when a `require()` of a top-level-await graph is retried, instead of a spurious "concurrent `import()`" error ([#16364](jestjs/jest#16364))
- `[jest-runtime]` Throw the evaluation error when another caller's `import()` of the same module failed while we awaited it, instead of resolving with the errored module ([#16364](jestjs/jest#16364))
- `[jest-runtime]` Mark the result of `require()`ing an ES module that has a default export with `__esModule: true` through a live-binding facade, and serve the same object from `require.cache`, matching Node ([#16367](jestjs/jest#16367))
- `[jest-runtime]` Provide a CommonJS module's exports under the `'module.exports'` named export when imported from ESM, matching Node 23+ ([#16367](jestjs/jest#16367))
- `[jest-runtime]` Give the test file itself a non-null `require.main` ([#16367](jestjs/jest#16367))
- `[jest-runtime]` Populate `module.children` with the modules a file loads, matching Node ([#16368](jestjs/jest#16368))
- `[jest-runtime]` Provide `import.meta.resolve` and `import.meta.jest` in `data:` URI modules, accept any-case mediatype parameters, and use Node's error codes for invalid `data:` URIs ([#16368](jestjs/jest#16368))
- `[jest-runtime]` Key ES modules by full URL, so query and fragment suffixes create the same module instances as Node and show up in `import.meta.url` ([#16375](jestjs/jest#16375))
- `[jest-runtime]` Share modules between overlapping graphs when a CommonJS module `require()`s an ES module mid-load, instead of evaluating shared dependencies twice ([#16375](jestjs/jest#16375))
- `[jest-runtime]` Throw `ERR_REQUIRE_CYCLE_MODULE` like Node when a CommonJS module `require()`s an ES module that is still being loaded, instead of evaluating the module a second time ([#16366](jestjs/jest#16366))
- `[jest-runtime]` Key builtin modules in the ESM registry by one canonical specifier ([#16341](jestjs/jest#16341))
- `[jest-runtime]` `import.meta.resolve()` for a builtin uses its `node:` specifier ([#16341](jestjs/jest#16341))
- `[jest-runtime]` Fall back to native ESM when a `.js` file contains ESM syntax but has no `"type":"module"` marker ([#16152](jestjs/jest#16152))
- `[jest-runtime]` Allow `require()` of ESM-marked files on Node < 24.9 via transform fallback ([#16244](jestjs/jest#16244))
- `[jest-runtime, @jest/transform]` Surface actionable `ERR_REQUIRE_ESM` error for files with untransformed ESM syntax instead of the generic "unexpected token" message ([#16244](jestjs/jest#16244))
- `[jest-runtime]` Support older test environments whose `moduleMocker` does not implement `clearMocksOnScope` ([#16169](jestjs/jest#16169))
- `[jest-runtime]` Apply `jest.unstable_mockModule` when the mocked file itself is `require()`d, not only when it is imported as a dependency ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Apply `jest.unstable_mockModule` to statically imported `data:` URIs on Node 24.9+, matching dynamic `import()` ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Run an async `jest.unstable_mockModule` factory once per module instead of twice, and fail the import instead of crashing the worker when the factory rejects ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Hide a `require(esm)` module that failed to evaluate from `require.cache`, as Node does, instead of exposing a namespace with uninitialized bindings ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Strip the byte-order mark when importing a JSON module, matching `require()` and Node ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Throw `ERR_REQUIRE_ASYNC_MODULE` when `require(esm)` runs under an async-only custom resolver, instead of silently resolving with the default resolver ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Parse imported JSON modules with the test realm's `JSON`, so their objects pass `instanceof Object` inside the test like `require()`d JSON does ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Accept every `file:` URL string in the sandboxed `module.createRequire`, including one with a `localhost` authority, as Node does ([#16389](jestjs/jest#16389))
- `[jest-runtime]` Point at `{virtual: true}` when `jest.mock` or `jest.unstable_mockModule` is given a module that cannot be resolved ([#16389](jestjs/jest#16389))
- `[jest-reporters]` Fix coverage report table formatting in CI/GitHub Actions environments where `process.stdout.columns` is undefined by falling back to the `COLUMNS` env var or `80` columns in CI, preserving existing behaviour in other non-TTY environments ([#16227](jestjs/jest#16227))
- `[jest-runtime]` Support CJS-in-ESM exports via `"module.exports"` named exports ([#16277](jestjs/jest#16277))
- `[jest-snapshot]` Keep a skipped or failed test's hinted snapshots, instead of reporting them obsolete ([#16348](jestjs/jest#16348))
- `[jest-util]` Stop `globsToMatcher` reusing a cached matcher compiled with different picomatch options, and keep its `dot: true` default when `dot` is passed as `undefined` ([#16381](jestjs/jest#16381))
- `[pretty-format]` Move the `react-is` aliases into the `@jest` scope, so they cannot be shadowed by unrelated packages published under the alias names ([#16333](jestjs/jest#16333))

##### Chore & Maintenance

- `[docs]` Document the intentional divergences from Node's module system in the ECMAScript Modules page ([#16368](jestjs/jest#16368))
- `[docs]` Note deprecation of `react-test-renderer` in React Native tutorial and `pretty-format` README ([#16294](jestjs/jest#16294))
- `[docs]` Use `@testing-library/react-native` in the React Native tutorial instead of the deprecated `react-test-renderer` ([#16318](jestjs/jest#16318))
- `[babel-jest, @jest/transform]` Update `babel-plugin-istanbul` to v8 ([#16049](jestjs/jest#16049))
- `[jest-config, @jest/reporters, jest-runtime]` Update `glob` to v13 ([#16397](jestjs/jest#16397))
- `[jest-haste-map]` Refactor massive class into multiple files ([#16180](jestjs/jest#16180))
- `[jest-haste-map]` Drop `walker` dependency; replace hand-rolled directory recursion in the JS crawler and watcher startup with `fdir` ([#16187](jestjs/jest#16187))
- `[jest-haste-map]` Reuse cached metadata for files whose haste name is a known duplicate, instead of re-reading and re-parsing them on every startup ([#16351](jestjs/jest#16351))
- `[jest-haste-map]` Cache the watchman socket path and replace the `watchman --version` probe with `get-sockname`, so warm runs spawn no watchman processes ([#16386](jestjs/jest#16386))
- `[jest-resolve]` Store the per-directory package-type lookup in the cache it reads, so it actually memoizes ([#16369](jestjs/jest#16369))
- `[jest-resolve, jest-runtime]` Cut repeated work on the resolution hot path: hoist the platform-extension list to construction, memoize `isCoreModule` and the options cache-key serialization, skip mapper preparation when no `moduleNameMapper` is configured, run each mapper regex once, and stop re-parsing `NODE_OPTIONS` on every default-resolver call ([#16371](jestjs/jest#16371))
- `[jest-resolve]` Cut warm resolution cost to about a third: reuse one `unrs-resolver` factory per options shape instead of cloning per resolution, compose the factory cache key from per-array cached strings instead of serializing options, and stop constructing an `Error` for misses that `findNodeModule` swallows; add a `__benchmarks__` suite for the default resolver ([#16373](jestjs/jest#16373))
- `[jest-runner, @jest/source-map]` Replace `source-map-support` with an implementation in `@jest/source-map` ([#16327](jestjs/jest#16327))
- `[jest-snapshot]` Load babel, semver and synckit lazily, so requiring the package (which every test process does through `@jest/expect`) no longer loads \~200 modules that only writing inline snapshots needs ([#16387](jestjs/jest#16387))
- `[jest-runtime]` Reduce per-require overhead: skip module ID resolution when no mock can apply, answer core modules before probing for a manual mock, share one `require.cache` proxy across modules, and cache empty files ([#16376](jestjs/jest#16376))
- `[@jest/source-map]` Deprecate `getCallsite` in favour of `SourceMapSupport#getCallsite` ([#16327](jestjs/jest#16327))
- `[jest-runtime]` Avoid magical `null` value in ESM loader ([#16160](jestjs/jest#16160))
mergify Bot added a commit to robfrank/linklift that referenced this pull request Sep 6, 2026
…ip ci]

Bumps [babel-jest](https://github.com/jestjs/jest/tree/HEAD/packages/babel-jest) from 30.4.1 to 30.5.1.
Release notes

*Sourced from [babel-jest's releases](https://github.com/jestjs/jest/releases).*

> v30.5.1
> -------
>
> Fixes
> -----
>
> * `[jest-config]` Don't warn about global-only options in the config that supplies the global config - the root config a project resolves to, or the first entry of `--projects` when no root config is passed ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-config, jest-types]` Stop accepting `reporters`, `coverageReporters`, `workerIdleMemoryLimit`, `cwd` and `runnerOptions` in a project config - they were silently ignored, and now warn like the other global-only options ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-config, jest-validate]` Warn about `maxWorkers` and `coverageThreshold` in a project config instead of dropping them without a word ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-resolve]` Match `moduleNameMapper` patterns against the specifier as written again (reverting [#16390](https://redirect.github.com/jestjs/jest/pull/16390)) ([#16417](https://redirect.github.com/jestjs/jest/pull/16417))
> * `[jest-runtime]` Resolve package `imports` specifiers like `#dep` under ESM again ([#16413](https://redirect.github.com/jestjs/jest/pull/16413))
>
> Chore & Maintenance
> -------------------
>
> * `[jest-util]` Name the `testEnvironmentOptions.globalsCleanup` option and link the docs from the `JEST-01` deprecation warning, and document the option's modes ([#16404](https://redirect.github.com/jestjs/jest/pull/16404))
>
> New Contributors
> ----------------
>
> * [`@​HuzaifaChaudary`](https://github.com/HuzaifaChaudary) made their first contribution in [jestjs/jest#16413](https://redirect.github.com/jestjs/jest/pull/16413)
>
> **Full Changelog**: <jestjs/jest@v30.5.0...v30.5.1>
>
> v30.5.0
> -------
>
> On a personal note: King Harald V of Norway passed away this morning. He ascended the throne 35 years ago, two months before I was born. This release is dedicated to his memory. Hvil i fred 🇳🇴
>
> ---
>
> This is a big release. It touches `jest-runtime`, `jest-resolve` and `jest-haste-map` in many places, and with this many changes there might be regressions 😬. If your suite behaves differently after upgrading, please [open an issue](https://github.com/jestjs/jest/issues).
>
> Highlights
> ==========
>
> `whenCalledWith`
> ----------------
>
> Mock functions can now configure return values per argument list, contributed by [`@​timkindberg`](https://github.com/timkindberg) ([#16053](https://redirect.github.com/jestjs/jest/pull/16053)):
>
> ```
> const fn = jest.fn();
> fn.whenCalledWith('apple').mockReturnValue('red');
> fn.whenCalledWith('banana').mockReturnValue('yellow');
> fn.whenCalledWith(expect.any(Number)).mockReturnValue('numeric');
>
> fn('apple'); // 'red'
> fn('banana'); // 'yellow'
> fn(42); // 'numeric'
> fn('grape'); // undefined
> ```
>
> The returned object is a real `Mock`, so `mockReturnValueOnce`, `mockResolvedValue`, `mockImplementation` etc. all chain here too. Argument slots accept literals or any asymmetric matcher, with the same equality semantics as `toHaveBeenCalledWith()`. Calls that match nothing fall through to the base mock. See the [Mock Functions docs](https://jestjs.io/docs/mock-function-api#mockfnwhencalledwithargs) for matching and precedence details.
>
> Describe-level retries
> ----------------------
>
> `jest.retryTimes()` can now retry a whole `describe` block instead of a single test, contributed by [`@​soltonigiri`](https://github.com/soltonigiri) ([#16322](https://redirect.github.com/jestjs/jest/pull/16322)). Each attempt reruns the block's `beforeAll`/`afterAll` hooks, child tests and nested describes, which helps when tests in a block depend on shared state:
>
> ```
> </tr></table>
> ```

... (truncated)


Changelog

*Sourced from [babel-jest's changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md).*

> 30.5.1
> ------
>
> ### Fixes
>
> * `[jest-config]` Don't warn about global-only options in the config that supplies the global config - the root config a project resolves to, or the first entry of `--projects` when no root config is passed ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-config, jest-types]` Stop accepting `reporters`, `coverageReporters`, `workerIdleMemoryLimit`, `cwd` and `runnerOptions` in a project config - they were silently ignored, and now warn like the other global-only options ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-config, jest-validate]` Warn about `maxWorkers` and `coverageThreshold` in a project config instead of dropping them without a word ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-resolve]` Match `moduleNameMapper` patterns against the specifier as written again (reverting [#16390](https://redirect.github.com/jestjs/jest/pull/16390)) ([#16417](https://redirect.github.com/jestjs/jest/pull/16417))
> * `[jest-runtime]` Resolve package `imports` specifiers like `#dep` under ESM again ([#16413](https://redirect.github.com/jestjs/jest/pull/16413))
>
> ### Chore & Maintenance
>
> * `[jest-util]` Name the `testEnvironmentOptions.globalsCleanup` option and link the docs from the `JEST-01` deprecation warning, and document the option's modes ([#16404](https://redirect.github.com/jestjs/jest/pull/16404))
>
> 30.5.0
> ------
>
> ### Features
>
> * `[@jest/expect-utils, jest-mock]` Add `mockFn.whenCalledWith(...args)` for configuring return values per argument list, with first-class asymmetric-matcher support ([#16053](https://redirect.github.com/jestjs/jest/pull/16053))
> * `[@jest/expect-utils]` Export `AsymmetricMatcher` and `FunctionParameters` types (previously private to `expect`) ([#16053](https://redirect.github.com/jestjs/jest/pull/16053))
> * `[jest-circus, jest-core, jest-jasmine2, jest-test-result, jest-types]` `--collectTests` now expands `test.each`/`describe.each` cases and reports per-status counts (skipped/todo via the new `wouldRun` flag for selected tests) plus a summary line that match a real run, including under `--testNamePattern` and `.only`/`fdescribe` focus on both the circus and jasmine2 runners ([#16259](https://redirect.github.com/jestjs/jest/pull/16259))
> * `[jest-circus, jest-environment, jest-runtime, jest-types]` Add describe-level retries via `jest.retryTimes(..., {entireDescribe: true})` ([#16322](https://redirect.github.com/jestjs/jest/pull/16322))
> * `[jest-circus, jest-message-util, jest-reporters, jest-types]` Add `retryMessages` to `AssertionResult` and export `formatErrorStack`, so the retry log renders nested `cause` and `AggregateError` sections with code frames instead of serialized `[cause]:`/`[errors]:` markers ([#16316](https://redirect.github.com/jestjs/jest/pull/16316))
> * `[jest-circus, jest-types]` Add `unhandledErrorsDetailed` to `Circus.RunResult`, so an unhandled rejection reports its `cause` chain and `AggregateError` entries with code frames instead of a pre-serialized stack ([#16316](https://redirect.github.com/jestjs/jest/pull/16316))
> * `[jest-haste-map]` Replace `NodeWatcher` and `FSEventsWatcher` with `@parcel/watcher` for the non-watchman watch path ([#16188](https://redirect.github.com/jestjs/jest/pull/16188))
> * `[jest-resolve]` Bump `unrs-resolver` to 1.12.1, remove `jest-pnp-resolver` and unnecessary checks ([#15721](https://redirect.github.com/jestjs/jest/pull/15721))
> * `[jest-resolve]` Honor Node's `--preserve-symlinks` / `NODE_PRESERVE_SYMLINKS` in the default resolver by passing `symlinks: false` to `unrs-resolver` ([#16260](https://redirect.github.com/jestjs/jest/pull/16260))
> * `[jest-runtime]` Apply automocking and manual `__mocks__` files to synchronously evaluable ESM graphs on Node 24.9+ - static imports, dynamic `import()` and `require()` of an ESM file now generate an automock from the real module's namespace instead of failing with "Attempting to import a mock without a factory". Graphs that need async evaluation (top-level await) or an async-only resolver or transformer still throw ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Route `process.getBuiltinModule` through the sandbox, so it returns the sandbox `process` and the hooked `node:module` instead of the host's ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Throw an actionable error from `module.register()` and `module.registerHooks()` inside a test - the hooks attached to the loader running Jest itself, never saw the sandboxed requires they were meant for, and stayed registered for every later test file in the worker ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Surface resolution and import-attribute errors in an ESM graph before executing any of its CJS dependencies on Node 24.9+, matching Node's run-nothing-on-a-broken-graph behavior; the legacy loader on older versions keeps its linking-time execution order ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Throw `ERR_SOURCE_PHASE_NOT_DEFINED` with an actionable message for `import source` and `import.source()`, instead of failing at instantiation with V8's bare "Source phase import object is not defined" ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Emit the JSON-without-import-attribute deprecation warning once per test file instead of once per worker, so it is no longer silently swallowed for every file after the first ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Set `import.meta.main` to `true` in the test file and `false` in every module it loads, matching Node 24+ ([#16367](https://redirect.github.com/jestjs/jest/pull/16367))
> * `[jest-runtime]` Resolve the `module-sync` export condition, so a package that exposes its ESM entry point for `require()` loads the same file Node would ([#16336](https://redirect.github.com/jestjs/jest/pull/16336))
> * `[jest-snapshot]` Add external snapshot paths to custom reporter failure details ([#16374](https://redirect.github.com/jestjs/jest/pull/16374))
>
> ### Fixes
>
> * `[jest-console, jest-reporters]` `CustomConsole` now buffers console output so `TestResult.console` is populated for reporters when `verbose` is enabled, while `GitHubActionsReporter` avoids replaying buffered output in verbose mode ([#16155](https://redirect.github.com/jestjs/jest/pull/16155))
> * `[expect, jest-message-util, jest-pattern, jest-regex-util, jest-util]` Revert `node:` protocol imports to restore webpack/browser-bundle compatibility ([#16167](https://redirect.github.com/jestjs/jest/pull/16167))
> * `[expect]` Widen `toMatchObject` and `objectContaining` parameter type from `Record<string, unknown>` to `object` so class instances are accepted ([#16196](https://redirect.github.com/jestjs/jest/pull/16196))
> * `[jest-circus]` Call a generator test body with the shared test context, so `this` matches what a regular test function receives ([#16347](https://redirect.github.com/jestjs/jest/pull/16347))
> * `[jest-circus]` Capture the error listeners of the parent process instead of the in-sandbox `process`, so listeners registered before the test file survive teardown and sandbox listeners no longer leak onto the parent ([#16347](https://redirect.github.com/jestjs/jest/pull/16347))
> * `[jest-circus]` Clear `currentlyRunningTest` after skipped and todo tests ([#16342](https://redirect.github.com/jestjs/jest/pull/16342))
> * `[jest-circus]` Prevent late `done()` callbacks from affecting later test or hook invocations ([#16343](https://redirect.github.com/jestjs/jest/pull/16343))
> * `[jest-circus, jest-jasmine2]` Honor `--expand` when formatting `node:assert` failures, instead of always collapsing the diff ([#16347](https://redirect.github.com/jestjs/jest/pull/16347))
> * `[jest-circus, jest-jasmine2, jest-message-util]` Serialize the inner errors of an `AggregateError` into `failureMessages`, `retryReasons` and `unhandledErrors`, so `--json` output and reporter annotations include them ([#16316](https://redirect.github.com/jestjs/jest/pull/16316))
> * `[jest-circus, jest-snapshot]` Keep snapshot state and counts correct when a test retries ([#16344](https://redirect.github.com/jestjs/jest/pull/16344))
> * `[@jest/create-cache-key-function]` Include the caller support flags in the generated key, so a transformer that emits ESM or CJS based on them no longer shares one cache entry between the two ([#16331](https://redirect.github.com/jestjs/jest/pull/16331))

... (truncated)


Commits

* [`9ab14fe`](jestjs/jest@9ab14fe) v30.5.1
* [`912baa3`](jestjs/jest@912baa3) v30.5.0
* [`8e6d128`](jestjs/jest@8e6d128) Update istanbul dependencies ([#16049](https://github.com/jestjs/jest/tree/HEAD/packages/babel-jest/issues/16049))
* [`1865dd8`](jestjs/jest@1865dd8) chore: update yarn & refresh lockfiles ([#16251](https://github.com/jestjs/jest/tree/HEAD/packages/babel-jest/issues/16251))
* [`ff542da`](jestjs/jest@ff542da) chore(deps): update babel monorepo to v8.0.0-rc.5 ([#16172](https://github.com/jestjs/jest/tree/HEAD/packages/babel-jest/issues/16172))
* [`b91717a`](jestjs/jest@b91717a) chore: refresh coding agent instructions ([#16182](https://github.com/jestjs/jest/tree/HEAD/packages/babel-jest/issues/16182))
* See full diff in [compare view](https://github.com/jestjs/jest/commits/v30.5.1/packages/babel-jest)
  
[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility\_score?dependency-name=babel-jest&package-manager=npm\_and\_yarn&previous-version=30.4.1&new-version=30.5.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
  
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot show  ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
mergify Bot added a commit to robfrank/linklift that referenced this pull request Sep 6, 2026
… /webapp [skip ci]

Bumps [jest-environment-jsdom](https://github.com/jestjs/jest/tree/HEAD/packages/jest-environment-jsdom) from 30.4.1 to 30.5.1.
Release notes

*Sourced from [jest-environment-jsdom's releases](https://github.com/jestjs/jest/releases).*

> v30.5.1
> -------
>
> Fixes
> -----
>
> * `[jest-config]` Don't warn about global-only options in the config that supplies the global config - the root config a project resolves to, or the first entry of `--projects` when no root config is passed ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-config, jest-types]` Stop accepting `reporters`, `coverageReporters`, `workerIdleMemoryLimit`, `cwd` and `runnerOptions` in a project config - they were silently ignored, and now warn like the other global-only options ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-config, jest-validate]` Warn about `maxWorkers` and `coverageThreshold` in a project config instead of dropping them without a word ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-resolve]` Match `moduleNameMapper` patterns against the specifier as written again (reverting [#16390](https://redirect.github.com/jestjs/jest/pull/16390)) ([#16417](https://redirect.github.com/jestjs/jest/pull/16417))
> * `[jest-runtime]` Resolve package `imports` specifiers like `#dep` under ESM again ([#16413](https://redirect.github.com/jestjs/jest/pull/16413))
>
> Chore & Maintenance
> -------------------
>
> * `[jest-util]` Name the `testEnvironmentOptions.globalsCleanup` option and link the docs from the `JEST-01` deprecation warning, and document the option's modes ([#16404](https://redirect.github.com/jestjs/jest/pull/16404))
>
> New Contributors
> ----------------
>
> * [`@​HuzaifaChaudary`](https://github.com/HuzaifaChaudary) made their first contribution in [jestjs/jest#16413](https://redirect.github.com/jestjs/jest/pull/16413)
>
> **Full Changelog**: <jestjs/jest@v30.5.0...v30.5.1>
>
> v30.5.0
> -------
>
> On a personal note: King Harald V of Norway passed away this morning. He ascended the throne 35 years ago, two months before I was born. This release is dedicated to his memory. Hvil i fred 🇳🇴
>
> ---
>
> This is a big release. It touches `jest-runtime`, `jest-resolve` and `jest-haste-map` in many places, and with this many changes there might be regressions 😬. If your suite behaves differently after upgrading, please [open an issue](https://github.com/jestjs/jest/issues).
>
> Highlights
> ==========
>
> `whenCalledWith`
> ----------------
>
> Mock functions can now configure return values per argument list, contributed by [`@​timkindberg`](https://github.com/timkindberg) ([#16053](https://redirect.github.com/jestjs/jest/pull/16053)):
>
> ```
> const fn = jest.fn();
> fn.whenCalledWith('apple').mockReturnValue('red');
> fn.whenCalledWith('banana').mockReturnValue('yellow');
> fn.whenCalledWith(expect.any(Number)).mockReturnValue('numeric');
>
> fn('apple'); // 'red'
> fn('banana'); // 'yellow'
> fn(42); // 'numeric'
> fn('grape'); // undefined
> ```
>
> The returned object is a real `Mock`, so `mockReturnValueOnce`, `mockResolvedValue`, `mockImplementation` etc. all chain here too. Argument slots accept literals or any asymmetric matcher, with the same equality semantics as `toHaveBeenCalledWith()`. Calls that match nothing fall through to the base mock. See the [Mock Functions docs](https://jestjs.io/docs/mock-function-api#mockfnwhencalledwithargs) for matching and precedence details.
>
> Describe-level retries
> ----------------------
>
> `jest.retryTimes()` can now retry a whole `describe` block instead of a single test, contributed by [`@​soltonigiri`](https://github.com/soltonigiri) ([#16322](https://redirect.github.com/jestjs/jest/pull/16322)). Each attempt reruns the block's `beforeAll`/`afterAll` hooks, child tests and nested describes, which helps when tests in a block depend on shared state:
>
> ```
> </tr></table>
> ```

... (truncated)


Changelog

*Sourced from [jest-environment-jsdom's changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md).*

> 30.5.1
> ------
>
> ### Fixes
>
> * `[jest-config]` Don't warn about global-only options in the config that supplies the global config - the root config a project resolves to, or the first entry of `--projects` when no root config is passed ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-config, jest-types]` Stop accepting `reporters`, `coverageReporters`, `workerIdleMemoryLimit`, `cwd` and `runnerOptions` in a project config - they were silently ignored, and now warn like the other global-only options ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-config, jest-validate]` Warn about `maxWorkers` and `coverageThreshold` in a project config instead of dropping them without a word ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-resolve]` Match `moduleNameMapper` patterns against the specifier as written again (reverting [#16390](https://redirect.github.com/jestjs/jest/pull/16390)) ([#16417](https://redirect.github.com/jestjs/jest/pull/16417))
> * `[jest-runtime]` Resolve package `imports` specifiers like `#dep` under ESM again ([#16413](https://redirect.github.com/jestjs/jest/pull/16413))
>
> ### Chore & Maintenance
>
> * `[jest-util]` Name the `testEnvironmentOptions.globalsCleanup` option and link the docs from the `JEST-01` deprecation warning, and document the option's modes ([#16404](https://redirect.github.com/jestjs/jest/pull/16404))
>
> 30.5.0
> ------
>
> ### Features
>
> * `[@jest/expect-utils, jest-mock]` Add `mockFn.whenCalledWith(...args)` for configuring return values per argument list, with first-class asymmetric-matcher support ([#16053](https://redirect.github.com/jestjs/jest/pull/16053))
> * `[@jest/expect-utils]` Export `AsymmetricMatcher` and `FunctionParameters` types (previously private to `expect`) ([#16053](https://redirect.github.com/jestjs/jest/pull/16053))
> * `[jest-circus, jest-core, jest-jasmine2, jest-test-result, jest-types]` `--collectTests` now expands `test.each`/`describe.each` cases and reports per-status counts (skipped/todo via the new `wouldRun` flag for selected tests) plus a summary line that match a real run, including under `--testNamePattern` and `.only`/`fdescribe` focus on both the circus and jasmine2 runners ([#16259](https://redirect.github.com/jestjs/jest/pull/16259))
> * `[jest-circus, jest-environment, jest-runtime, jest-types]` Add describe-level retries via `jest.retryTimes(..., {entireDescribe: true})` ([#16322](https://redirect.github.com/jestjs/jest/pull/16322))
> * `[jest-circus, jest-message-util, jest-reporters, jest-types]` Add `retryMessages` to `AssertionResult` and export `formatErrorStack`, so the retry log renders nested `cause` and `AggregateError` sections with code frames instead of serialized `[cause]:`/`[errors]:` markers ([#16316](https://redirect.github.com/jestjs/jest/pull/16316))
> * `[jest-circus, jest-types]` Add `unhandledErrorsDetailed` to `Circus.RunResult`, so an unhandled rejection reports its `cause` chain and `AggregateError` entries with code frames instead of a pre-serialized stack ([#16316](https://redirect.github.com/jestjs/jest/pull/16316))
> * `[jest-haste-map]` Replace `NodeWatcher` and `FSEventsWatcher` with `@parcel/watcher` for the non-watchman watch path ([#16188](https://redirect.github.com/jestjs/jest/pull/16188))
> * `[jest-resolve]` Bump `unrs-resolver` to 1.12.1, remove `jest-pnp-resolver` and unnecessary checks ([#15721](https://redirect.github.com/jestjs/jest/pull/15721))
> * `[jest-resolve]` Honor Node's `--preserve-symlinks` / `NODE_PRESERVE_SYMLINKS` in the default resolver by passing `symlinks: false` to `unrs-resolver` ([#16260](https://redirect.github.com/jestjs/jest/pull/16260))
> * `[jest-runtime]` Apply automocking and manual `__mocks__` files to synchronously evaluable ESM graphs on Node 24.9+ - static imports, dynamic `import()` and `require()` of an ESM file now generate an automock from the real module's namespace instead of failing with "Attempting to import a mock without a factory". Graphs that need async evaluation (top-level await) or an async-only resolver or transformer still throw ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Route `process.getBuiltinModule` through the sandbox, so it returns the sandbox `process` and the hooked `node:module` instead of the host's ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Throw an actionable error from `module.register()` and `module.registerHooks()` inside a test - the hooks attached to the loader running Jest itself, never saw the sandboxed requires they were meant for, and stayed registered for every later test file in the worker ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Surface resolution and import-attribute errors in an ESM graph before executing any of its CJS dependencies on Node 24.9+, matching Node's run-nothing-on-a-broken-graph behavior; the legacy loader on older versions keeps its linking-time execution order ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Throw `ERR_SOURCE_PHASE_NOT_DEFINED` with an actionable message for `import source` and `import.source()`, instead of failing at instantiation with V8's bare "Source phase import object is not defined" ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Emit the JSON-without-import-attribute deprecation warning once per test file instead of once per worker, so it is no longer silently swallowed for every file after the first ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Set `import.meta.main` to `true` in the test file and `false` in every module it loads, matching Node 24+ ([#16367](https://redirect.github.com/jestjs/jest/pull/16367))
> * `[jest-runtime]` Resolve the `module-sync` export condition, so a package that exposes its ESM entry point for `require()` loads the same file Node would ([#16336](https://redirect.github.com/jestjs/jest/pull/16336))
> * `[jest-snapshot]` Add external snapshot paths to custom reporter failure details ([#16374](https://redirect.github.com/jestjs/jest/pull/16374))
>
> ### Fixes
>
> * `[jest-console, jest-reporters]` `CustomConsole` now buffers console output so `TestResult.console` is populated for reporters when `verbose` is enabled, while `GitHubActionsReporter` avoids replaying buffered output in verbose mode ([#16155](https://redirect.github.com/jestjs/jest/pull/16155))
> * `[expect, jest-message-util, jest-pattern, jest-regex-util, jest-util]` Revert `node:` protocol imports to restore webpack/browser-bundle compatibility ([#16167](https://redirect.github.com/jestjs/jest/pull/16167))
> * `[expect]` Widen `toMatchObject` and `objectContaining` parameter type from `Record<string, unknown>` to `object` so class instances are accepted ([#16196](https://redirect.github.com/jestjs/jest/pull/16196))
> * `[jest-circus]` Call a generator test body with the shared test context, so `this` matches what a regular test function receives ([#16347](https://redirect.github.com/jestjs/jest/pull/16347))
> * `[jest-circus]` Capture the error listeners of the parent process instead of the in-sandbox `process`, so listeners registered before the test file survive teardown and sandbox listeners no longer leak onto the parent ([#16347](https://redirect.github.com/jestjs/jest/pull/16347))
> * `[jest-circus]` Clear `currentlyRunningTest` after skipped and todo tests ([#16342](https://redirect.github.com/jestjs/jest/pull/16342))
> * `[jest-circus]` Prevent late `done()` callbacks from affecting later test or hook invocations ([#16343](https://redirect.github.com/jestjs/jest/pull/16343))
> * `[jest-circus, jest-jasmine2]` Honor `--expand` when formatting `node:assert` failures, instead of always collapsing the diff ([#16347](https://redirect.github.com/jestjs/jest/pull/16347))
> * `[jest-circus, jest-jasmine2, jest-message-util]` Serialize the inner errors of an `AggregateError` into `failureMessages`, `retryReasons` and `unhandledErrors`, so `--json` output and reporter annotations include them ([#16316](https://redirect.github.com/jestjs/jest/pull/16316))
> * `[jest-circus, jest-snapshot]` Keep snapshot state and counts correct when a test retries ([#16344](https://redirect.github.com/jestjs/jest/pull/16344))
> * `[@jest/create-cache-key-function]` Include the caller support flags in the generated key, so a transformer that emits ESM or CJS based on them no longer shares one cache entry between the two ([#16331](https://redirect.github.com/jestjs/jest/pull/16331))

... (truncated)


Commits

* [`9ab14fe`](jestjs/jest@9ab14fe) v30.5.1
* [`912baa3`](jestjs/jest@912baa3) v30.5.0
* [`b91717a`](jestjs/jest@b91717a) chore: refresh coding agent instructions ([#16182](https://github.com/jestjs/jest/tree/HEAD/packages/jest-environment-jsdom/issues/16182))
* [`3955d24`](jestjs/jest@3955d24) Make `@​types/jsdom` a peer dependency of jest-environment-jsdom-abstract ([#16166](https://github.com/jestjs/jest/tree/HEAD/packages/jest-environment-jsdom/issues/16166))
* See full diff in [compare view](https://github.com/jestjs/jest/commits/v30.5.1/packages/jest-environment-jsdom)
mergify Bot added a commit to robfrank/linklift that referenced this pull request Sep 6, 2026
Bumps [jest](https://github.com/jestjs/jest/tree/HEAD/packages/jest) from 30.4.2 to 30.5.1.
Release notes

*Sourced from [jest's releases](https://github.com/jestjs/jest/releases).*

> v30.5.1
> -------
>
> Fixes
> -----
>
> * `[jest-config]` Don't warn about global-only options in the config that supplies the global config - the root config a project resolves to, or the first entry of `--projects` when no root config is passed ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-config, jest-types]` Stop accepting `reporters`, `coverageReporters`, `workerIdleMemoryLimit`, `cwd` and `runnerOptions` in a project config - they were silently ignored, and now warn like the other global-only options ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-config, jest-validate]` Warn about `maxWorkers` and `coverageThreshold` in a project config instead of dropping them without a word ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-resolve]` Match `moduleNameMapper` patterns against the specifier as written again (reverting [#16390](https://redirect.github.com/jestjs/jest/pull/16390)) ([#16417](https://redirect.github.com/jestjs/jest/pull/16417))
> * `[jest-runtime]` Resolve package `imports` specifiers like `#dep` under ESM again ([#16413](https://redirect.github.com/jestjs/jest/pull/16413))
>
> Chore & Maintenance
> -------------------
>
> * `[jest-util]` Name the `testEnvironmentOptions.globalsCleanup` option and link the docs from the `JEST-01` deprecation warning, and document the option's modes ([#16404](https://redirect.github.com/jestjs/jest/pull/16404))
>
> New Contributors
> ----------------
>
> * [`@​HuzaifaChaudary`](https://github.com/HuzaifaChaudary) made their first contribution in [jestjs/jest#16413](https://redirect.github.com/jestjs/jest/pull/16413)
>
> **Full Changelog**: <jestjs/jest@v30.5.0...v30.5.1>
>
> v30.5.0
> -------
>
> On a personal note: King Harald V of Norway passed away this morning. He ascended the throne 35 years ago, two months before I was born. This release is dedicated to his memory. Hvil i fred 🇳🇴
>
> ---
>
> This is a big release. It touches `jest-runtime`, `jest-resolve` and `jest-haste-map` in many places, and with this many changes there might be regressions 😬. If your suite behaves differently after upgrading, please [open an issue](https://github.com/jestjs/jest/issues).
>
> Highlights
> ==========
>
> `whenCalledWith`
> ----------------
>
> Mock functions can now configure return values per argument list, contributed by [`@​timkindberg`](https://github.com/timkindberg) ([#16053](https://redirect.github.com/jestjs/jest/pull/16053)):
>
> ```
> const fn = jest.fn();
> fn.whenCalledWith('apple').mockReturnValue('red');
> fn.whenCalledWith('banana').mockReturnValue('yellow');
> fn.whenCalledWith(expect.any(Number)).mockReturnValue('numeric');
>
> fn('apple'); // 'red'
> fn('banana'); // 'yellow'
> fn(42); // 'numeric'
> fn('grape'); // undefined
> ```
>
> The returned object is a real `Mock`, so `mockReturnValueOnce`, `mockResolvedValue`, `mockImplementation` etc. all chain here too. Argument slots accept literals or any asymmetric matcher, with the same equality semantics as `toHaveBeenCalledWith()`. Calls that match nothing fall through to the base mock. See the [Mock Functions docs](https://jestjs.io/docs/mock-function-api#mockfnwhencalledwithargs) for matching and precedence details.
>
> Describe-level retries
> ----------------------
>
> `jest.retryTimes()` can now retry a whole `describe` block instead of a single test, contributed by [`@​soltonigiri`](https://github.com/soltonigiri) ([#16322](https://redirect.github.com/jestjs/jest/pull/16322)). Each attempt reruns the block's `beforeAll`/`afterAll` hooks, child tests and nested describes, which helps when tests in a block depend on shared state:
>
> ```
> </tr></table>
> ```

... (truncated)


Changelog

*Sourced from [jest's changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md).*

> 30.5.1
> ------
>
> ### Fixes
>
> * `[jest-config]` Don't warn about global-only options in the config that supplies the global config - the root config a project resolves to, or the first entry of `--projects` when no root config is passed ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-config, jest-types]` Stop accepting `reporters`, `coverageReporters`, `workerIdleMemoryLimit`, `cwd` and `runnerOptions` in a project config - they were silently ignored, and now warn like the other global-only options ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-config, jest-validate]` Warn about `maxWorkers` and `coverageThreshold` in a project config instead of dropping them without a word ([#16411](https://redirect.github.com/jestjs/jest/pull/16411))
> * `[jest-resolve]` Match `moduleNameMapper` patterns against the specifier as written again (reverting [#16390](https://redirect.github.com/jestjs/jest/pull/16390)) ([#16417](https://redirect.github.com/jestjs/jest/pull/16417))
> * `[jest-runtime]` Resolve package `imports` specifiers like `#dep` under ESM again ([#16413](https://redirect.github.com/jestjs/jest/pull/16413))
>
> ### Chore & Maintenance
>
> * `[jest-util]` Name the `testEnvironmentOptions.globalsCleanup` option and link the docs from the `JEST-01` deprecation warning, and document the option's modes ([#16404](https://redirect.github.com/jestjs/jest/pull/16404))
>
> 30.5.0
> ------
>
> ### Features
>
> * `[@jest/expect-utils, jest-mock]` Add `mockFn.whenCalledWith(...args)` for configuring return values per argument list, with first-class asymmetric-matcher support ([#16053](https://redirect.github.com/jestjs/jest/pull/16053))
> * `[@jest/expect-utils]` Export `AsymmetricMatcher` and `FunctionParameters` types (previously private to `expect`) ([#16053](https://redirect.github.com/jestjs/jest/pull/16053))
> * `[jest-circus, jest-core, jest-jasmine2, jest-test-result, jest-types]` `--collectTests` now expands `test.each`/`describe.each` cases and reports per-status counts (skipped/todo via the new `wouldRun` flag for selected tests) plus a summary line that match a real run, including under `--testNamePattern` and `.only`/`fdescribe` focus on both the circus and jasmine2 runners ([#16259](https://redirect.github.com/jestjs/jest/pull/16259))
> * `[jest-circus, jest-environment, jest-runtime, jest-types]` Add describe-level retries via `jest.retryTimes(..., {entireDescribe: true})` ([#16322](https://redirect.github.com/jestjs/jest/pull/16322))
> * `[jest-circus, jest-message-util, jest-reporters, jest-types]` Add `retryMessages` to `AssertionResult` and export `formatErrorStack`, so the retry log renders nested `cause` and `AggregateError` sections with code frames instead of serialized `[cause]:`/`[errors]:` markers ([#16316](https://redirect.github.com/jestjs/jest/pull/16316))
> * `[jest-circus, jest-types]` Add `unhandledErrorsDetailed` to `Circus.RunResult`, so an unhandled rejection reports its `cause` chain and `AggregateError` entries with code frames instead of a pre-serialized stack ([#16316](https://redirect.github.com/jestjs/jest/pull/16316))
> * `[jest-haste-map]` Replace `NodeWatcher` and `FSEventsWatcher` with `@parcel/watcher` for the non-watchman watch path ([#16188](https://redirect.github.com/jestjs/jest/pull/16188))
> * `[jest-resolve]` Bump `unrs-resolver` to 1.12.1, remove `jest-pnp-resolver` and unnecessary checks ([#15721](https://redirect.github.com/jestjs/jest/pull/15721))
> * `[jest-resolve]` Honor Node's `--preserve-symlinks` / `NODE_PRESERVE_SYMLINKS` in the default resolver by passing `symlinks: false` to `unrs-resolver` ([#16260](https://redirect.github.com/jestjs/jest/pull/16260))
> * `[jest-runtime]` Apply automocking and manual `__mocks__` files to synchronously evaluable ESM graphs on Node 24.9+ - static imports, dynamic `import()` and `require()` of an ESM file now generate an automock from the real module's namespace instead of failing with "Attempting to import a mock without a factory". Graphs that need async evaluation (top-level await) or an async-only resolver or transformer still throw ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Route `process.getBuiltinModule` through the sandbox, so it returns the sandbox `process` and the hooked `node:module` instead of the host's ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Throw an actionable error from `module.register()` and `module.registerHooks()` inside a test - the hooks attached to the loader running Jest itself, never saw the sandboxed requires they were meant for, and stayed registered for every later test file in the worker ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Surface resolution and import-attribute errors in an ESM graph before executing any of its CJS dependencies on Node 24.9+, matching Node's run-nothing-on-a-broken-graph behavior; the legacy loader on older versions keeps its linking-time execution order ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Throw `ERR_SOURCE_PHASE_NOT_DEFINED` with an actionable message for `import source` and `import.source()`, instead of failing at instantiation with V8's bare "Source phase import object is not defined" ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Emit the JSON-without-import-attribute deprecation warning once per test file instead of once per worker, so it is no longer silently swallowed for every file after the first ([#16391](https://redirect.github.com/jestjs/jest/pull/16391))
> * `[jest-runtime]` Set `import.meta.main` to `true` in the test file and `false` in every module it loads, matching Node 24+ ([#16367](https://redirect.github.com/jestjs/jest/pull/16367))
> * `[jest-runtime]` Resolve the `module-sync` export condition, so a package that exposes its ESM entry point for `require()` loads the same file Node would ([#16336](https://redirect.github.com/jestjs/jest/pull/16336))
> * `[jest-snapshot]` Add external snapshot paths to custom reporter failure details ([#16374](https://redirect.github.com/jestjs/jest/pull/16374))
>
> ### Fixes
>
> * `[jest-console, jest-reporters]` `CustomConsole` now buffers console output so `TestResult.console` is populated for reporters when `verbose` is enabled, while `GitHubActionsReporter` avoids replaying buffered output in verbose mode ([#16155](https://redirect.github.com/jestjs/jest/pull/16155))
> * `[expect, jest-message-util, jest-pattern, jest-regex-util, jest-util]` Revert `node:` protocol imports to restore webpack/browser-bundle compatibility ([#16167](https://redirect.github.com/jestjs/jest/pull/16167))
> * `[expect]` Widen `toMatchObject` and `objectContaining` parameter type from `Record<string, unknown>` to `object` so class instances are accepted ([#16196](https://redirect.github.com/jestjs/jest/pull/16196))
> * `[jest-circus]` Call a generator test body with the shared test context, so `this` matches what a regular test function receives ([#16347](https://redirect.github.com/jestjs/jest/pull/16347))
> * `[jest-circus]` Capture the error listeners of the parent process instead of the in-sandbox `process`, so listeners registered before the test file survive teardown and sandbox listeners no longer leak onto the parent ([#16347](https://redirect.github.com/jestjs/jest/pull/16347))
> * `[jest-circus]` Clear `currentlyRunningTest` after skipped and todo tests ([#16342](https://redirect.github.com/jestjs/jest/pull/16342))
> * `[jest-circus]` Prevent late `done()` callbacks from affecting later test or hook invocations ([#16343](https://redirect.github.com/jestjs/jest/pull/16343))
> * `[jest-circus, jest-jasmine2]` Honor `--expand` when formatting `node:assert` failures, instead of always collapsing the diff ([#16347](https://redirect.github.com/jestjs/jest/pull/16347))
> * `[jest-circus, jest-jasmine2, jest-message-util]` Serialize the inner errors of an `AggregateError` into `failureMessages`, `retryReasons` and `unhandledErrors`, so `--json` output and reporter annotations include them ([#16316](https://redirect.github.com/jestjs/jest/pull/16316))
> * `[jest-circus, jest-snapshot]` Keep snapshot state and counts correct when a test retries ([#16344](https://redirect.github.com/jestjs/jest/pull/16344))
> * `[@jest/create-cache-key-function]` Include the caller support flags in the generated key, so a transformer that emits ESM or CJS based on them no longer shares one cache entry between the two ([#16331](https://redirect.github.com/jestjs/jest/pull/16331))

... (truncated)


Commits

* [`9ab14fe`](jestjs/jest@9ab14fe) v30.5.1
* [`912baa3`](jestjs/jest@912baa3) v30.5.0
* [`b91717a`](jestjs/jest@b91717a) chore: refresh coding agent instructions ([#16182](https://github.com/jestjs/jest/tree/HEAD/packages/jest/issues/16182))
* See full diff in [compare view](https://github.com/jestjs/jest/commits/v30.5.1/packages/jest)
renovate Bot added a commit to NiGhTTraX/jest-react-mock that referenced this pull request Sep 19, 2026
| datasource | package                | from   | to     |
| ---------- | ---------------------- | ------ | ------ |
| npm        | jest                   | 30.4.2 | 30.5.1 |
| npm        | jest-environment-jsdom | 30.4.1 | 30.5.1 |


## [v30.5.1](https://github.com/jestjs/jest/blob/HEAD/CHANGELOG.md#3051)

##### Fixes

- `[jest-config]` Don't warn about global-only options in the config that supplies the global config - the root config a project resolves to, or the first entry of `--projects` when no root config is passed ([#16411](jestjs/jest#16411))
- `[jest-config, jest-types]` Stop accepting `reporters`, `coverageReporters`, `workerIdleMemoryLimit`, `cwd` and `runnerOptions` in a project config - they were silently ignored, and now warn like the other global-only options ([#16411](jestjs/jest#16411))
- `[jest-config, jest-validate]` Warn about `maxWorkers` and `coverageThreshold` in a project config instead of dropping them without a word ([#16411](jestjs/jest#16411))
- `[jest-resolve]` Match `moduleNameMapper` patterns against the specifier as written again (reverting [#16390](jestjs/jest#16390)) ([#16417](jestjs/jest#16417))
- `[jest-runtime]` Resolve package `imports` specifiers like `#dep` under ESM again ([#16413](jestjs/jest#16413))

##### Chore & Maintenance

- `[jest-util]` Name the `testEnvironmentOptions.globalsCleanup` option and link the docs from the `JEST-01` deprecation warning, and document the option's modes ([#16404](jestjs/jest#16404))


## [v30.5.0](https://github.com/jestjs/jest/blob/HEAD/CHANGELOG.md#3050)

##### Features

- `[@jest/expect-utils, jest-mock]` Add `mockFn.whenCalledWith(...args)` for configuring return values per argument list, with first-class asymmetric-matcher support ([#16053](jestjs/jest#16053))
- `[@jest/expect-utils]` Export `AsymmetricMatcher` and `FunctionParameters` types (previously private to `expect`) ([#16053](jestjs/jest#16053))
- `[jest-circus, jest-core, jest-jasmine2, jest-test-result, jest-types]` `--collectTests` now expands `test.each`/`describe.each` cases and reports per-status counts (skipped/todo via the new `wouldRun` flag for selected tests) plus a summary line that match a real run, including under `--testNamePattern` and `.only`/`fdescribe` focus on both the circus and jasmine2 runners ([#16259](jestjs/jest#16259))
- `[jest-circus, jest-environment, jest-runtime, jest-types]` Add describe-level retries via `jest.retryTimes(..., {entireDescribe: true})` ([#16322](jestjs/jest#16322))
- `[jest-circus, jest-message-util, jest-reporters, jest-types]` Add `retryMessages` to `AssertionResult` and export `formatErrorStack`, so the retry log renders nested `cause` and `AggregateError` sections with code frames instead of serialized `[cause]:`/`[errors]:` markers ([#16316](jestjs/jest#16316))
- `[jest-circus, jest-types]` Add `unhandledErrorsDetailed` to `Circus.RunResult`, so an unhandled rejection reports its `cause` chain and `AggregateError` entries with code frames instead of a pre-serialized stack ([#16316](jestjs/jest#16316))
- `[jest-haste-map]` Replace `NodeWatcher` and `FSEventsWatcher` with `@parcel/watcher` for the non-watchman watch path ([#16188](jestjs/jest#16188))
- `[jest-resolve]` Bump `unrs-resolver` to 1.12.1, remove `jest-pnp-resolver` and unnecessary checks ([#15721](jestjs/jest#15721))
- `[jest-resolve]` Honor Node's `--preserve-symlinks` / `NODE_PRESERVE_SYMLINKS` in the default resolver by passing `symlinks: false` to `unrs-resolver` ([#16260](jestjs/jest#16260))
- `[jest-runtime]` Apply automocking and manual `__mocks__` files to synchronously evaluable ESM graphs on Node 24.9+ - static imports, dynamic `import()` and `require()` of an ESM file now generate an automock from the real module's namespace instead of failing with "Attempting to import a mock without a factory". Graphs that need async evaluation (top-level await) or an async-only resolver or transformer still throw ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Route `process.getBuiltinModule` through the sandbox, so it returns the sandbox `process` and the hooked `node:module` instead of the host's ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Throw an actionable error from `module.register()` and `module.registerHooks()` inside a test - the hooks attached to the loader running Jest itself, never saw the sandboxed requires they were meant for, and stayed registered for every later test file in the worker ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Surface resolution and import-attribute errors in an ESM graph before executing any of its CJS dependencies on Node 24.9+, matching Node's run-nothing-on-a-broken-graph behavior; the legacy loader on older versions keeps its linking-time execution order ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Throw `ERR_SOURCE_PHASE_NOT_DEFINED` with an actionable message for `import source` and `import.source()`, instead of failing at instantiation with V8's bare "Source phase import object is not defined" ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Emit the JSON-without-import-attribute deprecation warning once per test file instead of once per worker, so it is no longer silently swallowed for every file after the first ([#16391](jestjs/jest#16391))
- `[jest-runtime]` Set `import.meta.main` to `true` in the test file and `false` in every module it loads, matching Node 24+ ([#16367](jestjs/jest#16367))
- `[jest-runtime]` Resolve the `module-sync` export condition, so a package that exposes its ESM entry point for `require()` loads the same file Node would ([#16336](jestjs/jest#16336))
- `[jest-snapshot]` Add external snapshot paths to custom reporter failure details ([#16374](jestjs/jest#16374))

##### Fixes

- `[jest-console, jest-reporters]` `CustomConsole` now buffers console output so `TestResult.console` is populated for reporters when `verbose` is enabled, while `GitHubActionsReporter` avoids replaying buffered output in verbose mode ([#16155](jestjs/jest#16155))
- `[expect, jest-message-util, jest-pattern, jest-regex-util, jest-util]` Revert `node:` protocol imports to restore webpack/browser-bundle compatibility ([#16167](jestjs/jest#16167))
- `[expect]` Widen `toMatchObject` and `objectContaining` parameter type from `Record<string, unknown>` to `object` so class instances are accepted ([#16196](jestjs/jest#16196))
- `[jest-circus]` Call a generator test body with the shared test context, so `this` matches what a regular test function receives ([#16347](jestjs/jest#16347))
- `[jest-circus]` Capture the error listeners of the parent process instead of the in-sandbox `process`, so listeners registered before the test file survive teardown and sandbox listeners no longer leak onto the parent ([#16347](jestjs/jest#16347))
- `[jest-circus]` Clear `currentlyRunningTest` after skipped and todo tests ([#16342](jestjs/jest#16342))
- `[jest-circus]` Prevent late `done()` callbacks from affecting later test or hook invocations ([#16343](jestjs/jest#16343))
- `[jest-circus, jest-jasmine2]` Honor `--expand` when formatting `node:assert` failures, instead of always collapsing the diff ([#16347](jestjs/jest#16347))
- `[jest-circus, jest-jasmine2, jest-message-util]` Serialize the inner errors of an `AggregateError` into `failureMessages`, `retryReasons` and `unhandledErrors`, so `--json` output and reporter annotations include them ([#16316](jestjs/jest#16316))
- `[jest-circus, jest-snapshot]` Keep snapshot state and counts correct when a test retries ([#16344](jestjs/jest#16344))
- `[@jest/create-cache-key-function]` Include the caller support flags in the generated key, so a transformer that emits ESM or CJS based on them no longer shares one cache entry between the two ([#16331](jestjs/jest#16331))
- `[@jest/create-cache-key-function]` Include the stringified project config in the generated key, so editing a transformer's own settings invalidates what it cached ([#16331](jestjs/jest#16331))
- `[@jest/transform]` Include the caller support flags in a transform's cache key, so a file transformed both as ESM and as CJS no longer serves one shape's output for the other ([#16331](jestjs/jest#16331))
- `[jest-config]` Add missing `findRelatedTests`, `outputFile`, and `replname` entries to `ValidConfig` so they no longer trigger spurious "Unknown option" warnings ([#16224](jestjs/jest#16224))
- `[jest-config]` Use `--config` for the global config when multiple `--projects` are specified ([#16273](jestjs/jest#16273))
- `[jest-core]` Serialize `bigint` values in `--json` and `--outputFile` output as their literal form (`4n`), instead of failing the run with `TypeError: Do not know how to serialize a BigInt` ([#16338](jestjs/jest#16338))
- `[jest-core]` Do not report a `CustomGC` async resource (used by N-API addons such as napi-rs for per-isolate GC bookkeeping) as an open handle, since it is `napi_unref`'d by the addon and can never keep the event loop alive ([#16379](jestjs/jest#16379))
- `[jest-each]` Keep a `$&`, `` $` ``, `$'` or `$$` inside a `%p` param value out of the replacement, so the title shows the value instead of the text around it ([#16338](jestjs/jest#16338))
- `[jest-each]` Interpolate a `bigint` into a `%j` title as its literal form (`"4n"`) at any depth, instead of throwing `TypeError: Do not know how to serialize a BigInt` while collecting the tests ([#16338](jestjs/jest#16338))
- `[jest-environment, jest-runtime]` Bind `sandboxInjectedGlobals` to the right values when `injectGlobals` is `false`, instead of shifting every one of them by a position ([#16377](jestjs/jest#16377))
- `[jest-environment-node, jest-util]` Only warn about a conflicting `globalsCleanup` mode when one was explicitly configured, and follow the mode that is actually in effect ([#16323](jestjs/jest#16323))
- `[jest-environment-node, jest-util]` Stop resolving lazy globals when setting up an environment, so Node 26's builtin module globals are no longer loaded (and no longer emit their deprecation warnings) for every test file ([#16324](jestjs/jest#16324))
- `[jest-haste-map]` Keep watch mode alive when an outside process briefly makes a file unreadable on Windows, instead of tearing the watcher down on `EPERM` ([#16295](jestjs/jest#16295))
- `[jest-haste-map]` Keep indexing when an outside process holds a file open on Windows, instead of failing the whole crawl on `EPERM` ([#16358](jestjs/jest#16358))
- `[jest-haste-map]` Keep a duplicated manual mock resolving when the file it pointed at is deleted in watch mode ([#16360](jestjs/jest#16360))
- `[jest-haste-map]` Shut the worker farm down when a duplicate manual mock aborts the build under `throwOnModuleCollision` ([#16354](jestjs/jest#16354))
- `[jest-haste-map]` Attach the watchman client's `error` listener before the first command, so a watchman failure falls back to the node crawler instead of crashing on an unhandled `error` event, and always end the client ([#16355](jestjs/jest#16355))
- `[jest-haste-map]` Stop delivering watch events after `WatchmanWatcher` is closed, and route its warnings through the configured console ([#16355](jestjs/jest#16355))
- `[jest-haste-map]` Restore the nested `duplicates` index correctly in `ModuleMap.fromJSON`, so a haste collision reported inside a test worker raises `DuplicateHasteCandidatesError` instead of a `TypeError` ([#16353](jestjs/jest#16353))
- `[jest-haste-map]` Match watched files on a full extension, so `moduleFileExtensions: ['js']` no longer accepts `foo.mjs` ([#16352](jestjs/jest#16352))
- `[jest-haste-map]` Delimit the fields that make up the haste map cache key, so two different option sets cannot hash to the same cache file ([#16352](