首页
/ 从 v1.0 到 v5.0:@cypress/angular 的演进史、Angular 支持矩阵与升级迁移指南

从 v1.0 到 v5.0:@cypress/angular 的演进史、Angular 支持矩阵与升级迁移指南

2026-09-07 16:32:24作者:翟萌耘Ralph

@cypress/angular 是 Cypress 官方提供的 Angular 组件测试(Component Testing)适配器,核心能力是让开发者把 Angular 组件直接挂载进 Cypress 浏览器中编写交互与断言。本文以 npm/angular/CHANGELOG.md 为主线,结合本仓库中该包的 README.mdpackage.jsonmount 源码,系统梳理从 2022 年首个 1.0.0 到 5.0.0 的版本脉络,回答"每个大版本支持哪些 Angular 版本、引入了哪些破坏性变更、应该怎样升级"这三个核心问题,并下沉到 mount 的实现原理。

包定位:它是做什么的,为什么大多数人不需单独安装

@cypress/angular 在 npm 上发布,向开发者导出 mount 命令及配套类型,用于在 Cypress 测试运行器中挂载 Angular 组件。其定位在 README.md 中有明确说明:该包随 cypress 主包一起分发,一般不需要单独安装。只有当你需要 mount 之类的进阶能力时才应显式安装并从 @cypress/angular 导入。若只是搭建标准 Angular 组件测试项目,官方推荐直接使用 Cypress 自带的脚手架与 Angular Component Testing 文档 中的指引,不必手工处理该适配器。

在当前的仓库快照中,包自身的 package.json 对版本号的描述是 0.0.0-development(monorepo 内各 npm 包统一使用该占位版本号,真正对外版本由发布流程基于 CHANGELOG 生成),并声明:

{
  "peerDependencies": {
    "@angular/common": ">=21.0.0",
    "@angular/core": ">=21.0.0",
    "@angular/platform-browser": ">=21.0.0",
    "rxjs": ">=7.8.0"
  },
  "keywords": ["angular", "cypress", "test", "testing", "zoneless"]
}

peerDependencieskeywords 可以确认:当前主线版本的适配对象是 Angular 21+ 与 zoneless 变更检测,这与 5.0.0 的发布内容完全吻合。

源码布局与构建管线

