配了三年 E2E 测试,今天才发现 Cypress 15 到 16 的迁移没有想象中那么简单

配了三年 E2E 测试,今天才发现 Cypress 15 到 16 的迁移没有想象中那么简单

每次打开 Cypress 跑 E2E 测试,以为版本升级只是改个数字——直到你发现团队里几十个 spec 文件全部报错,Cypress.env() 全局报红,cy.exec() 直接消失,CI 彻底跑不动了。

Cypress 16 在 2026 年 9 月 1 日正式发布。这个版本干掉了三个用了几年的 API,顺手把底层依赖全部升级,还给 Chrome 加了 HTTP/2 网络拦截——不是小版本,是大版本。升级窗口很短,团队需要现在就行动。


第一个:cy.exec() 没了,cy.task() 要自己管超时

这是改动最大的一块。cy.exec() 在 Cypress 16 里直接消失,取而代之的是 cy.task() + taskTimeout。

旧的写法:

// Cypress ≤15
cy.exec('npm run build', { timeout: 60000 });

新的写法:

// Cypress 16+
cy.task('exec', { cmd: 'npm run build' }, { timeout: 60000 });

但 task() 默认超时是 60 秒,如果你之前写的 timeout 比这个短,要显式覆盖。更重要的是:cy.task() 运行在 Node.js 进程里,任何崩溃都会导致测试失败,不像 exec() 那样有隔离保护。

影响范围:如果你的项目里有 cy.exec() 来跑构建命令、调用 CLI 工具或者执行系统命令,所有这些地方都要改。


第二个:Cypress.env() 变成异步了

这是最多人踩坑的地方。Cypress.env() 以前是同步的,随便在哪都能读:

// Cypress ≤15 — 同步,到处都能读
const token = Cypress.env('API_TOKEN');
cy.request('/api/data', { headers: { Authorization: token } });

Cypress 16 改成了异步,而且彻底分离了「敏感值」和「公开配置」的读取路径:

// Cypress 16 — 异步,敏感值走 cy.env([]).then()
cy.env(['API_TOKEN']).then(token => {
  cy.request('/api/data', { headers: { Authorization: token } });
});

// 公开配置走 cypress.expose(),在 config 文件里声明
export default defineConfig({
  expose: ['BASE_URL', 'USER_EMAIL'],
  env: {
    BASE_URL: 'https://staging.example.com',
    USER_EMAIL: 'test@example.com',
  }
});

这个改动的原因很明确:Cypress 15 及之前,所有 env 值都会灌进浏览器内存,API Token、数据库密码这些敏感信息在 DevTools 里随便看。Cypress 16 把这个后门堵上了——敏感值永远在 Node.js 进程里流转,只有显式调用才会进浏览器。

影响范围:任何直接用 Cypress.env() 读 token 或密钥的测试都要改。一个有 200 个 spec 文件的仓库,如果大量用同步 env 读取,迁移工作量不小。好在 Cypress 官方出了一个 AI-assisted upgrade prompt,Claude Code 可以帮着一键生成迁移脚本。


第三个:Node.js 版本要求直接跳到 22/24/26

Cypress 16 不再支持 Node.js 20 和 25,安装层面就过不去。最低要求变成了:

  • Node.js 22.x ✅
  • Node.js 24.x ✅
  • Node.js 26.x ✅

还在用 Node.js 18 或者卡在 Node.js 20 LTS 的团队,升级 Cypress 之前要先升 Node。如果你的 CI 镜像是严格锁版本的,这个改动会卡住整个 pipeline。


第四个:Chrome/Edge 流量走原生网络栈,HTTP/2 默认开启

这是对生产环境最有价值的改动,也是最容易被忽略的隐性破坏点。

Cypress 16 里,Chrome、Chromium 和 Edge 的测试流量不再经过 Cypress 的代理层,而是直接走浏览器原生网络。HTTP/1.1 的六连接上限不存在了,多路复用直接可用,你的应用在测试环境里会表现得和线上完全一样。

这听起来是好事,但有几个副作用:

  1. 如果你的测试依赖了 Cypress 代理层的请求日志,有些用法会失效
  2. 某些 mock 行为在 HTTP/2 下和 HTTP/1.1 不一样,特别是并发请求的时序
  3. forceHttp1 这个 escape hatch 存在,但它是临时的,Cypress 17 之后会移除

第五个:component testing 的框架最低版本集体上调

如果你用 Cypress 做 React/Vue 组件测试,新版本的最低要求是:

  • Angular 21+
  • Next.js 15.0.4+ 或 16+
  • Vite 8+

卡在 Angular 18 或者 Next.js 14 的团队,升级 Cypress 之前要先升级框架本身。这个依赖链可能比 Cypress 本身更难搞。


三步迁移路径

第一步:跑官方迁移检查

cypress install --force  # 先升级 Cypress
npx cypress open       # 会弹出 AI-assisted upgrade prompt

这个 prompt 会扫描你的 spec 文件,识别出所有 cy.exec() 和 Cypress.env() 调用,生成对应的修改建议。

第二步:优先处理 cy.exec()

把项目里所有 cy.exec() 替换成 cy.task(),记得在 plugins/index.js 里注册对应的 task handler:

// plugins/index.js
on('task', {
  exec({ cmd }) {
    return require('child_process').execSync(cmd, { encoding: 'utf-8' });
  }
});

第三步:分类处理 Cypress.env()

区分两类 env 值:敏感信息(Token、密钥)走异步 cy.env([]).then() 路径;公开配置(BASE_URL、测试用户)迁移到 config 里的 expose 块。


你的 CI 现在能跑 Cypress 16 吗?

对照检查:

  • CI 机器的 Node.js 版本 >= 22?
  • 项目里有多少处 cy.exec()?有没有超过 20 处?
  • Cypress.env() 读敏感值的场景有多少?
  • component testing 用的是哪个框架版本?

如果三个问题里有两个答不上来,升级 Cypress 16 的优先级要提到这周。不要等到 Cypress 15 的安全更新停止推送之后再动手,那时候就真的被动了。

评论区

0 条评论

登录后可评论。