Jest 16.0 发布解读:Turbocharged CLI、快照格式重构与新匹配器
【免费下载链接】jestDelightful JavaScript Testing.项目地址: https://gitcode.com/gh_mirrors/je/jest
本文基于 Jest 16.0 官方发布博客 整理而成。Jest 16 是 2016 年 10 月发布的重大版本,距离上一大版本仅一个月,它重构了命令行交互与快照子系统,并完成 Jasmine 断言向新匹配器的迁移。读完本文,你将掌握--testNamePattern、--findRelatedTests、--bail等 CLI 能力的使用场景,理解快照格式变更的原因,以及toBeInstanceOf、toContainEqual、test.concurrent等 API 的现代用法,并能在当前仓库源码中找到它们的实现印证。
版本背景:一次聚焦开发者反馈的迭代
Jest 16.0 发布于 2016 年 10 月,是继上一大版本之后一个月的快速迭代。这个版本最核心的信号有两点:CLI 体验大幅提速,以及快照格式迎来一次不兼容更新——升级 Jest 后,已存在的快照文件大概率需要重新生成。发布方在博客中明确表示,这类格式变更不会频繁发生,但为了长期可维护性,偶尔的格式改进是必要的。
值得注意的是,Jest 16 已经是当时真正的社区协作产物,项目贡献者超过 220 人。Jest 的目标始终是"提供多种编写高效测试的方式,而不牺牲性能与项目可维护性"。
升级的 CLI:更快给出有用信号
Jest 16 引入了全新的 reporter 界面:实时展示正在运行的测试、基于上一次测试运行估算的进度条与实时汇总信息,同时优化了 CLI 输出对不同配色方案的适配。最关键的体验改进是:如果上一次运行存在失败测试,本次会优先运行它们,让用户最快获得最有价值的失败信号。
新增 CLI 标志:--testNamePattern / -t
--testNamePattern=pattern(简写-t <pattern>)用于在命令行按测试名称过滤,效果类似在测试内使用it.only或fit,但无需修改测试代码:
# 只运行名称匹配 /integration/ 的测试 jest -t integration从当前仓库源码看,该参数在 packages/jest-cli/src/args.ts 中定义,其描述为"Run only tests with a name that matches the regex pattern",并注册了别名t。在运行时,packages/jest-circus/src/eventHandler.ts 会将其编译为大小写不敏感的正则:
state.testNamePattern = new RegExp(event.testNamePattern, 'i');这也印证了博客中"jest <pattern>现在大小写不敏感"的改进。此外,watch 模式下按t键会弹出交互式输入,由 packages/jest-core/src/plugins/TestNamePattern.ts 插件驱动,输入后通过updateConfigAndRun({mode: 'watch', testNamePattern: value})触发重跑。
watch 模式:可中断 + --bail 支持
Jest 16 之前,watch 模式下发起一次测试运行后必须等它跑完。现在,运行过程中随时按下 watch 模式的任一输入键(a、o、p、q或enter)即可中断当前运行并立即开启新一轮,配合"失败测试优先"策略,watch 模式的操作节奏大幅加快。
同时,--bail标志在 watch 模式下也生效。--bail的语义是"遇到第 n 个失败测试后立即退出测试套件",其参数定义见 packages/jest-cli/src/args.ts。在现代 watch 模式下,bail与testNamePattern一样通过 packages/jest-core/src/lib/updateGlobalConfig.ts 合并进全局配置:
if (typeof options.bail === 'boolean') { newConfig.bail = options.bail ? 1 : 0; } else if (options.bail !== undefined) { newConfig.bail = options.bail; }新增 --findRelatedTests:为 pre-commit 而生
--findRelatedTests <fileA> <fileB>用于运行与指定文件存在依赖关联的测试,非常适合作为pre-commit 钩子:只跑与本次改动文件相关的测试,把验证成本降到最低。
jest --findRelatedTests src/foo.js src/bar.js若未附带任何文件路径,Jest 会直接报错,错误信息与示例用法写在 packages/jest-cli/src/args.ts 的参数校验函数check中。其底层实现位于 packages/jest-core/src/SearchSource.ts:通过dependencyResolver.resolveInverse(allPaths, isTestFilePath, ...)做反向依赖解析——给定源码文件,反查出所有依赖它们的测试文件;配合--coverage时还会基于resolveInverseModuleMap反推出需要纳入覆盖率统计的源码范围。
其余 CLI 与工程化改进
jsx扩展自动识别:Jest 现在自动把.jsx后缀的文件视为候选测试文件与模块文件。从当前仓库的默认配置看,moduleFileExtensions已覆盖js、mjs、cjs、jsx、ts、tsx等主流扩展名。- 重复 manual mock 文件告警:当同一个模块存在多份手写 mock 时,Jest 会给出警告,避免"改了 A 处没改 B 处"的隐患。
- ES Modules mock 自动生成改进:针对 Babel 编译后的 ES 模块,自动生成的 mock 更符合预期。
jest.clearAllMocks:新增全局函数,用于在测试之间清理所有 mock 的调用记录、实例与返回结果。当前实现位于 packages/jest-mock/src/index.ts,通过重置内部的_mockState弱映射完成;对应 CLI 选项--clearMocks等价于在每个测试前调用jest.clearAllMocks()。moduleNameMapper解析改进:当使用moduleNameMapper做模块映射(例如将图片、样式映射到桩模块)时,模块解析逻辑得到优化。
Snapshot 更新:彻底重写的 jest-snapshot
Jest 的快照实现被完全重写。新版jest-snapshot包在架构上按模块拆分,便于被其他测试运行器集成(当时即推动了与 React Storybook 等工具的联动)。重写还带来一个行为修正:在包含跳过或失败测试的文件中,Jest 不再将其中的快照标记为 obsolete——避免误删那些尚未跑完验证流程的快照。
快照格式的三项变更
- 对象与数组打印尾随逗号:
{ a: 1, b: 2 }这类结构现在以{ a: 1, b: 2, }的形式输出,减少未来字段增删导致的格式级 diff 噪音。 - 移除函数名:快照中不再输出函数名。原因是函数名在不同 Node 版本、代码覆盖率插桩场景下都不稳定,且对用户而言"函数名变了"并不是有意义的信号。
- 文件内自然排序:同一快照文件内的快照条目按自然排序顺序组织,保证输出顺序的确定性。
升级时的 diff 长什么样
由于上述格式变化,从旧版本升级到 Jest 16 时,--updateSnapshot(-u)前看到的失败 diff 大致如下:函数名(如[Function bound ...])被替换为无名的[Function],对象字面量带上了尾逗号,整体出现大面积的增删行。
此时直接执行jest -u重录快照即可完成迁移。该标志的参数定义与"可与--testNamePattern组合、仅重录匹配测试的快照"的用法,见 packages/jest-cli/src/args.ts。
Test Library 更新:Jasmine 断言迁移收官
三个新匹配器
Jest 完成了 Jasmine 断言到新匹配器的迁移,并新增三个匹配器:
| 匹配器 | 作用 |
|---|---|
toBeInstanceOf | 断言接收值是某个构造函数(或类)的实例,如expect(err).toBeInstanceOf(Error) |
toContainEqual | 断言可迭代结构中包含与期望值深度相等的元素,常用于数组内嵌对象的匹配 |
toThrowErrorMatchingSnapshot | 断言函数抛出错误,并将错误信息与快照比对,适合对错误消息做回归守护 |
后两者配合使用尤其适合"错误消息可读性"的测试:先用toThrowErrorMatchingSnapshot固化错误文案,未来文案变化会以快照 diff 的形式暴露。这三个匹配器的当前实现分别位于 packages/expect/src/matchers.ts(toBeInstanceOf)与同文件toContainEqual(第 569 行附近)。
spy/mock 匹配器失败信息更可读
toHaveBeenLastCalledWith、toHaveBeenCalledWith(及其别名lastCalledWith、toBeCalledWith)等 mock 匹配器的失败消息被重写,现在能更清晰地展示实际调用参数与期望参数之间的差异。所有断言完成重写并拆分到独立包后,Jest 团队的下一个目标是让这些匹配器脱离 Jest 独立使用,可集成到任意测试框架中。
断言别名与并发测试
根据社区呼声,Jest 16 补齐了一系列describe/it/test的别名:
- 聚焦单个测试:
it.only、test.only,或继续使用fit; - 跳过测试:
it.skip、test.skip,或继续使用xit; - 并发测试:
test.concurrent,适用于访问网络资源或数据库的测试场景(现代版本中并发上限由--maxConcurrency控制,定义见 packages/jest-cli/src/args.ts)。
覆盖 expect 全局:setupTestFrameworkScriptFile
如果你希望用 chai 等第三方断言库替换 Jest 自带的expect全局,可以通过setupTestFrameworkScriptFile配置项指向一个设置脚本,在其中自行覆盖全局断言。需要说明的是,这一配置在现代 Jest 中已废弃(被setupFilesAfterEnv取代,后者定义见 packages/jest-cli/src/args.ts),但它开启的"用配置注入自定义框架行为"思路一直延续至今——例如在 setup 文件中引入 expect-extend 示例 那样的自定义匹配器。
Community Update:快照测试生态的成形
发布同期,社区围绕快照测试产生了大量讨论。当时最受 Jest 团队认可的一篇文章总结了三个要点,至今仍是快照测试的最佳实践准则:
- 快照测试是常规测试的补充,而非替代——它解决的是"工程师原本不会去写测试的代码"(React 组件渲染结果、CLI 输出、错误消息等),但不解决所有问题;
- 快照测试在有健康 code review 流程时更有价值——快照变更应当被审查者审阅,而不是被无脑
-u吞掉; - 快照测试与自动 mock(auto-mocking)配合效果最佳——mock 掉不稳定依赖后,快照反映的才是被测单元自身的输出。
围绕快照能力的生态也在此时成形:社区出现了将 enzyme 组件树序列化为 JSON 以配合 Jest 快照的enzyme-to-json工具,以及自动把其他测试框架语法转换为 Jest 语法的jest-codemods——后者让开发者可以低成本评估"Jest 是否适合我"。大型项目层面,Redux 在此时期正式采用 Jest 作为测试框架,create-react-app 也将 Jest 内置为默认测试方案。
这些能力在本仓库的测试套件中均有对应验证,例如 e2e/tests/snapshot.test.ts 覆盖快照的基础行为,e2e/tests/toThrowErrorMatchingSnapshot.test.ts 验证错误快照匹配器,e2e/tests/testNamePattern.test.ts 与 e2e/tests/watchModePatterns.test.ts 则分别守护了--testNamePattern与 watch 模式过滤的行为。读者可结合这些用例深入理解每个特性。
结语
回顾 Jest 16,其核心思路可以用一句话概括:在 CLI 上"更快给出信号",在快照上"更稳定的格式",在 API 上"更完整的断言与别名"。这三大方向——CLI 交互效率、快照稳定性、匹配器完备性——在此后十余年的版本演进中始终是 Jest 迭代的主线。今天你在jest -t、jest --findRelatedTests、test.concurrent中看到的用法,其雏形都可以追溯到这一个版本。
【免费下载链接】jestDelightful JavaScript Testing.项目地址: https://gitcode.com/gh_mirrors/je/jest
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考