从 v29 到 v30
要将 Jest 从 v29 升级到 v30 吗?本指南旨在帮助重构你的配置和测试。
¥Upgrading Jest from v29 to v30? This guide aims to help refactoring your configuration and tests.
兼容性
¥Compatibility
-
Jest 30 不再支持 Node 14、16、19 和 21。最低支持的 Node 版本现在为 18.x。升级之前,请确保你的环境使用的是兼容的 Node 版本。
¥Jest 30 drops support for Node 14, 16, 19, and 21. The minimum supported Node versions are now 18.x. Ensure your environment is using a compatible Node release before upgrading.
-
最低 TypeScript 版本现在为 5.4。如果你正在使用 Jest(或其任何软件包)的类型定义,请更新 TypeScript。
¥The minimum TypeScript version is now 5.4. Update TypeScript, if you are using type definitions of Jest (or any of its packages).
-
jest-environment-jsdom
包现在使用 JSDOM v26。此更新可能会引入 DOM 环境中的行为变更。如果你遇到 DOM 行为差异或新的警告,请参阅 v21-26 的 JSDOM 发行说明。¥The
jest-environment-jsdom
package now uses JSDOM v26. This update may introduce behavior changes in the DOM environment. If you encounter differences in DOM behavior or new warnings, refer to the JSDOM release notes for v21–26.
Jest Expect 和匹配器
¥Jest Expect & Matchers
移除别名匹配器函数
¥Removal of Alias Matcher Functions
所有别名匹配器名称均已删除,取而代之的是其主要名称。如果你一直在使用较旧的、已弃用的匹配器名称,则需要更新测试:
¥All alias matcher names have been removed in favor of their primary names. If you have been using older, deprecated matcher names, you will need to update your tests:
-
已移除别名及其替代:
¥Removed aliases and their replacements:
-
expect(fn).toBeCalled()
→expect(fn).toHaveBeenCalled()
-
expect(fn).toBeCalledTimes(n)
→expect(fn).toHaveBeenCalledTimes(n)
-
expect(fn).toBeCalledWith(arg)
→expect(fn).toHaveBeenCalledWith(arg)
-
expect(fn).lastCalledWith(arg)
→expect(fn).toHaveBeenLastCalledWith(arg)
-
expect(fn).nthCalledWith(n, arg)
→expect(fn).toHaveBeenNthCalledWith(n, arg)
-
expect(fn).toReturn()
→expect(fn).toHaveReturned()
-
expect(fn).toReturnTimes(n)
→expect(fn).toHaveReturnedTimes(n)
-
expect(fn).toReturnWith(val)
→expect(fn).toHaveReturnedWith(val)
-
expect(fn).lastReturnedWith(val)
→expect(fn).toHaveLastReturnedWith(val)
-
expect(fn).nthReturnedWith(n, val)
→expect(fn).toHaveNthReturnedWith(n, val)
-
expect(func).toThrowError(message)
→expect(func).toThrow(message)
-
这些别名方法自 Jest 26 起已弃用,并在 Jest 30 中被完全移除。在代码库中执行全局搜索和替换,以更新到规范的匹配器名称。功能相同 - 只有方法名称发生了变化。(如果你将 ESLint 与 eslint-plugin-jest
结合使用,no-alias-methods
规则可以帮助你自动执行此替换。)
¥These alias methods were deprecated since Jest 26, and in Jest 30 they are fully removed. Perform a global search-and-replace in your codebase to update to the canonical matcher names. The functionality is identical — only the method names have changed. (If you use ESLint with eslint-plugin-jest
, the no-alias-methods
rule can help automate this replacement.)
不可枚举属性
¥Non-enumerable properties
现在默认情况下,不可枚举的对象属性将被排除在对象匹配器之外。这可能会影响 expect.objectContaining
或相等性检查。
¥Non-enumerable object properties are now excluded from object matchers by default. This could affect expect.objectContaining
or equality checks.
CalledWith 类型推断改进
¥Improved Type Inference for CalledWith
TypeScript 用户:CalledWith
系列匹配器(例如 toHaveBeenCalledWith
)的类型已得到改进,可以推断函数参数类型。在大多数情况下,这将更准确地捕获类型不匹配的情况。这是一项编译时重大变更。
¥TypeScript users: The types for the CalledWith
family of matchers (e.g. toHaveBeenCalledWith
) have been improved to infer function parameter types. In most cases this will catch type mismatches more accurately. This is a compile-time breaking change.
如果你断言调用时使用的参数与实际函数的参数类型不匹配,TypeScript 现在可能会在这些测试中出错。例如,如果一个函数被输入为接受数字,并且你编写了 expect(fn).toHaveBeenCalledWith("string")
,TypeScript 5 + Jest 30 的类型将会标记此错误。匹配器的运行时行为保持不变。
¥If you were asserting calls with arguments that don’t match the actual function’s parameter types, TypeScript may now error on those tests. For example, if a function is typed to accept a number and you wrote expect(fn).toHaveBeenCalledWith("string")
, TypeScript 5 + Jest 30’s types will flag this. The runtime behavior of the matcher is unchanged.
要修复新的 TypeScript 错误,请确保测试参数与函数的预期类型一致(或者,如果你有意使用不同类型调用,请使用类型转换)。
¥To fix new TypeScript errors, ensure your test arguments align with the function’s expected types (or use type casts if you intentionally call with different types).
此更改不会影响运行时,但它可能会在测试中发现之前未被注意到的新类型错误,从而使你的测试更加类型安全。
¥This change doesn’t impact runtime, but it can surface new type errors in your tests that were previously unnoticed, making your tests more type-safe.
配置更新
¥Configuration Updates
支持 .mts
和 .cts
文件扩展名
¥Support for .mts
and .cts
File Extensions
Jest 30 扩展了对 ESM 和 TypeScript 模块文件扩展名的支持:
¥Jest 30 expands support for ESM and TypeScript module file extensions:
-
除了常见的扩展之外,默认的
moduleFileExtensions
现在还包含.mts
和.cts
(TypeScript ESM 和 CommonJS 模块)。¥The default
moduleFileExtensions
now include.mts
and.cts
(TypeScript ESM and CommonJS modules) in addition to the usual extensions. -
默认的
testMatch
和testRegex
模式已更新,现在可以将.mjs
、.cjs
、.mts
和.cts
文件识别为测试文件。¥The default
testMatch
andtestRegex
patterns have been updated to recognize.mjs
,.cjs
,.mts
, and.cts
files as test files.
如果你的项目包含具有这些扩展名的文件,并且这些文件不打算被视为模块或测试,则可能需要调整配置。相反,如果你有带有这些扩展名的测试文件,Jest 现在将默认检测它们(你可以删除之前需要包含它们的自定义配置)。
¥If your project contains files with these extensions that are not intended to be treated as modules or tests, you may need to adjust your configuration. Conversely, if you have test files with these extensions, Jest will now detect them by default (you may remove custom configuration that was previously needed to include them).
--testPathPattern
已重命名为 --testPathPatterns
¥--testPathPattern
was renamed to --testPathPatterns
如果你按路径过滤测试,请注意 CLI 标志已更改:--testPathPattern
标志现在是 --testPathPatterns
。你可以通过用空格分隔或重复标志来传递多个模式。例如:
¥If you filter tests by path, note that the CLI flag has changed: The --testPathPattern
flag is now --testPathPatterns
. You can pass multiple patterns by separating them with spaces or by repeating the flag. For example:
# Old (Jest 29)
jest --testPathPattern="unit/.*"
# New (Jest 30)
jest --testPathPatterns "unit/.*" "integration/.*"
在内部,Jest 将这些模式合并为 TestPathPatterns
对象。如果你之前以编程方式使用 testPathPattern
调用 Jest 的监视模式,现在必须改为构造一个 TestPathPatterns
实例。
¥Internally, Jest consolidates these patterns into a TestPathPatterns
object. If you were programmatically calling Jest’s watch mode with a testPathPattern
, you must now construct a TestPathPatterns
instance instead.
已移除 --init
命令
¥Removed --init
Command
交互式配置初始化命令 jest --init
已被移除。此弃用命令曾用于搭建 Jest 配置文件。如果你需要创建配置,可以运行:
¥The interactive config initialization command jest --init
has been removed. This deprecated command was used to scaffold a Jest configuration file. If you need to create a config, you can run:
npm init jest@latest
# Or for Yarn
yarn create jest
# Or for pnpm
pnpm create jest
其他 CLI 变更
¥Other CLI Changes
-
Jest 现在会验证需要参数的 CLI 标志,以确保提供了参数。例如,如果你使用
--maxWorkers
或--selectProjects
,则必须包含一个值(例如--maxWorkers=50%
)。以前,Jest 可能允许某些标志没有值(回退到默认值);现在如果缺少该值,将会抛出错误。确保任何传递 Jest 标志的脚本或 npm 命令都包含必要的参数。¥Jest now validates CLI flags that require arguments to ensure an argument is provided. For example, if you use
--maxWorkers
or--selectProjects
, you must include a value (e.g.--maxWorkers=50%
). Previously, Jest might have allowed certain flags without a value (falling back to defaults); now it will throw an error if the value is missing. Ensure any scripts or npm commands passing Jest flags include the necessary arguments. -
如果你使用
--filter
选项来过滤测试文件(这是一种高级用例,你需要提供过滤器实现的路径),则预期的接口已更改。过滤函数现在应该返回一个形状为{filtered: Array<string>}
的对象,与文档中记录的格式一致。在之前的版本中,可能接受不同的返回格式(例如,直接返回数组)。更新所有自定义测试过滤器函数,使其返回具有文档中所述的filtered
属性的对象。¥If you use the
--filter
option to filter test files (an advanced use-case where you provide a path to a filter implementation), the expected interface has changed. The filter function should now return an object of shape{filtered: Array<string>}
, matching the documented format. In prior versions, a different return format may have been accepted (e.g., returning an array directly). Update any custom test filter functions to return an object with afiltered
property as documented.
测试运行器行为变更
¥Test Runner Behavior Changes
测试中未处理的 Promise 拒绝
¥Unhandled Promise Rejections in Tests
Jest 包含一个修复程序,可以正确处理被拒绝但随后被捕获的 Promise,从而避免误报测试失败。在 Jest 29 中,异步处理(在测试 tick 之后)的 Promise 拒绝仍然可能导致测试错误失败。Jest 30 现在会等待一个额外的事件循环轮次,以确认 Promise 的拒绝状态仍未得到处理,否则测试将失败。
¥Jest includes a fix to properly handle promises that are rejected and later caught, to avoid false test failures. In Jest 29, a promise rejection that was handled asynchronously (after the test tick) could still cause the test to fail erroneously. Jest 30 now waits an extra event loop turn to confirm that a promise rejection remains unhandled before failing a test.
你应该会看到未处理的 Promise 拒绝的误报减少。之前由于异步处理拒绝而失败的测试现在应该可以通过了。但是,此更改可能会稍微减慢测试完成速度,尤其是在故意拒绝 Promise 的测试中。为了减轻性能影响,引入了新的配置标志 waitForUnhandledRejections
。如果确实需要,禁用此标志后可以恢复之前的行为(不等待)。大多数用户无需更改此设置 - 默认设置现在通过防止错误失败来提高正确性。
¥You should see fewer false positives for unhandled promise rejections. Tests that previously failed due to async handled rejections should now pass. However, this change can slightly slow down test completion, especially in tests that intentionally reject promises. To mitigate performance impact, a new configuration flag waitForUnhandledRejections
was introduced. This flag, when disabled, can restore the previous behavior (not waiting) if absolutely needed. Most users should not need to change this – the default now favors correctness by preventing false failures.
自定义测试序列器
¥Custom Test Sequencers
如果你有自定义测试序列器(继承自 Jest TestSequencer
的类),则需要将其更新至 Jest 30。Jest 现在会将额外的上下文传递给测试序列器。具体来说,TestSequencer
API 已扩展,以便将 globalConfig
和 contexts
暴露给你的序列器。
¥If you have a custom test sequencer (a class inheriting from Jest’s TestSequencer
), you’ll need to update it for Jest 30. Jest now passes additional context to the test sequencer. Specifically, the TestSequencer
API was extended to expose the globalConfig
and contexts
to your sequencer.
运行时必需的 globalConfig
¥Required globalConfig
in Runtime
对于使用 Jest 编程式 API 的用户:构造 Runtime
现在需要一个 globalConfig
参数。如果你使用 jest.runCLI
或类似的辅助函数,请确保根据更新的 API 传递所有必需的选项。(典型的 jest
CLI 或 npm test
使用不受此更改影响。)
¥For those using Jest’s programmatic APIs: constructing a Runtime
now requires a globalConfig
parameter. If you use jest.runCLI
or similar helpers, make sure you pass all required options as per the updated API. (The typical jest
CLI or npm test
usage is unaffected by this change.)
快照和输出变更
¥Snapshots and Output Changes
更新损坏的文档链接
¥Update broken documentation link
已弃用的 goo.gl URL 已从快照测试中移除。此更改会更新现有快照,将所有 goo.gl 链接替换为完整的、未缩短的 URL。
¥Deprecated goo.gl URL is removed from snapshot tests. This change updates existing snapshots to replace any goo.gl links with full, unshortened URLs.
快照中的错误原因
¥Error Causes in Snapshots
快照中的错误序列化已更改。Jest 30 的快照序列化器现在将在打印错误时包含 Error
的 cause
属性(如果存在)。
¥Error serialization in snapshots has changed. Jest 30’s snapshot serializer will now include an Error
’s cause
property (if present) when printing errors.
React 空字符串渲染
¥React Empty String Rendering
React 特有的快照序列化器不再在输出中渲染空字符串子元素 (""
)。在 Jest 29 中,React 元素中的空字符串子元素在快照输出中可能显示为 ""
;在 Jest 30 中,它将被省略(视为无内容)。
¥The React-specific snapshot serializer no longer renders empty string children (""
) in the output. In Jest 29, an empty string child in a React element might appear as ""
in the snapshot output; in Jest 30 it will be omitted (treated as no content).
pretty-format
中对象打印改进
¥Improved Object Printing in pretty-format
ArrayBuffer
和 DataView
现在以人类可读的方式打印,而不是作为带有内部字段的对象。
¥ArrayBuffer
and DataView
are now printed in a human-readable way instead of as objects with internal fields.
Jest Mock API 变更
¥Jest Mock API Changes
jest.genMockFromModule
已移除
¥jest.genMockFromModule
Removed
旧版函数 jest.genMockFromModule(moduleName)
已被移除。它之前已被弃用,取而代之的是 jest.createMockFromModule(moduleName)
。如果你仍在使用 genMockFromModule
,请切换到 createMockFromModule
- 行为相同。例如:
¥The legacy function jest.genMockFromModule(moduleName)
has been removed. It was previously deprecated in favor of jest.createMockFromModule(moduleName)
. If you still use genMockFromModule
, switch to createMockFromModule
– the behavior is the same. For example:
旧代码 (Jest 29):
¥Old code (Jest 29):
const mockFs = jest.genMockFromModule('fs');
新代码 (Jest 30):
¥New code (Jest 30):
const mockFs = jest.createMockFromModule('fs');
已移除模拟函数类型
¥Removed Mock Function Types
类型的更改仅在显式导入 Jest API 时适用:
¥The type changes are only applicable if you explicitly import Jest APIs:
import {expect, jest, test} from '@jest/globals';
一些与模拟函数相关的 TypeScript 类型已从公共 API 中移除。
¥Some TypeScript types related to mock functions have been removed from the public API.
-
MockFunctionMetadata
-
MockFunctionMetadataType
-
SpyInstance
如果你之前使用 jest.SpyInstance
(例如,注释 jest.spyOn
的返回值),则应更新为使用 jest.Spied
。
¥If you were using jest.SpyInstance
(for instance, to annotate the return of jest.spyOn
), you should update to using jest.Spied
.
模块和运行时变更
¥Module & Runtime Changes
ESM 模块支持和内部重构
¥ESM Module Support and Internal Restructuring
Jest 对其软件包的打包和导出方式进行了重大的底层更改:
¥Jest has introduced significant under-the-hood changes to how its packages are bundled and exported:
-
Jest 的所有内部模块现在都打包到单个文件中,以便更快地启动。这意味着安装 Jest 时,它加载的文件数量将大大减少(从而提高性能)。但是,副作用是任何非官方的深度导入 Jest 包的操作都可能会中断。例如,如果你之前执行过类似
require('jest-runner/build/testWorker')
的操作(它不是公共 API),则此路径将不再存在。解决方案:仅使用 Jest 的公共 API 或已记录的接口。如果你依赖的某个内部模块你认为它应该是公共 API 的一部分,请提交 Pull 请求以公开它。¥All of Jest’s internal modules are now bundled into single files for faster startup. This means when you install Jest, the number of files it loads is greatly reduced (improving performance). However, a side effect is that any unofficial deep imports into Jest’s packages will likely break. For example, if you previously did something like
require('jest-runner/build/testWorker')
(which is not a public API), this path will no longer exist. Solution: Use Jest’s public APIs or documented interfaces only. If you are relying on an internal module that you think should be part of the public API, please open a Pull Request to expose it. -
Jest 的软件包现在提供 ESM 封装器。这是正在进行的工作的一部分,旨在允许在 ESM 上下文中运行 Jest。所有官方 Jest 包都可以通过
package.json
"exports"
字段正确导出自身。对于大多数用户来说,这没有直接影响 - 你可以继续以相同的方式使用 Jest。但是,如果你维护一个导入 Jest 模块的工具或插件,请确保使用包名称作为导入(这将通过 Node 的模块解析进行解析)。¥Jest’s packages now provide ESM wrappers. This is part of ongoing work to allow running Jest in an ESM context. All official Jest packages export themselves properly via the
package.json
"exports"
field. For most users, this has no direct impact – you continue to use Jest the same way. But if you maintain a tool or plugin that imports Jest’s modules, ensure you use the package names as imports (which will resolve via Node’s module resolution).
这些更改对于探究 Jest 内部机制的任何人来说都具有破坏性,但对于 Jest CLI 和配置的典型用法而言并非如此。升级后,请正常运行测试 - 如果你遇到与 Jest 自身模块相关的模块解析错误,则很可能是由于导入不受支持,需要删除或更新。
¥These changes are considered breaking for anyone poking at Jest’s internals, but not for typical usage of the Jest CLI and config. After upgrading, run your tests normally – if you get module resolution errors related to Jest’s own modules, it’s likely due to an unsupported import that needs to be removed or updated.
通配符模式匹配变更
¥Glob Pattern Matching Changes
Jest 对文件模式匹配 (glob
) 的依赖已升级到 v10。Glob v10 在模式语法和行为上可能略有不同。
¥Jest’s dependency for file pattern matching (glob
) has been upgraded to v10. Glob v10 may have slight differences in pattern syntax and behavior.
一个值得注意的变化是,glob@10
对括号扩展和扩展全局变量的处理略有不同,并且对某些模式更加严格。如果你有自定义 testMatch
模式、moduleNameMapper
模式或其他基于 glob 的配置,它们在大多数情况下应该可以继续工作。请注意,如果模式与文件匹配效果不如以前,则可能需要根据新的 glob 引擎进行调整。
¥One notable change is that glob@10
treats brace expansions and extglobs a bit differently and is stricter about some patterns. If you have custom testMatch
patterns, moduleNameMapper
patterns, or other glob-based config, they should continue to work in most cases. Just be aware that if a pattern isn’t matching files as it used to, you might need to adjust it for the new glob engine.
结论
¥Conclusion
升级到 Jest 30 之前,请先确保你的环境符合新的 Node.js 和 TypeScript 要求。更新你的 Jest 配置文件和 CLI 用法,以适应重命名和删除的选项(尤其是 testPathPatterns
和 --init
的删除)。运行测试套件并解决任何故障:
¥Upgrade to Jest 30 by first ensuring your environment meets the new Node.js and TypeScript requirements. Update your Jest configuration file and CLI usage for the renamed and removed options (notably testPathPatterns
and the removal of --init
). Run your test suite and address any failures:
-
使用已删除的匹配器别名的测试,请将其替换为官方匹配器名称,以修复它们。
¥Fix tests using removed matcher aliases by replacing them with the official matcher names.
-
更新所有因格式更改(错误原因、空字符串等)而失败的快照。
¥Update any snapshots that fail due to the formatting changes (error causes, empty strings, etc.).
-
注意 TypeScript 编译器错误 - 它们会指导你更新已弃用的 API(例如
genMockFromModule
或已移除的类型),并调整类型更严格的测试。¥Pay attention to TypeScript compiler errors – they will guide you to update deprecated API usage (like
genMockFromModule
or removed types) and adjust tests where types are now stricter.
祝你测试愉快!
¥Happy testing!