v30.5.0
Breaking Changes📦 jestView on GitHub →
⚠ 2 breaking✨ 14 features🐛 17 fixes🔧 22 symbols
Summary
This release introduces `mockFn.whenCalledWith` for granular mock return values and `jest.retryTimes` for entire describe blocks. It also features a significant rewrite of the file watcher using `@parcel/watcher` and `fdir`, alongside numerous performance improvements and ESM compatibility enhancements.
⚠️ Breaking Changes
- The `source-map-support` package has been replaced with an internal implementation in `@jest/source-map`. This change fixes a memory leak but might affect custom configurations relying on `source-map-support`'s global caches or specific behaviors.
- The default resolver now honors Node's `--preserve-symlinks` / `NODE_PRESERVE_SYMLINKS` behavior. If your project relies on symlinks being resolved differently, you may need to adjust your Jest configuration or test setup.
Migration Steps
- If you encounter issues with symlinks, consider adjusting your Jest configuration or test setup to align with Node's `--preserve-symlinks` behavior.
- If you have custom logic relying on `source-map-support`'s global caches, you may need to migrate that logic to the new `@jest/source-map` implementation.
✨ New Features
- Mock functions can now configure return values per argument list using `mockFn.whenCalledWith(...args)`, supporting literals and asymmetric matchers.
- Jest can now retry an entire `describe` block using `jest.retryTimes(n, {entireDescribe: true})`, rerunning `beforeAll`/`afterAll` hooks and nested tests.
- The non-watchman file watcher has been rewritten using `@parcel/watcher` and `fdir` for improved performance and reliability.
- Dependency updates include `babel-plugin-istanbul` to v8 and `glob` to v13.
- Snapshot failures now expose the `.snap` file path as `matcherResult.snapshotPath` in `failureDetails`.
- `--collectTests` now expands `test.each`/`describe.each` cases and reports per-status counts.
- AggregateError now renders inner errors and nested `cause` chains with code frames and indentation, and includes them in `--json` output and reporter annotations.
- Automocking and manual `__mocks__` files now apply to ESM on Node 24.9+, handling static imports, dynamic `import()`, and `require()` of ESM files by generating mocks from the real module's namespace.
- Gaps in `jest.unstable_mockModule` have been closed, including proper handling of `require()`d mocked files, single execution of async factories, and scoped mocks within `jest.isolateModules`.
- Jest's module system now matches Node.js more closely for `require(esm)`, CJS/ESM interop, `import.meta`, `data:` URIs, and error ordering.
- The `module-sync` export condition is now resolved, ensuring packages expose their ESM entry point for `require()` correctly.
- The default resolver now honors Node's `--preserve-symlinks` / `NODE_PRESERVE_SYMLINKS`.
- `moduleNameMapper` now applies to both `fs` and `node:fs` specifiers, and builtins like `node:sqlite` resolve asynchronously.
- User-defined resolvers can now be written as ES modules.
🐛 Bug Fixes
- Fixes a memory leak in `source-map-support` by replacing it with an internal implementation.
- Watching and indexing now survive locked files on Windows, watchman failures, and duplicate manual mocks.
- Warm module resolution costs are reduced significantly.
- Per-`require` overhead in `jest-runtime` is cut by skipping module ID resolution when no mock applies and prioritizing core modules.
- `jest-snapshot` now loads dependencies lazily, reducing the number of modules loaded per test process.
- `jest-haste-map` caches the watchman socket path to avoid spawning watchman processes on warm runs.
- `jest-haste-map` reuses cached metadata for duplicated haste names.
- ESM automocking and manual mocks now correctly handle static imports, dynamic `import()`, and `require()` of ESM files.
- `jest.unstable_mockModule` now correctly applies mocks when the mocked file is `require()`d directly.
- Async factories in `jest.unstable_mockModule` now run once and fail the import instead of crashing the worker.
- Mocks created within `jest.isolateModules` now stay scoped to that block.
- Fixes dozens of edge cases in ESM/CJS interop, `require(esm)`, `import.meta`, `data:` URIs, and error ordering to match Node.js.
- The `module-sync` export condition is now resolved.
- The default resolver now honors Node's `--preserve-symlinks` / `NODE_PRESERVE_SYMLINKS`.
- `moduleNameMapper` now applies to both `fs` and `node:fs` specifiers.
- Builtin modules that only exist prefixed (e.g., `node:sqlite`, `node:test`) now resolve asynchronously.
- A user resolver can be written as an ES module.
Affected Symbols
`jest-runtime``jest-resolve``jest-haste-map``jest-mock``@jest/expect-utils``jest-circus``jest-core``jest-jasmine2``jest-test-result``jest-types``jest-snapshot``@jest/source-map``jest.fn()``jest.retryTimes()``@parcel/watcher``fdir``babel-plugin-istanbul``glob``source-map-support``jest.unstable_mockModule()``jest.isolateModules()``moduleNameMapper`