Skip to content

docs: add blog post for jest 30 (#15556) #15650

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 10, 2025

Conversation

MillerSvt
Copy link
Contributor

@MillerSvt MillerSvt commented Jun 4, 2025

ToDo

  • Check all contributors links manually

Copy link

netlify bot commented Jun 4, 2025

Deploy Preview for jestjs ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 083bb8c
🔍 Latest deploy log https://app.netlify.com/projects/jestjs/deploys/684790d24800730008c12279
😎 Deploy Preview https://deploy-preview-15650--jestjs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

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

@MillerSvt MillerSvt force-pushed the add-blog-post-jest-30 branch from 9dec7f8 to f6c1ebd Compare June 4, 2025 06:27
@cpojer
Copy link
Member

cpojer commented Jun 4, 2025

How much of this did you write by hand vs. an llm?

@MillerSvt MillerSvt force-pushed the add-blog-post-jest-30 branch from f6c1ebd to 02d3487 Compare June 4, 2025 08:07
@MillerSvt
Copy link
Contributor Author

How much of this did you write by hand vs. an llm?

I use a language model for 70% of the work, and I handle the remaining 30% manually. Sometimes the model misinterprets the intended changes, so I review and correct them. Additionally, I add code previews and links to relevant documentation to enhance clarity and usability.

Tomorrow, I'll examine it with a fresh head to address any remaining issues.

@MillerSvt MillerSvt force-pushed the add-blog-post-jest-30 branch from 02d3487 to 53fbbc3 Compare June 4, 2025 08:12

ESM support isn’t just about file extensions. **Under the hood, Jest’s packages now provide proper ESM exports** and have been restructured for better ESM compatibility. All of Jest’s internal modules are bundled into a few files for faster startup, and each official package defines an export map for Node’s ESM resolver. For the average user, this change is invisible – you continue to use Jest the same way – but it generally improves performance by reducing the file I/O overhead on startup. (One side effect: if you were importing internal, unofficial modules from Jest’s code, those imports will break due to the repackaging – but doing that was never supported, so it won’t affect normal usage.)

On a related note, **Jest 30’s module resolution got smarter for Node ESM features**. You can now use `import.meta` properties in your tests and modules when running under Jest. Specifically, Jest 30 supports `import.meta.url`, `import.meta.filename`, `import.meta.dirname`, and even the new `import.meta.resolve` for module resolution. If you have tests or library code that rely on these ESM-specific globals (for example, determining the current file path via `import.meta.url`), Jest will no longer choke on them – it handles these as Node does (note that some of these features require Node 20+). Additionally, Jest’s resolver now understands `file://` URL imports, which can appear in ESM contexts. Jest now also respects Node’s conditional exports when resolving stub modules (like manual mocks), passing along the `conditions` option. This ensures even stubbed modules pick the correct export variant for the current environment. All of this means Jest 30 plays more nicely with modern ESM projects.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we mention https://github.com/unrs/unrs-resolver in favor of #15619?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't understand what it is. Add a change suggestion.

| **Server tests** | ~1350s / 7.8 GB max | ~850s / 1.8 GB max |
| **Client tests** | ~49s / 1.0 GB max | ~44s / 0.8 GB max |

These improvements come from Jest 30’s work on memory leaks, module loading efficiency, and better ESM handling under the hood. While your mileage may vary, many projects – especially large ones – should see Jest 30 running tests a bit faster and using less memory than before.
Copy link
Contributor

Choose a reason for hiding this comment

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

Let me know if you'd like some more data for this section. I am close to having a fully passing test run for our tests at Happo and I'd be happy to share some performance numbers for this post.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think any data is appreciate

Copy link
Contributor

Choose a reason for hiding this comment

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

Here are some numbers for running Jest v29 vs v30 on our main tests at Happo.

206 suites with 1804 tests total

  • Local: 2024 MacBook Air M3
  • CI: CircleCI medium resource class (2 vCPUs, 4GB RAM), using --runInBand)

For the CI times, I only counted the time spent in the step that runs Jest, and not all of the setup and teardown.

Jest Version Local Time / Max Heap CI Time (Total of 6 Shards)
Jest 29 1m 31s / 450 MiB 11m 5s
Jest 30 with globalsCleanupMode default setting 1m 42s / 328 MiB 9m 31s
Jest 30 with globalsCleanupMode: 'hard' 1m 43s / 315 MiB 9m 47s

Here are some charts that CircleCI generates of resource usage over the job run. Note that while these jobs are for Jest only, these charts include the setup steps so to understand what it looks like for Jest running, pay most attention to the last couple of minutes of the run or so.

Jest 29:

image

Jest 30 with globalsCleanupMode default setting:

image

Jest 30 with globalsCleanupMode: 'hard':

image

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I should also mention that I landed all of the fixes that I needed to do before updating to Jest 30, mostly around fixing open handles. Those seemed to have a bigger impact on performance.

On Jest 29 before I landed these fixes, Jest in CI ran in 14m 26s (divided among 6 shards). Here's the resource graph for that:

image


### `testPathPattern` is now `testPathPatterns`

You’ll need to update your config and any CLI usage. In config files, `testPathPatterns` now expects an array of patterns (instead of a single regex). This actually makes the feature more flexible – you can specify multiple include patterns for test files. Correspondingly, the CLI flag is now `--testPathPatterns` (with an “s”). You can provide multiple patterns separated by spaces or by using the flag multiple times. This change shouldn’t affect you unless you were filtering tests by path, but it’s an easy find-and-replace if so.
Copy link
Contributor

