跳至主内容

Jest 27:Jest 的新默认设置,2021 年版 ⏩

· 8 分钟阅读
Tim Seckinger
Tim Seckinger
非官方测试版翻译

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

在约一年前的 Jest 26 博客文章中,我们宣布经过两个破坏性变更较少的主要版本后,Jest 27 将调整部分开关设置,为新建项目或能平滑迁移的项目提供更优的默认配置。这让我们有机会从 Jest 28 的默认分发包中移除某些依赖,将其改为独立安装的可插拔模块。采用新默认配置的用户可获得更小的安装体积,而需要这些包的用户仍可单独安装它们。

自具有里程碑意义的版本 15 引入 Jest 的新默认设置以来,Jest 27 首次对默认配置进行了重大调整,旨在让 Jest 保持快速、轻量且面向未来的特性。本文将详细解释这些默认配置变更及其他重要破坏性变更,但首先让我们聚焦激动人心的新功能!

功能更新

首先,您可能熟悉的用于审查和更新失败快照的交互模式,现在也可用于单步调试失败的测试。此功能的实现归功于首次贡献者 @NullDivision 提交的 PR

交互式失败测试运行

谈到快照测试,近年来我们推出的最令人兴奋的功能之一当属内联快照——该功能在约三年前随 Jest 23 的次要版本落地。但当时存在限制:项目必须使用 Prettier 格式化代码,因为 Jest 需依赖它确保写入快照的文件保持正确格式。
因此在过去几年里,我们一直有个待合并的 PR,旨在消除此限制以实现无需 Prettier 的内联快照。该 PR 积累了远超百条的评论(这还不包括从中拆分并先行合并的 PR),甚至在初次提交后更换过负责人——另一位首次贡献者 @mmkal 在幽默的暂定标题 "更丑的内联快照" 下继续推进。随着 Prettier 近年来的飞速普及,这项改进的需求或许不如 2018 年迫切,但我们深知:当您接手未使用 Prettier 的项目时,突然无法使用内联快照的挫败感。永不再见!

这个功能耗时如此之久的首要原因,竟是我们构建管道频繁出现内存溢出。我们发现:为每个测试文件加载的解析、快照插入和打印依赖项,确实会带来显著的时间和内存开销。
通过若干优化技巧,我们将每个测试文件的初始化速度提高了约 70%(相较于 Jest 26)。请注意:您的项目几乎不可能感受到如此显著的性能提升——只有当您拥有大量运行极快的测试文件时,这种优化效果才最明显,而使用 JSDOM 环境的开销会完全掩盖此类改进。

另外,原生 ESM 支持正在推进中,但围绕模拟等功能的重大复杂性仍需攻克。我们仍将 ESM 迁移视为庞大的生态工程:Node 和众多关键工具/包必须相互配合才能提供整体卓越体验。
Jest 模块的 ESM 支持进展更快——自定义运行器、报告器、watch 插件等模块现已支持作为 ES 模块加载。

我们还合并了一个 PR,使其能够处理符号链接到测试目录中的测试文件——这是 Bazel 用户期待已久的功能。

另一个 PR 实现了transform 的异步支持,这是有效支持通过 esbuildSnowpackVite 等工具进行转译的必要条件。

更改默认设置

截至目前,当您使用 Jest 的默认配置时,您可能并未意识到自己正在运行多年前从测试运行器 Jasmine 2.0 分支出来的代码,这些代码提供了 describeitbeforeEach 等测试框架函数。2017 年,Aaron Abramov 初步编写了名为 jest-circus 的 Jasmine 替代方案,旨在改善错误信息、可维护性和可扩展性。
经过在 Facebook 和 Jest 自身多年的大规模应用,以及近期在 create-react-app 中的采用,我们现在确信 jest-circusjest-jasmine2 高度兼容,可在大多数环境中无缝工作。虽然执行顺序和严格性可能存在细微差异,但我们预计除了依赖 jasmine.getEnv() 等 Jasmine 特定 API 的代码外,不会有重大迁移问题。如果您重度依赖此类 API,可以通过配置 "testRunner": "jest-jasmine2" 切换回基于 Jasmine 的测试运行器。

JSDOM 环境中运行测试会产生显著的性能开销。由于这是 Jest 至今的默认行为(除非另有配置),编写 Node 应用的用户可能并未意识到自己被赋予了一个昂贵且不需要的 DOM 环境。
因此,我们将默认测试环境"jsdom" 更改为 "node"。如果您因此变更受到影响(例如访问 document 时出错),可以通过配置 "testEnvironment": "jsdom" 或使用按文件的环境配置来解决。
对于混合项目(部分测试需要 DOM 环境而其他不需要),我们建议默认使用快速的 "node" 环境,并通过文档块明确声明需要 DOM 的测试。
在下一个主要版本中,我们计划将 jest-jasmine2jest-environment-jsdom 移出 Jest 的默认依赖树,要求单独安装这些模块,使更多用户能享受到更精简的安装体积。

我们变更的另一项默认设置涉及 Fake Timers(又称 Timer Mocks)。Jest 26 中引入了可选的 "modern" 版 Fake Timers 实现(通过相同 API 透明访问),但提供了更全面的模拟功能(如 DatequeueMicrotask)。
现在这个现代版实现将成为默认设置。如果您不幸因细微的实现差异而难以迁移,可通过 jest.useFakeTimers("legacy") 恢复旧版实现,或者通过配置 "timers": "legacy" 全局启用旧版。

伴随破坏性变更的功能

我们还引入了一些小型破坏性变更,通过禁止容易意外发生的操作来帮助您避免错误:

  • 禁止多次调用同一个 done 测试回调函数,

  • 调用 done 和返回 Promise 不可同时使用

  • describe 代码块不得返回任何值

此外,我们强化了部分 TypeScript 类型

以下配置选项中使用的模块现在会像其他代码一样被转换,如果你依赖它们以原始形式加载,这可能会造成破坏性变更:

  • testEnvironment

  • runner

  • testRunner

  • snapshotResolver

其他破坏性变更

我们移除了以下长期弃用的函数:

  • jest.addMatchers(请改用 expect.extend

  • jest.resetModuleRegistry(请改用 jest.resetModules

  • jest.runTimersToTime(请改用 jest.advanceTimersByTime

许多 Jest 包已迁移为使用 ESM 风格的导出(尽管仍以 CommonJS 形式发布),因此如果你直接使用如 pretty-format 等包,可能需要将导入方式调整为 default 导入。

我们放弃了对 Node 13 的支持——但 Jest 始终支持所有当前和 LTS 版本的 Node,而 Jest 27 将继续支持 Node 10(该版本近期才结束维护)。

完整的变更日志和破坏性变更列表可在此查看

最后,我们要感谢社区在 2020 年 JavaScript 现状调查中再次给予 Jest 高达 96% 的满意度评分!请大家保重,期待在未来的版本中继续为你带来愉快的 Jest 使用体验!🃏