包体很小、结构清晰,便于源码级阅读:

  • src/index.ts:公共入口,仅一行 export * from './mount'
  • src/mount.ts:全部挂载逻辑,包括 TestBed 配置、Signals 处理、清理钩子等;
  • rollup.config.mjs:Rollup 构建配置,产物为 ESM(formats: ['es']),并将 @angular/*@angular/core/rxjs-interop 等声明为 external,不打进包体;
  • package.jsonpostbuild 执行 scripts/sync-exported-npm-with-cli.js,把产物同步到 cli/angular 目录供 Cypress 二进制分发。

与之配套的 AGENTS.md(npm/angular/AGENTS.md)进一步说明:开发期运行 yarn build(Rollup 编译到 dist/ 并同步至 cli/angular)、yarn check-tstsc --noEmit 类型检查)、yarn lint(ESLint)。构建前务必先完成编译,因为 Cypress 二进制里实际发布的是 cli/angular 这份拷贝。

Angular 版本支持矩阵:13 到 21 的一次性俯瞰

把 CHANGELOG 与 README 的 Requirements 小节拼合,可以得到完整的"包大版本 × Angular 版本"对应关系:

@cypress/angular 大版本 支持的 Angular 对应 Cypress 关键节点
v1.x(2022-08 起) Angular 13–16 时代 Cypress 10/11 时代 mount 落地、模板/teardown/standalone 支持
v2.x(2022-11 起) Angular 13–16 Cypress 12/13 时代 多次 mount 清理、Angular Signals CT Harness
v3.x(2025-01 起) Angular 17.2+(含 19) Cypress 14 移除 13–16 支持
v4.x(2025-08 起) Angular 18、19 Cypress 15 移除 Angular 17 支持
v5.x(2026-08 起) Angular 21+ Cypress 16 合并 zoneless 上游、移除 18–20 支持

其中 README 给出的官方摘要为:

  • @cypress/angular@2 支持 Angular 13–16;
  • @cypress/angular@3 支持 Angular 17(更准确地说,v3.0.0 的 BREAKING CHANGES 注明是 17.2 及以上);
  • @cypress/angular@4 支持 Angular 18–19;
  • @cypress/angular@5 及当前主线要求 Angular >=21.0.0

这意味着适配器的每个大版本都会主动收窄对老 Angular 的支持范围,升级前务必对照本表核对项目锁定的 Angular 主版本。

逐版本演进记录:2022—2026 的完整时间线

以下按 CHANGELOG 的发布顺序,把 13 个版本(若干版本存在重复的自动生成条目,此处合并表述)的功能、修复与破坏性变更完整归档。

v1.0.0(2022-08):Angular 组件测试的起点

首个正式版本围绕"Angular CT 支持从实验走向可用"展开,集中落地的能力包括:

  • mount 本体:feature "angular mount"(#22858);
  • 开启 Angular Component Testing 支持(#23089);
  • 支持模板字符串直接挂载、teardown(组件销毁)与 standalone 组件(#23117);
  • 支持组件挂载容器选择器迁移:将 #__cy_root 切换为 data-cy-root(#20951),这也是后续断言 cy.get 选择根容器的事实标准;
  • 脚手架模板与配置文件路径修正(#19776、#20047)、按 testingType 收敛配置(#20677、#19364)、未迁移配置的报错信息改进(#21467);
  • 配置体系演进:从 integrationFolder/componentFolder 走向 specPattern(#19319),支持 .config 文件(#18578)、devServer 字段(#18962、#20092)与 plugins-on-config(#18798);
  • 工程侧:支持 webpack-dev-server v4(#17918)、移除 testFiles 引用(#20565)、CLI 从 run-ct/open-ct 全面切换到 --ct(#18422);
  • 依赖修复:rxjs 依赖锁定 >6.6.0(#16676),移除导致 semantic-release 失败的依赖(#23142)。

v1.1.x(2022-08 ~ 2022-10):稳定性修正

  • Angular 14.2 下 mount 编译报错的修复(#23593);
  • 补齐测试中缺失的 it.skip 支持(#23829);
  • 挂载后主动调用 ngOnChanges(#23596)——这是纯类语法输入绑定的关键补偿逻辑,详见后文源码解析;
  • 同时期仓库顺带加入了 Svelte 组件测试支持(#23553,属于旁路功能)。

v2.0.0(2022-11):多次挂载行为收敛 + 服务覆盖

  • BREAKING:在同一个测试中重复调用 mount 时,会先移除上一次挂载的组件(#24470),避免 DOM 中残留旧组件导致断言错乱;
  • 支持在 Angular 组件测试中覆盖全局服务(#24394);
  • v2.0.1/v2.0.2/v2.0.3 的修复:组件派生信息为空时不再抛错(#24571);根挂载元素从 [data-cy-root](#25807)到"在原始位置挂载 cy-root"(#25965)的进一步修正。

v2.0.4(2024-06)与 v2.1.0(2024-07):Signals 时代到来

  • 全仓库 TypeScript 升级到 5(#29568);
  • 新增 Angular Signals CT Harness(#29621),面向 Angular 17.2+,允许用户在组件测试里使用 Angular Signals。

v3.0.0 / v3.0.1(2025-01 / 2025-07)

  • 支持 Angular 19,并同步更新测试套件(#30675);
  • BREAKING(Cypress 14):移除 Angular 13–16 支持,要求 Angular 17.2 及以上;
  • v3.0.1:确保 cy.mount 具备引用安全性(reference safe),修复 #31238 与 #31983 两个 issue(#31993)。

v4.0.0 / v4.1.0(2025-08 / 2025-12)

  • BREAKING(Cypress 15):移除 Angular 17 支持,仅支持 Angular 18 与 19,并同步修正脚手架依赖与系统测试配置(#31446、#31303 等系列提交);
  • 保证遗留(legacy)输出 spy 按预期工作(#32158);
  • v4.1.0:新增 cypress/angular-zoneless 测试装置(testing harness),面向 Angular 21 且兼容 Angular 20(#33025)——这是通往 5.0 的过渡形态。

v5.0.0(2026-08):zoneless 主线化,Angular 21 专属

这是当前仓库快照所对应的大版本,破坏性变更最密集:

  • @cypress/angular-zoneless 的上游实现合并进 @cypress/angular,同时移除对 Angular 18、19、20 的支持@cypress/schematic 仅支持 Cypress 16,且不再脚手架生成 angular-zoneless 的 mount handler;@cypress/angular-zoneless 在 npm 上随之废弃(deprecated);
  • 移除对 @angular/platform-browser-dynamic 的依赖,统一改用 @angular/platform-browser
  • 构建目标(build targets)从 es2020 提升到 es2022——官方声明这虽是 breaking 但影响应最小。

把 5.0.0 与当前 package.json(peer 依赖 @angular/* >= 21、开发依赖 ^21.0.0provideZonelessChangeDetection 相关实现)对照即可确认:zone.js 时代彻底结束,zoneless 变更检测成为唯一路径

从源码看 v5 的挂载实现:zoneless 如何工作

理解 CHANGELOG 中 5.0.0 的变更,最好直接读 src/mount.ts。该文件是整个包的实现核心,其设计能解释大量 changelog 条目背后的动机。

TestBed 初始化与"一次环境、逐测清理"模型

模块加载时即初始化测试环境(文件中最后一次性的环境搭建):

  • getTestBed().initTestEnvironment(BrowserTestingModule, platformBrowserTesting(), { teardown: { destroyAfterEach: false } })
  • 通过 setupHooks(cleanup) 注册 Cypress 测试钩子,使每个用例之间执行 cleanup()
  • cleanup() 内部调用非公开的 getTestBed().tearDownTestingModule() 移除 DOM 中的上一个组件——这正是 v2.0.0 破坏性变更(重复 mount 先移除旧组件)与后续 data-cy-root/cy-root 位置修正的运行时落点;若 Angular 版本过旧导致 teardown 失败,会抛出带 https://on.cypress.io/frameworks 指引的错误。

模块引导:standalone、CommonModule 与 zoneless

bootstrapModuleMountConfig 做三件事:

  1. 归一化 declarations / imports / providers 为空数组;
  2. 注入自定义 CypressAngularErrorHandler(替换默认 ErrorHandler,把组件内异常重新抛出,使 Cypress 能捕获并让用例失败)与 provideZonelessChangeDetection()——后者即 5.0.0"合并 zoneless 上游"的代码证据,参见源码注释 @see https://angular.dev/guide/zoneless#using-zoneless-in-testbed
  3. 根据 Angular 组件元数据 ɵcmp.standalone 判断组件是否为 standalone:是则放入 imports,否则放入 declarations;随后无条件并入 CommonModule

MountConfig:一个接口承载"声明、导入、提供者与组件输入"

源码中 MountConfig<T> extends TestModuleMetadata 额外暴露了 componentProperties 字段,允许直接注入组件 @Input(),甚至用 cy.spy() 替换 EventEmitter 型输出:

it('renders a button with Save text', () => {
  cy.mount(ButtonComponent, { componentProperties: { text: 'Save' } })
  cy.get('button').contains('Save')
})

返回值为 MountResponse<T>,携带 fixture: ComponentFixture<T>component: T,方便在用例内继续操作组件实例。挂载完成后还会通过 Cypress.log 输出 mount 命令日志。

Signals 双向桥接:为何 v2.1 与 v4.1 的"harness"能成立

针对 Angular Signals,源码实现了运行时类型探测与自动订阅(这是 #29731 系列 issue 的产物):

  • isSignal 通过组件属性上的 Symbol(SIGNAL) 判断;
  • isInputSignal 进一步检查函数名为 inputValueFn
  • isModelSignal 判断"writable signal 且带 subscribe";
  • registerSignalEventsIfNeededtoObservable 建立信号→组件输入的单向同步,并用 fixture.componentRef.setInput 推送;
  • 当检测到组件端为 model signal(xxxChange 约定),还会建立组件→外部信号的反向回写;detectAndRegisterOutputSpyToSignal 则让 createOutputSpy('countChange') 这类 spy 与 signal 输出协同工作;
  • 所有内部订阅被收集到 activeInternalSubscriptions,在 cleanup() 时统一 unsubscribe(),防止跨用例内存泄漏。

类语法输入为何要手动触发 ngOnChanges

setupComponent 中有一段容易被忽略但很关键的逻辑:由于组件输入是通过把值赋给实例属性完成初始化的,ngOnChanges 生命周期不会自动触发,因此当组件实现 OnChanges 且有 componentProperties 时,代码会手工构造 SimpleChanges 并调用 component.ngOnChanges(...)——这正是 changelog v1.1.1(#23596)"call ngOnChanges after mount"的源码级实现,属于典型的"版本记录与实现一一对应"的细节。

模板字符串挂载与测试容器渲染器

  • 传字符串时,createComponentFixture 通过 TestBed.overrideTemplate(WrapperComponent, template) 把模板字符串塞进内置的 cy-wrapper-component(standalone: false),从而支持 mount('<app-stepper></app-stepper>', { declarations: [StepperComponent] }) 这类不传组件类的写法;
  • 自定义的 CypressTestComponentRenderer 继承 TestComponentRenderer,把 Angular 的根元素插入由 @cypress/mount-utils 提供的容器 getContainerEl() 中,并在每次挂载前清空容器,从而保证 DOM 位置可控。

各版本关键 API 与使用范式对比

CHANGELOG 演进同样反映在 API 使用范式上,下表可作为迁移时的自查清单:

关注点 v1 时期 v2/v3 v4 v5(当前主线)
根容器 #__cy_root data-cy-root data-cy-root data-cy-root
重复 mount 残留旧组件 自动清理旧组件 自动清理 自动清理
Signals 不支持 v2.1+ 支持(Angular 17.2+) 支持 支持(含 model signal 双向同步)
zoneless 通过 @cypress/angular-zoneless(v4.1 起) 内建于 @cypress/angular
组件输入传递 componentProperties 同左 同左 + 引用安全 同左 + InputSignal/WritableSignal 类型约束

其中"引用安全(reference safe)"值得展开:v3.0.1 修复 #31238/#31983 后,cy.mount 不再破坏传入对象/数组的引用;但源码注释也明确指出保留一个例外——用户主动传入 Cypress 输出 spy(EventEmitter 实例)时仍按兼容逻辑直接赋值,从而保证既有测试写法不回归。

升级迁移建议

基于 CHANGELOG 的破坏性变更记录,可以提炼出三条可执行结论:

  1. 升级顺序不能跳步:Angular 支持面按"13–16 → 17.2+ → 18/19 → 21+"单向收窄,若项目当前使用 Angular 17,应先升级到 @cypress/angular@3(对应 Cypress 14)验证,再考虑进入 18/19(v4,Cypress 15),最终迁到 21+(v5,Cypress 16)。任何一次跨大版本跳跃都可能同时触发适配器与 Cypress 主版本的双重变更。
  2. v5 迁移要检查三处代码:① 确认 Angular 已升级到 21 及以上,且项目中不再依赖 zone.js 引导路径;② 检查是否仍在 import @angular/platform-browser-dynamic,如有需改为 @angular/platform-browser;③ 若此前使用的是 cypress/angular-zoneless 入口或由 schematic 生成的 zoneless mount handler,请改为 @cypress/angular 自带的 mount,因为该独立包已在 npm 上废弃、schematic 也不再生成对应 handler。
  3. 回归验证以组件测试全集为准:升级后优先跑一遍包含以下场景的用例——多次 mount 同一测试、componentProperties 传对象/数组(验证引用安全)、ngOnChanges 生命周期断言、Signals/model 输入输出双向同步、以及模板字符串挂载,这些恰好覆盖了 CHANGELOG 中历次 bug fix 的回归面。

结语

@cypress/angular 的 CHANGELOG 虽然只是版本记录,却完整折射出 Cypress Angular 组件测试四年间的技术决策:从 #__cy_rootdata-cy-root 的容器标准化,从"重复 mount 不清理"到"自动清理 + 引用安全"的行为收敛,从 zone.js 到 Angular Signals 再到 zoneless 的框架演进。对照 mount 源码 阅读,你能在每一行版本记录背后找到具体的实现落点——这正是把 changelog 从"发生了什么"升级为"为什么这么做"的最佳路径。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388