跳至主内容

Jest 15.0:全新默认配置

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

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

过去一年中,我们致力于让Jest更快配置更简单新增海量功能并构建了快照测试。然而有两个领域我们投入甚少:CLI输出和用户体验。通过Jest 15,我们彻底改造了框架,使其对新手和经验丰富的用户都更易用。我们欣喜地看到对Jest的投资正在获得回报:能够快速迭代框架,为Facebook和开源社区提供光速般的改进。Jest的目标是开箱即用,并尽可能减少配置需求。我们最近在create-react-app的讨论中阐述了这一设计理念。

最重要的变更是全新默认配置。现有Jest用户很可能需要更新配置以适应Jest 15。多数情况下这将简化您的设置,升级过程中Jest会提供实用的错误提示。所有新默认项均可按需禁用,但我们认为这些功能在特定场景中至关重要,并将长期在Facebook内部持续使用和支持。API文档也已全面重写以体现这些变更。React的这个PR展示了现有项目需要进行的部分调整。

全新的CLI错误提示与摘要

作为逐步移除Jest中Jasmine工作的一部分,我们基本完成了所有Jasmine匹配器的替换。团队投入大量时间优化每个匹配器的错误提示,确保在测试失败时(Jest最应发挥价值的时刻)为用户提供最清晰的信号。除显示预期值与实际值外,toBetoEqual匹配器现在会输出差异对比以帮助定位问题。新增了更多色彩标识,堆栈轨迹中的相关文件也获得更醒目的高亮。

浅色终端效果对比:failure1 深色终端同样出色:failure2

全新的watch命令

我们彻底重写了jest --watch使其更具交互性。现在可通过按ao在"运行全部测试"与"仅运行变更文件相关测试"间切换。按p将弹出提示框供您指定测试模式以聚焦特定文件集。按u可更新快照测试。

watch

jest-react-native改进

新增了ListViewTextInputActivityIndicatorScrollView等模块的模拟实现。现有模拟器已更新为使用真实实现,升级至Jest 15后可能需要更新既有快照。jest-react-native新增了mockComponent函数用于模拟原生组件:

jest.mock('MyNativeComponent', () => {
const jestReactNative = require('jest-react-native');
return jestReactNative.mockComponent('MyNativeComponent');
});

同时在模拟图片、fetch模块及其他原生API方面进行了多项改进。

缓冲式控制台消息

Jest通过多工作进程并行执行测试以最大化性能。此前控制台消息会从工作进程即时转发至主进程并立即打印。当并行运行多个测试时,往往难以定位日志函数的具体调用位置。在Jest 15中,所有控制台消息会被缓冲,并与对应测试结果同步输出。同时打印日志调用的文件路径和行号,便于快速定位代码。

新旧版本输出对比:console

禁用自动模拟

Jest 现已默认禁用自动模拟功能。这无疑是新用户最容易混淆的特性,对于小型项目而言,自动模拟在很多场景下并不合理。Facebook 最初引入自动模拟时,在大型既有代码库的单元测试落地阶段(特别是测试覆盖率较低时)效果显著。但随着时间的推移,开发者花费在解决模拟/非模拟模块冲突上的精力,往往超过了正常编写测试所需的时间。我们还注意到,库作者经常需要手动解除大量基础模块的模拟状态。即使在 Jest 自身项目中,我们也发现绝大多数测试都手动禁用了自动模拟。我们依然认为显式的自动模拟极具价值,本次变更只是将隐式模拟转变为通过显式调用 jest.mock(moduleName) 实现的显式模拟。

若您仍希望默认启用自动模拟功能,请在配置中启用 automock 选项,或在测试文件/启动文件中手动调用 jest.enableAutomock()

测试文件匹配模式

并非所有用户都采用 __tests__ 目录存储测试文件。Jest 15 新增支持识别以 .spec.js.test.js 结尾的文件,这两种是社区广泛采用的命名规范。同时移除了 testDirectoryNametestFileExtensions 配置项,当检测到用户使用旧配置时,会提示改用 testRegex 选项。

模块注册表持久化

此前 Jest 默认在每次测试前隐式重置所有模块,因此建议在 beforeEach 或测试内部引入模块。这种机制在模块含有不应跨测试共享的局部状态时非常有用。然而两大趋势改变了这一现状:ES 模块的顶层 import 语法日益普及,以及无状态函数式模块的开发理念复兴。

这导致了许多兼容性问题。我们还发现 Facebook 内部项目甚至不再使用这种隐式重置,而是依赖显式调用 jest.resetModules(),让工程师自主掌控状态清除时机。

示例如下:

const React1 = require('react');
jest.resetModules();
const React2 = require('react');

React1 !== React2; // These two are separate copies of React.

调用 resetModules 会清除 require 缓存。第二次 require 同一个模块会导致该模块及其所有依赖重新实例化。这个特性在处理具有副作用的模块时特别有用,例如 jest-haste-map

我们认为将控制权交给用户更为合理,因此禁用了隐式重置。开发者仍可通过代码调用 jest.resetModules() 重置模块,或在配置中启用 resetModules 选项恢复原有行为。

真实计时器 vs 模拟计时器

此前 Jest 默认模拟所有计时器函数(如 setTimeoutprocess.nextTick),并通过 jest.runAllTimers() API 以编程方式推进计时器。当代码设置了测试中无需等待的长超时时限时,该机制非常实用。

但我们发现多数场景的使用需求相对独立。同时异步编程在我们的测试运行器中已大幅简化,因此 Jest 现在默认使用真实计时器。

您仍可通过配置 "timers": "fake",或调用全局开关 jest.useRealTimers()jest.useFakeTimers() 来覆盖此行为。

setupEnvScriptFile vs setupFiles

setupEnvScriptFile 配置项已被弃用多时。Jest 15 彻底移除了该选项,并用 setupFiles 替代。新选项接收文件路径数组,测试文件执行前会按序加载这些文件。

重构的代码覆盖率支持

Jest 中的代码覆盖率功能可通过 jest --coverage 命令使用,无需额外安装包或配置。代码覆盖率支持已完全重构,新增了 collectCoverageFrom 选项用于收集整个项目的代码覆盖率信息(包括未测试文件)。请注意该选项使用 glob 模式匹配,未来我们计划进一步简化配置选项,提供比正则表达式更简洁的替代方案。具体示例可参考 Jest 的 package.json

其他改进

我们还实现了大量其他改进:

  • 优化了小型测试套件的执行性能

  • 当仅执行单个测试文件时,Jest 会自动启用详细模式

  • 新增 --env 选项用于覆盖预设的测试环境

  • moduleNameMapper 现在采用解析算法

  • Jest 现在支持包含特殊字符(如括号)的路径

  • 在 Node 环境中添加了 global.global 支持

  • 修复了当用户函数命名为 mockbabel-plugin-jest-hoist 误报错误的问题

  • 修复 testEnvironment 解析机制:优先匹配 jest-environment-{name} 而非 {name},避免使用 jsdom 测试环境时的模块冲突

  • 通过合并集成测试和单元测试优化了 Jest 自身测试基础设施,现可收集 Jest 自身的代码覆盖率

回顾在社区帮助下共同实现的这些改进,我们倍感欣喜,并期待在未来数月让 Jest 更臻完善。如遇预期外问题,请提交 issue,也欢迎向我们提交 pull request。

下一步计划:并发报告器(Concurrent Reporter)