Jest 30: Faster, Leaner, Better
Today we are happy to announce the release of Jest 30. This release features a substantial number of changes, fixes, and improvements. While it is one of the largest major releases of Jest ever, we admit that three years for a major release is too long. In the future, we are aiming to make more frequent major releases to keep Jest great for the next decade.
If you want to skip all the news and just get going, run npm install jest@^30.0.0
and follow the migration guide: Upgrading from Jest 29 to 30.
What’s New?
Jest 30 is noticeably faster, uses less memory, and comes with tons of new features. First, let’s take a look at the breaking changes:
Breaking Changes
- Jest 30 drops support for Node 14, 16, 19, and 21.
jest-environment-jsdom
was upgraded from jsdom 21 to 26.- The minimum compatible TypeScript version is now 5.4.
- Various
expect
aliases were removed.eslint-plugin-jest
has an autofixer which you can run to automatically upgrade your codebase. - Non-enumerable object properties are now excluded from object matchers such as
toEqual
by default. - Jest now supports
.mts
and.cts
files by default. --testPathPattern
was renamed to--testPathPatterns
.- Jest now properly handles promises that are first rejected and then later caught to avoid false positive test failures.
- We made various improvements to Jest’s printing of snapshots which might require you to update snapshots. Google deprecated
goo.gl
links which we were using in snapshots. We don’t like it either, but you’ll have to update all your snapshots. - Jest itself is now bundled into a single file per package. This improves performance, but might break if you built tools that reach into Jest's internals.
These are just some of the highlights. The full list of breaking changes can be found in the CHANGELOG and the Jest 30 migration guide.
Performance & Memory Improvements
Jest 30 delivers real-world performance gains thanks to many optimizations, especially related to module resolution, memory usage, and test isolation. By relying on the new unrs-resolver, module resolution in Jest became more feature-rich, standards-compliant, and faster. Thanks to @JounQin for the migration. Depending on your project, you may see significantly faster test runs and reduced memory consumption. For example, one large TypeScript app with a client and server observed 37% faster test runs and 77% lower memory usage in one part of their codebase:
Jest 29 | Jest 30 | |
---|---|---|
Server tests | ~1350s / 7.8 GB max | ~850s / 1.8 GB max |
Client tests | ~49s / 1.0 GB max | ~44s / 0.8 GB max |
Jest is fast, but due to Jest's test isolation, slow user code often exacerbates performance issues and leads to slow test runs. When tests leave behind open handles like unclosed timers or connections to other services, it can cause Jest to hang or slow down. Jest 30 has gotten better at detecting and reporting these issues, which helps you identify and fix slow or problematic tests more easily. For example, tests at Happo were sped up by 50% from 14 minutes down to 9 minutes by cleaning up open handles and upgrading to Jest 30.
If you are using files that consolidate the exports of multiple modules into a single file (i.e. "barrel files"), we recommend using tools such as babel-jest-boost
, babel-plugin-transform-barrels
or no-barrel-file
to avoid loading large swaths of application code for each test file. This can lead to performance improvements of up to 100x.
Globals cleanup between test files
Jest achieves test isolation between files by running each test in a separate VM context, giving each file a fresh global environment. However, if your code does not clean up globals after each test file, it can lead to memory leaks across Jest and slow down your test runs. Jest 30 introduces a new feature that notifies you about globals that are not correctly cleaned up after a test run.
In the future, Jest will automatically clean up globals after each test run. If you don't get any warnings about uncleaned globals with Jest 30, you can already set the globals cleanup mode to "on" now to enable this feature fully, and benefit from major memory savings and performance improvements:
export default {
testEnvironmentOptions: {
globalsCleanup: 'on',
},
};
The default in Jest is globalsCleanup: 'soft'
. To disable this feature you can set it to off
. If you need to protect specific global objects from being cleaned up -- for example, shared utilities or caches -- you can mark them as protected using jest-util
:
import {protectProperties} from 'jest-util';
protectProperties(globalThis['my-property']);