Choose a reason for hiding this comment

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

This should probably be more explicit about changing testPathPattern to testPathPatterns and maybe offer some before and after examples for extra clarity.

@cpojer
Copy link
Member

cpojer commented Jun 5, 2025

I'll take a pass on the blog post soon, until then I suggest holding off on reviewing beyond mentioning what else needs to be mentioned.

@MillerSvt MillerSvt force-pushed the add-blog-post-jest-30 branch from 53fbbc3 to 8cf7413 Compare June 5, 2025 01:57
@MillerSvt MillerSvt closed this Jun 5, 2025
@MillerSvt MillerSvt reopened this Jun 5, 2025

### `testPathPattern` is now `testPathPatterns`

You’ll need to update your config and any CLI usage. In config files, `testPathPatterns` now expects an array of patterns (instead of a single regex). This actually makes the feature more flexible – you can specify multiple include patterns for test files. Correspondingly, the CLI flag is now `--testPathPatterns` (with an “s”). You can provide multiple patterns separated by spaces or by using the flag multiple times. This change shouldn’t affect you unless you were filtering tests by path, but it’s an easy find-and-replace if so.
Copy link
Contributor

Choose a reason for hiding this comment

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

This mentions config files but it turns out it is cli only

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It changes in config too. See #12519 (packages/jest-types/src/Config.ts)

Copy link
Contributor

Choose a reason for hiding this comment

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

@MillerSvt MillerSvt force-pushed the add-blog-post-jest-30 branch from 8cf7413 to 600e055 Compare June 6, 2025 12:58
Copy link

pkg-pr-new bot commented Jun 6, 2025

Open in StackBlitz

babel-jest

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

babel-plugin-jest-hoist

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

babel-preset-jest

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

create-jest

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

@jest/diff-sequences

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

expect

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

@jest/expect-utils

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

jest

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

jest-changed-files

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

jest-circus

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

jest-cli

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

jest-config

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

@jest/console

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

@jest/core

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

@jest/create-cache-key-function

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

jest-diff

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

jest-docblock

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

jest-each

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

@jest/environment

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

jest-environment-jsdom

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

@jest/environment-jsdom-abstract

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

jest-environment-node

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

@jest/expect

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

@jest/fake-timers

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

@jest/get-type

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

@jest/globals

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

jest-haste-map

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

jest-jasmine2

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

jest-leak-detector

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

jest-matcher-utils

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

jest-message-util

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

jest-mock

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

@jest/pattern

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

jest-phabricator

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

jest-regex-util

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

jest-repl

npm i https://pkg.pr.new/jest-repl@15650

@jest/reporters

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

jest-resolve

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

jest-resolve-dependencies

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

jest-runner

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

jest-runtime

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

@jest/schemas

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

jest-snapshot

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

@jest/snapshot-utils

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

@jest/source-map

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

@jest/test-result

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

@jest/test-sequencer

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

@jest/transform

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

@jest/types

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

jest-util

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

jest-validate

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

jest-watcher

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

jest-worker

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

pretty-format

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

commit: 083bb8c

@cpojer cpojer force-pushed the add-blog-post-jest-30 branch 3 times, most recently from eaf0347 to e25edb6 Compare June 9, 2025 08:22
@cpojer
Copy link
Member

cpojer commented Jun 9, 2025

I updated the blog post. Thanks to @MillerSvt for the outline, it was really helpful! Would you all be able to give this a look?

Preview: https://deploy-preview-15650--jestjs.netlify.app/blog/2025/06/04/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](https://happo.io/) were sped up by 50% from 14 minutes down to 9 minutes by cleaning up open handles and upgrading to Jest 30.
Copy link
Member

Choose a reason for hiding this comment

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

@lencioni is this correct and are you ok with this mention?

Copy link
Contributor

Choose a reason for hiding this comment

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

The mention is good, thank you!

It might be clearer to rephrase the speed up bit like this:

Suggested change
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](https://happo.io/) were sped up by 50% from 14 minutes down to 9 minutes by cleaning up open handles and upgrading to Jest 30.
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, test times at [Happo](https://happo.io/) improved from 14 minutes down to 9 minutes—a 36% reduction—by cleaning up open handles and upgrading to Jest 30.

This 36% number also matches the math done in the previous paragraph (from 1350s to 850s being a 37% reduction).

Comment on lines 31 to 36
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](https://github.com/unrs/unrs-resolver), module resolution in Jest became more feature rich, standards compliant, and faster. Thanks to [@JounQin](https://github.com/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** |
Copy link
Member

Choose a reason for hiding this comment

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

@MillerSvt can we mention the source/company here? Who is this?

Copy link
Contributor

@lencioni lencioni left a comment

Choose a reason for hiding this comment

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

Looks great!

@cpojer cpojer force-pushed the add-blog-post-jest-30 branch from e25edb6 to 4f5465e Compare June 10, 2025 01:37
@cpojer
Copy link
Member

cpojer commented Jun 10, 2025

Did another iteration + added a "What's Next" section.

@cpojer cpojer force-pushed the add-blog-post-jest-30 branch from be955b5 to 0df129f Compare June 10, 2025 01:51
@cpojer cpojer force-pushed the add-blog-post-jest-30 branch from 0df129f to 083bb8c Compare June 10, 2025 01:56
@cpojer cpojer merged commit be842ac into jestjs:main Jun 10, 2025
76 checks passed
@cpojer
Copy link
Member

cpojer commented Jun 10, 2025

Jest 30 has shipped. Thanks everyone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants