跳至主内容

Jest 28:轻装上阵,兼容性更佳 🫶

· 9 分钟阅读
Simen Bekkhus
Simen Bekkhus
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

Jest 28 终于来了!它带来了许多开发者期待已久的功能,包括支持在多台机器上分片(sharding)运行测试、package exports支持,以及自定义模拟计时器(fake timers)行为的能力。这些只是部分亮点功能,我们将在本文中详细介绍更多更新。

此外,正如我们在去年的Jest 27博客文章中所预告的,我们已从默认安装中移除了不再默认使用的包。这使得安装体积减少了约三分之一。

破坏性变更​

破坏性变更列表较长(完整内容可查看更新日志),为方便迁移,我们还编写了迁移指南。希望这能让您的升级过程尽可能顺畅!

主要可能影响迁移的破坏性变更包括:停止支持 Node 10 和 15(但_不包括_ Node 12,它将在几天后结束支持期)以及部分配置选项的重命名。

请注意,被移除的两个模块(jest-environment-jsdom 和 jest-jasmine2)仍以相同方式积极维护和测试,因此唯一的破坏性变更就是您需要显式安装它们。

该指南应该能让迁移变得轻松,但请注意:如果您直接使用了 Jest 的组成包(如 jest-worker 或 pretty-format),而不仅仅是运行 jest 命令,那么您需要查看更新日志以了解所有破坏性变更。

新特性​

现在让我们聊聊 Jest 28 更令人兴奋的新功能吧!这次更新带来了不少新特性,请系好安全带。

测试运行分片​

Jest 现在新增了 --shard CLI 选项,由 Mario Nebl 贡献。它允许您在多台机器上分片运行测试,这是 Jest 历史最悠久的功能需求之一。

在 CI 环境中,Jest 自身的测试套件在 Ubuntu 上从约 10 分钟缩短到 3 分钟,在 Windows 上从 20 分钟缩短到 7 分钟。

package.json exports​

Jest 27.3 已提供对 exports 的基础支持,但仅支持主入口点(.),且仅在 package.json 中不存在 main 字段时生效。在 Jest 28 中,我们终于提供了完整支持!

相关改进:在 Jest 27 中,我们仅提供 require 或 import 条件。而在 Jest 28 中,jest-environment-node 现在会自动提供 node 和 node-addons 条件,而 jest-environment-jsdom 则会提供 browser 条件。

这一直是 Jest 最突出的兼容性问题,希望此次更新能彻底解决。

模拟计时器​

Jest 26 引入了"现代"模拟计时器的概念(底层使用 @sinonjs/fake-timers),Jest 27 将其设为默认。在 Jest 28 中,我们通过配置和运行时 API 开放了更多底层实现。特别感谢贡献此功能的 Tom Mrazauskas!

这样您就无需模拟 process.nextTick,从而提升与伪造 Promise 的兼容性;或者启用 advanceTimers 功能来自动推进计时器。

详情请参阅 fakeTimers 配置文档。

GitHub Actions 报告器​

Jest 现已内置适用于 GitHub Actions 的报告器,该功能会通过注解在代码行内直接显示测试错误。

GitHub Actions 测试错误截图

您只需在 reporters 配置选项 中传入 github-actions 即可启用此报告器。

衷心感谢 Bernie Reiter 及其他贡献者长期以来的坚持,最终促成此功能落地。

内联 testEnvironmentOptions​

现在您可以直接在文件中内联传递 testEnvironmentOptions,这类似于设置测试环境的方式。当您需要在单个文件中修改 URL 等配置时特别实用。

/**
* @jest-environment jsdom
* @jest-environment-options {"url": "https://jestjs.io/"}
*/

test('use jsdom and set the URL in this test file', () => {
expect(window.location.href).toBe('https://jestjs.io/');
});

完整 Node.js 全局对象支持​

如果您在 Node v18 中使用新的 fetch 实现,可能已注意到此函数在 Jest 中不可用。过去我们必须手动将所有全局对象复制到测试环境,这曾是长期存在的问题。Jest 28 通过检查 Jest 自身运行的全局环境,并自动补全测试环境中缺失的全局对象,彻底解决了该问题。

ECMAScript 模块支持​

自 Jest 27 发布以来,我们对原生 ESM 的支持未有重大变化。目前仍受限于 Node 的稳定化进程,期待该问题能早日取得进展!

不过我们仍在 Jest 28 中实现了若干新功能。

data: URL 支持​

Tommaso Bossi 贡献了对 data URL 的支持,这意味着您现在可以直接内联定义 JavaScript 代码并执行,无需使用 eval。

import.meta.jest​

虽然您始终可以通过 import {jest} from '@jest/globals' 访问 jest,但我们收到反馈称这种方式不如 CJS 中(看似全局实则非全局的)jest 变量便捷。为此 Jest 28 提供了 import.meta.jest 以实现更便捷的访问。

其他改进​

以上是我个人重点介绍的功能亮点,但实际上我们还有更多改进值得关注:

异步解析器​

Ian VanSchooten 贡献了对异步解析器的支持,这将使 Vite 等工具能更好地与 Jest 集成。

异步设置文件​

现在当您使用 setupFiles 时,可以导出一个 async function 来执行异步操作,Jest 将在加载任何测试前调用并等待该函数执行完成。

请注意此功能仅适用于 CJS 模块。对于 ESM 模块,我们建议改用顶层 await 方案。

使用 globalThis​

Jest 内部一直使用 global 来指代全局环境。但由于这仅在 Node 环境中存在(浏览器环境对应 window),导致在其他环境中使用 Jest 模块时出现兼容性问题。

Jest 28 改用 globalThis 实现,该特性在所有环境中均可使用。

JSDOM 19​

如前所述,虽然 Jest 默认安装包不再包含 jest-environment-jsdom,但该模块仍持续维护。作为更新的一部分,Jest 28 已将 jsdom@16 升级至 jsdom@19。

TypeScript​

如果您在测试或编写插件(如自定义运行器)时使用 TypeScript,Jest 28 对类型系统进行了全面增强。以下是 Jest 28 类型改进的非详尽列表:

expect​

当使用 expect 自有类型(直接使用或通过 import {expect} from '@jest/globals' 导入)时,现在终于可以添加自定义匹配器了。具体实现方法请参考我们的示例。

自定义插件​

如果您编写自定义运行器、测试报告器、解析器等插件,我们现在导出了更多类型帮助您准确定义。这是一个持续改进的领域,如果您是 Jest 可插拔组件的作者且发现类型支持不足,请提交 issue 反馈!

jest-runner-tsd​

jest-runner-tsd 是用于运行类型测试的自定义运行器。Jest 自身就使用它来测试类型系统,我们也希望其他开发者能从中受益!顾名思义,它基于 tsd 实现,底层实际使用的是其分支 tsd-lite。



以上所有改进和修复均由 Tom Mrazauskas 贡献。衷心感谢 Tom!👏

最后,TypeScript 最低支持版本现已提升至 4.3。

jest-light-runner​

本文最后要重点介绍的是由 Nicolò Ribaudo 开发的超酷新运行器 jest-light-runner。它在保留 Jest 标志性开发者体验的同时,通过精简 Node 抽象层大幅提升速度。Babel 测试套件迁移后速度提升近一倍。虽然存在使用限制,但该运行器能让测试小型 Node 模块的开发者更轻松地选择 Jest。感谢 Nicolò!

未来规划​

虽然 Jest 28 距上个主版本发布近一年,但 Jest 29 将在数月内推出。当前计划的核心变更(除弃用 Node 版本外)是将 snapshotFormat 默认值设为 {escapeString: false, printBasicPrototype: false}。这将使快照更易读且更便于直接复制使用。

当然您可以选择覆盖该配置,如果不想等待,现在就可以启用这些选项!

致谢​

Jest 28 汇集了 60 多位贡献者的智慧成果,其中超过三分之二是首次贡献者。衷心感谢所有新老贡献者!没有你们,这个项目绝不会如此出色!特别感谢 汤姆·姆拉佐斯卡斯 和 冯宇,他们从代码编写、问题分类到调试优化全程参与,正是这些贡献铸就了今天的 Jest 28。感激不尽!🙏

感谢阅读,祝您测试愉快!🃏