跳至主内容

Jest 26:滴答作响

· 7 分钟阅读
非官方测试版翻译

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

五年前我们开始重构 Jest 时,目标是打造一个开箱即用的零配置测试运行器:对初学者友好,几乎适用于所有测试场景,并能扩展至大型项目。Jest 15 是关键版本之一,它整合了所有功能,提供了良好的默认配置,让用户无需任何设置即可运行 Jest。但这种做法有个显著缺点:Jest 会安装大量你可能不需要的依赖项到项目中。

现在,我们开始解决这一问题,在保持 Jest 友好性和可扩展性的同时努力减小其安装体积。我们在 Jest 26 中进行了以下重大变更

  • [expect, jest-mock, pretty-format] 移除了 ES5 构建文件,现在最低支持版本为 ES2015(Node 8),这些文件仅用于浏览器构建 (#9945)

    迁移指南:此变更后,打包受影响包的责任将转移给用户而非由 Jest 默认提供,因为用户最了解目标环境。如需恢复此功能,我们考虑将其作为独立包发布。欢迎提交 PR!

  • [jest-config, jest-resolve] 移除了对 browser 字段的支持 (#9943)

    迁移指南:安装 browser-resolve 模块并使用以下配置:

    {
    "jest": {
    "resolver": "<rootDir>/resolver.js"
    }
    }
    // resolver.js
    const browserResolve = require('browser-resolve');

    module.exports = browserResolve.sync;
  • TypeScript 类型定义现在要求最低 TypeScript 版本为 v3.8 (#9823)

经过以上优化,Jest 26 比 Jest 25.5.4 减小了 4 MiB(53 → 49 MiB)。请注意,像 Babel 这样的依赖项很可能已存在于您的项目中。Jest 自身体积减小了 1.2 MiB(4.3 → 3.1 MiB)。

这虽是个良好开端,但还不足以让 Jest 显著瘦身。我们计划逐步将 Jest 及其依赖树体积减少高达 70%。大多数精简默认配置的变更将是小幅的重大变更,我们希望能尽可能带动社区共同推进。因此我们将采用“滴答作响”发布流程,在 Jest 27 和 Jest 28 中实施以下变更:

  • Jest 27 将默认提供新测试运行器 "jest-circus" 和 Node.js 环境。jest-jasmine2jest-environment-jsdom 仍会捆绑提供,用户只需在配置中各改一行即可继续使用。

  • Jest 28 将从默认分发包中移除 jest-jasmine2jest-environment-jsdom。这些包仍将作为 Jest 项目的一部分积极维护并单独发布。用户需要安装这些包才能使用。

升级到这些主版本时,Jest 将引导您完成必要的更改。如果您想提前准备,现在就想迁移到新的默认配置,且项目不需要 DOM 环境,可升级至 Jest 26 并添加以下配置选项:

{
"jest": {
"testEnvironment": "node",
"testRunner": "jest-circus/runner"
}
}

Jest 将继续默认启用 babel-jest。它除了能将现代 JavaScript 语法编译成当前 Node.js 和浏览器兼容的代码外,目前还为 Jest 的几项关键功能提供支持:包括代码覆盖率统计和对 ES 模块的模拟。Jest 当前提供对 V8 coverage 的实验性支持以及对 ES 模块的原生支持(下文将详述!)。根据规范要求,若不先转换代码就无法模拟静态 ES 模块,因此我们将鼓励采用无需当前 Babel 转换的替代方案。一旦 V8 coverage 和原生 ESM 在 Jest 中稳定实现,我们也将移除默认的 babel-jest 依赖,但会继续维护该包。

全新的模拟计时器

在 Jest 26 中,我们推出了基于 @sinonjs/fake-timers 重构的模拟计时器实现。多年来我们一直希望完成这项改进,很高兴它终于演进到能完全支持 Jest 现有所有模拟计时器用例的阶段。

新实现额外支持模拟 DatequeueMicrotask 等功能(详见 此 README)。它通过 jest.runAllTimers() 等现有计时器 API 透明工作——请查阅 官网文档

我们确信该实现已具备生产环境可用性,但考虑到新旧版本在细节实现上的差异可能影响现有测试,在 Jest 26 中此功能将保持_可选启用_状态。可通过调用 jest.useFakeTimers('modern') 激活,若已在配置中全局启用模拟计时器,则可将 timers 选项设为 modern

在 Jest 27 中,我们将把默认实现切换为新的 "modern" 版本,但仍会通过 jest.useFakeTimers('legacy') 继续维护旧版实现。若您不确定能否在 Jest 27 发布前完成所有测试迁移,建议现在就在测试中添加此调用以保留原有行为。

衷心感谢 Carl-Erik KopsengBenjamin Gruenbaum@sinonjs/fake-timers 维护团队的鼎力协作与耐心支持!激动人心!

使用 Jest 的新方式 - @jest/globals

Jest 长期依赖 Jasmine 测试框架推广的全局变量如 describeittestexpect。尽管该模式被广泛采用,许多开发者更倾向于导入测试函数。为此我们新增了 @jest/globals 包支持按需导入:import {expect, jest, test} from '@jest/globals';

注意事项:

  • 当前全局变量仍存在于环境中,未来将提供禁用全局变量的模式。同时,由于 jest 目前仍是全局变量,请勿使用 const jest = require('@jest/globals') 以避免声明冲突

  • 当前无法在使用此类导入时为 TypeScript 定义添加自定义匹配器

  • 虽然这支持无全局变量的测试运行,但目前仍依赖 Jest 测试运行器

原生 ESM 支持

正如我们在 Jest 25 的博客文章 中提到的,我们一直在致力于为 ECMAScript 模块提供原生支持。该功能目前尚未稳定,但已准备好接受测试。我们非常期待收到您的反馈和错误报告!要了解当前进展,您可以查看 此 issue,或浏览所有带有 ES Modules 标签的问题。

Jest 26 中的其他破坏性变更

  • 放弃对 Node 8 的支持 (#9423)

  • [jest-environment-jsdom]jsdom 升级至 v16 版本 (#9606)

  • [jest-runtime] 移除长期弃用的 require.requireActualrequire.requireMock 方法 (#9854)

  • [jest-haste-map] 移除 providesModuleNodeModules (#8535)

  • [jest-circus] 若测试接受 done 回调函数并包含返回值,则测试将失败 (#9129)

  • [jest-circus] 当测试/钩子被异步定义时抛出明确错误 (#8096)

共克时艰

当前我们都经历着前所未有的不确定时期。如果您正面临经济困难,我们希望利用 Jest 的 Open Collective 基金 帮助新老贡献者。我们在部分 issue 上设置了悬赏,并愿意为任何现有开放 issue 提供悬赏——您可以在 issue 中提出悬赏请求,或通过 Twitter 私信联系 @cpojer

请务必保重。