尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Nx 21.3 迁移实战:自动替换 Jest v30 移除的 Matcher 别名
Nx 21.3 迁移实战自动替换 Jest v30 移除的 Matcher 别名【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nxJest v30 移除了一批历史遗留的 Matcher 别名如toBeCalled、toThrowError直接升级会让大量存量测试在运行时断言失效。Nx 的nx/jest插件在 21.3.0 版本中内置了一条名为replace-removed-matcher-aliases的自动化迁移用于在工作区升级到 Jest v30 时将测试文件中的废弃别名批量改写为对应的新 Matcher。本文基于该迁移的文档、实现源码与测试用例完整讲解这条迁移的映射规则、工作原理、安全设计以及触发方式帮助你在升级 Jest 大版本时无痛完成断言代码的同步。一、背景Jest v30 移除 Matcher 别名随着 Jest v30 的发布jest.expect中一批以动词过去式风格命名的 Matcher 别名被正式移除。这些别名与对应的正式 Matcher 语义完全相同但属于历史遗留命名官方在 v30 迁移指南中要求开发者全部改用新命名。Nx 在 迁移注册表 中为这条迁移声明了明确的适用条件replace-removed-matcher-aliases: { version: 21.3.0-beta.3, requires: { jest: 30.0.0 }, description: Replace removed matcher aliases in Jest v30 with their corresponding matcher, implementation: ./dist/src/migrations/update-21-3-0/replace-removed-matcher-aliases, documentation: ./dist/src/migrations/update-21-3-0/replace-removed-matcher-aliases.md }注意两个细节其一requires.jest 30.0.0表示只有当工作区中的 Jest 版本满足条件时迁移才会被执行其二在 migrations.json 中这条迁移还以replace-removed-matcher-aliases-v22-3的名称在22.3.2-beta.0版本再次注册说明它会在 21.3 与 22.3 两个升级路径上被重复触发覆盖未在第一次升级中完成迁移的工作区。二、别名 → 新 Matcher 完整映射表迁移的核心是一张固定的映射表。完整的 11 组替换关系如下与实现源码 replace-removed-matcher-aliases.ts 中的matcherAliasesMap一一对应废弃别名Jest v30 已移除对应新 MatchertoBeCalledtoHaveBeenCalledtoBeCalledTimestoHaveBeenCalledTimestoBeCalledWithtoHaveBeenCalledWithlastCalledWithtoHaveBeenLastCalledWithnthCalledWithtoHaveBeenNthCalledWithtoReturntoHaveReturnedtoReturnTimestoHaveReturnedTimestoReturnWithtoHaveReturnedWithlastReturnedWithtoHaveLastReturnedWithnthReturnedWithtoHaveNthReturnedWithtoThrowErrortoThrow前 5 组针对 Mock 函数的调用记录断言called 系列中间 5 组针对 Mock 函数的返回值断言returned 系列最后一组是针对抛错断言的toThrowError→toThrow。替换时参数如toBeCalledTimes(1)中的1、nthCalledWith(1, arg)中的调用序号与参数保持不变仅改写 Matcher 名称本身。三、Before / After 完整示例原迁移文档给出了一个覆盖全部 11 种别名用法的典型测试文件。迁移前describe(test, () { it(should pass, async () { expect(mockFn).toBeCalled(); expect(mockFn).toBeCalledTimes(1); expect(mockFn).toBeCalledWith(arg); expect(mockFn).lastCalledWith(arg); expect(mockFn).nthCalledWith(1, arg); expect(mockFn).toReturn(); expect(mockFn).toReturnTimes(1); expect(mockFn).toReturnWith(value); expect(mockFn).lastReturnedWith(value); expect(mockFn).nthReturnedWith(1, value); expect(() someFn()).toThrowError(); expect(() someFn()).not.toThrowError(); await expect(someAsyncFn()).rejects.toThrowError(); await expect(someAsyncFn()).resolves.not.toThrowError(); }); });迁移后describe(test, () { it(should pass, async () { expect(mockFn).toHaveBeenCalled(); expect(mockFn).toHaveBeenCalledTimes(1); expect(mockFn).toHaveBeenCalledWith(arg); expect(mockFn).toHaveBeenLastCalledWith(arg); expect(mockFn).toHaveBeenNthCalledWith(1, arg); expect(mockFn).toHaveReturned(); expect(mockFn).toHaveReturnedTimes(1); expect(mockFn).toHaveReturnedWith(value); expect(mockFn).toHaveLastReturnedWith(value); expect(mockFn).toHaveNthReturnedWith(1, value); expect(() someFn()).toThrow(); expect(() someFn()).not.toThrow(); await expect(someAsyncFn()).rejects.toThrow(); await expect(someAsyncFn()).resolves.not.toThrow(); }); });可以看到not.、rejects.、resolves.等修饰链同样被正确处理这是通过 AST 选择器而非简单字符串替换实现的详见下一节。四、实现原理基于 tsquery 的 AST 定向替换迁移实现位于 replace-removed-matcher-aliases.ts它并非对文件做粗暴的字符串替换而是用phenomnomnominal/tsquery对 TypeScript AST 做定向匹配核心流程分四步1. 快速短路检查。先用aliasNames.some((alias) fileContent.includes(alias))判断文件内容是否包含任意别名。不包含则直接原样返回避免对大量无关文件做无谓的 AST 解析这也是大仓库性能的关键。2. tsquery 选择器精确匹配 expect 链。关键代码如下const selector CallExpression PropertyAccessExpression:has(CallExpression Identifier[nameexpect]) Identifier[name/^(${aliasPattern})$/]; const matchedNodes queryIdentifier(sourceFile, selector);选择器语义是匹配「作为expect(...)调用链成员访问的、名称落在别名集合内的标识符」。正是借助:has(CallExpression Identifier[nameexpect])这个结构约束迁移只会命中expect(mockFn).toBeCalled()这样的断言链而不会误伤普通代码中恰好同名的变量、方法或字符串字面量。3. 逆序应用替换。收集每个匹配节点的start/end位置后按b.start - a.start降序排序再逐个替换保证靠后的替换不会因字符串长度变化而破坏前面的位置偏移for (const update of updates.sort((a, b) b.start - a.start)) { updatedContent updatedContent.slice(0, update.start) update.text updatedContent.slice(update.end); }4. 最后统一格式化。全部替换完成后调用formatFiles(tree)确保改写后的文件仍符合 prettier 等格式化约定。测试用例 replace-removed-matcher-aliases.spec.ts 中专门有一条「should preserve complex code patterns that could be corrupted by AST reprinting」它构造了包含泛型接口、解构赋值、箭头函数嵌套回调、对象字面量的复杂测试文件验证迁移不会破坏{ payGroupId, value }、{ result }等代码形态。这说明该迁移在设计上刻意避免了早期 tsquery 实现「整体重打印 AST」导致格式损坏的问题——只做精确的位置替换其余代码保持原样。五、测试文件发现复用 Jest 自身的解析能力迁移的另一半工作量在于「找到哪些文件需要改」。getTestFilePaths的流程同样见 replace-removed-matcher-aliases.ts如下用globAsync在工作区中查找所有**/jest.config.{cjs,mjs,js,cts,mts,ts}配置文件跳过根级聚合配置如果某个jest.config内容包含getJestProjectsAsync()则说明它是 Nx 生成的、会聚合所有项目测试路径的根配置直接跳过以免重复处理对每个项目配置调用 Jest 的readConfigjest-config包读取配置用Runtime.createContext(config.projectConfig, { maxWorkers: 1, watchman: false })创建最小化 Jest 运行时上下文通过new SearchSource(jestContext).getTestPaths(...)得到该项目实际匹配的测试文件列表这正是 Jest 真正会运行的测试集合天然尊重testMatch、testRegex等配置。测试用例「should not update non-jest spec files」验证了这一行为当配置testMatch: [**/*.spec.ts]时app1.test.ts不会被改动而app1.spec.ts会被正确更新——迁移只会触碰 Jest 实际纳入运行的测试文件。对坏配置的容错设计。迁移在resolveTestPaths的三处可能失败的环节读取配置失败、创建运行时上下文失败、解析测试路径失败都做了try/catch通过logger.warn输出包含配置文件路径的警告后跳过该项目绝不会让整个迁移崩溃。测试套件中的「gracefully handles broken jest configs」分组覆盖了引用缺失.swcrc文件、引用不存在的 preset、getTestPaths抛出异常如损坏的正则等场景并验证了「坏项目被警告、好项目仍被处理」的隔离性。六、如何触发这条迁移这条迁移属于 Nx 的自动迁移migration会在工作区执行nx migrate升级流程时根据版本与依赖条件自动运行。结合 migrations.json 中packageJsonUpdates的定义可以推断完整链路Nx 21.3.0 的包更新将jest升级到~30.0.0同时升级types/jest、expect、jest/globals等配套包随后满足jest 30.0.0条件的replace-removed-matcher-aliases迁移即被触发对工作区所有 Jest 项目的测试文件执行别名改写。建议在升级后通过nx test全量运行一次测试确认断言行为与改写前完全一致别名与新 Matcher 语义等价测试结果不应有任何变化。七、小结replace-removed-matcher-aliases是 Nx 自动迁移能力的一个典型缩影以 Jest v30 的破坏性变更为驱动用结构化的 AST 匹配保证替换精确、用逆序编辑保证零副作用、用 Jest 自身的配置解析保证只处理真实测试文件、用逐级容错保证迁移过程不中断。对于升级到 Jest v30 的 Nx 工作区这条迁移可以在「零手工改代码」的前提下完成全部断言别名的现代化让团队把精力集中在真正需要人工决策的升级事项上。【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

2026视觉标定板实测:自动化程度对科研误差的影响分析

2026视觉标定板实测:自动化程度对科研误差的影响分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/11 22:06:33
Flink Web UI 核心功能与生产环境实战指南

Flink Web UI 核心功能与生产环境实战指南

1. Flink Web UI 完全指南:从入门到精通作为Apache Flink的核心管理界面,Web UI是每个Flink开发者必须掌握的运维工具。我在实际生产环境中使用Flink处理日均PB级数据时,发现90%的集群问题都可以通过Web UI快速定位。这个可视化控制台不仅提供…

📅 2026/9/11 22:01:32
Pico+MicroPython+EMQX+MQTT+JSON全链路实战指南

Pico+MicroPython+EMQX+MQTT+JSON全链路实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/11 22:01:32
MORE NEWS

更多资讯

📰

OKF(开放知识格式)深度解析:纯文本文件夹能否替代向量数据库?

OKF(开放知识格式)深度解析:纯文本文件夹能否替代向量数据库?摘要:近期,Google 以开放知识格式(Open Knowledge Format,OKF)将一种基于纯文本文件夹的知识管理方式推向标…

📰

STM32+Keil5心电监测蓝牙App链路:从ADC采样到波形绘制全流程

简介:基于STM32Keil5开发的心电图监测蓝牙传输App毕业设计资源,面向需要完成嵌入式软硬件结合课题的本科生与开发者。项目以STM32单片机为硬件核心,通过AD转换实时采集心脏电压信号,再经DMA高效传输并由主程序将心电数值交由HC-05…

📰

矿井通风PLC控制系统设计与实践

1. 矿井通风控制系统的生死时速干过矿井作业的老铁都知道,井下最要命的就是通风问题。我十年前在山西某煤矿做自动化改造时,亲眼见过因为通风故障导致瓦斯积聚的惊险场面——当时要不是备用风机及时启动,差点就酿成大祸。这种生死攸关的系统&…

📰

OmniRoute Dashboard 全功能指南:从 Provider 管理、Auto Combo 智能路由到安全运维

OmniRoute Dashboard 全功能指南:从 Provider 管理、Auto Combo 智能路由到安全运维 【免费下载链接】OmniRoute Never stop coding. Free MIT AI gateway: one endpoint, 352 providers (150 free), 1200 models Kimi, Claude, GPT, Gemini, GLM, DeepSeek, MiniMa…

📰

Flutter在鸿蒙系统中的文本对齐实现与优化

1. 项目背景与需求分析在跨平台应用开发领域,Flutter框架因其高效的渲染性能和跨平台特性备受开发者青睐。而鸿蒙系统作为新兴的操作系统平台,其独特的分布式架构和全场景能力为应用开发带来了新的可能性。将Flutter应用于鸿蒙项目开发时,文本…

📰

Gopeed 桌面多窗口 Capability RPC 架构解析:主窗口与子窗口的通信契约设计与实现

Gopeed 桌面多窗口 Capability RPC 架构解析:主窗口与子窗口的通信契约设计与实现 【免费下载链接】gopeed A fast, modern download manager for HTTP, BitTorrent, Magnet, and ed2k. Cross-platform, built with Golang and Flutter. 项目地址: https://gitco…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