关于 cypress-automation
cypress-automation 是面向编写 Cypress TypeScript 测试套件的技能,涵盖端到端与组件测试。它强调命令队列和重试机制,并通过网络拦截与别名等待减少不稳定测试。
主要功能
- 01Cypress 命令队列与重试机制
- 02网络请求拦截与断言
- 03端到端和组件测试
- 04自定义命令与会话登录
- 05跨域认证流程
- 06CI 与 Cypress Cloud 配置
适用场景
- 01编写稳定的端到端测试
- 02在浏览器中隔离测试组件
- 03模拟 API 响应和网络错误
- 04在 CI 中运行并并行化测试
MCP 相关
文档提及 Cypress Cloud MCP,可向 AI 助手提供已记录运行中的错误、堆栈跟踪和 Test Replay 链接。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ petrkindlmann/ qa-skills --skill cypress-automation安装后在 Claude Code 中输入/cypress-automation确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/ci-recipes.mdcomponent-and-fixtures.mdconfig-and-commands.mdintercept-patterns.md详细介绍
快速导航
| 你需要…… | 前往 |
|---|---|
| 编写 E2E 规格(加载、拦截、断言) | 核心原则 + references/intercept-patterns.md |
添加类型化自定义命令 / cy.session 登录 | 自定义命令 + references/config-and-commands.md |
| 挂载并测试单个组件 | 组件测试 + references/component-and-fixtures.md |
搭建 cypress.config.ts / 项目布局 | 项目结构 + references/config-and-commands.md |
| 存根、监视、模拟错误或轮询 API | cy.intercept 模式 + references/intercept-patterns.md |
| 在 CI 中运行 / 在 Cypress Cloud 上并行运行 | CI 集成 + references/ci-recipes.md |
| 处理 SSO / OAuth 重定向 | 跨源流程 + references/intercept-patterns.md |
探索问题
先检查 .agents/qa-project-context.md——如果该文件存在,就使用其中的信息,并跳过已回答的问题。
- 组件测试、E2E,还是两者都需要? 组件测试会在隔离环境中挂载单个组件;E2E 则通过浏览器测试整个应用。大多数项目两者都需要。组件测试需要针对具体框架的挂载方式(React、Vue、Angular、Svelte)。
- 是否使用 Cypress Cloud? Cloud 提供并行运行、波动检测、分析、Test Replay 和 AI 插件。如果团队使用它,请配置
projectId和记录密钥。否则,所有测试都可以在本地或 CI 中运行,无需 Cloud。 - 是否使用 TypeScript? 强烈推荐,本指南也默认使用 TypeScript——Cypress 原生支持它。所有示例均使用 TypeScript。
- 使用什么框架和打包工具? React + Vite、Next.js + Webpack、Vue + Vite、Angular——组件测试配置取决于这些选择。
- 是否涉及跨源身份验证? 如果登录会重定向到其他域名(SSO、OAuth 提供方),就需要使用
cy.origin。请提前说明,以便据此构建登录命令。 - 现有测试套件还是从头开始? 如果正在迁移,请从最不稳定或最关键的测试开始,不要一次性全部重写(参见
test-migration)。
核心原则
1. 命令会排入队列,而不会立即执行
这是最重要的概念。Cypress 命令(cy.get、cy.click、cy.type)调用时不会执行——它们会被加入队列,然后按顺序异步运行。你不能对 Cypress 命令使用 async/await,也不能将其返回值存入变量。
// WRONG -- this looks synchronous but is not
const button = cy.get('[data-testid="submit"]'); // button is a Chainable, not an element
button.click(); // works only by accident, via chaining
// CORRECT -- chain commands; use .then() when you need a value
cy.get('[data-testid="submit"]').click();
cy.get('[data-testid="price"]').invoke('text').then((text) => {
const price = parseFloat(text.replace('$', ''));
expect(price).to.be.greaterThan(0);
});
2. 内置重试能力(适用于查询,不适用于操作)
Cypress 会自动重试查询(cy.get、cy.find、cy.contains)和断言,直到它们通过或超时。它不会重试操作(cy.click、cy.type、cy.select):
cy.get('.loading').should('not.exist')会等待指示器消失cy.get('.item').should('have.length', 5)会等待元素数量达到 5cy.click()只执行一次——如果元素无法交互,就会失败
3. 使用 cy.intercept 控制网络
cy.intercept 会在网络层拦截 HTTP 请求——可以存根响应、等待请求完成,以及断言请求正文。掌握它是编写不稳定测试与稳定测试的分水岭。始终等待网络别名或 DOM 断言,绝不要使用固定的 cy.wait(ms)。
4. 隔离:每项测试都从干净状态开始
每个 it() 都会在全新的浏览器状态下运行——默认情况下,Cypress 会在测试之间清除 cookies、localStorage 和 sessionStorage。测试不得依赖其他测试的状态或执行顺序。使用 beforeEach 进行共享设置,不要让测试之间相互依赖。
5. 测试选择器的数据属性
使用 data-testid、data-cy 或 data-test。这些属性在 CSS 重构、类名重命名和本地化后仍会保留。在 cypress.config.ts 中配置首选属性。
项目结构与配置
标准布局将 e2e/、component/、fixtures/ 和 support/ 分开,并在根目录下通过 cypress.config.ts 配置两个运行器。关键配置选项:从环境变量获取 baseUrl(CI 中绝不硬编码)、明确设置视口、在 CI 中设置 retries.runMode: 2,以及在 component.devServer 下配置框架和打包工具组合。组件测试文件位于 cypress/component/**/*.cy.tsx 下。
目录树、完整的 cypress.config.ts 和 tsconfig.json 补充配置,请参阅 references/config-and-commands.md。
自定义命令
自定义命令可将重复操作封装为简洁、类型安全的 API。常见命令包括:通过 cy.session 和 API(而非 UI)实现的 login、简写选择器 getByTestId,以及 shouldShowToast 等断言辅助命令。在 cypress/support/index.d.ts 中声明这些命令(使用带有 JSDoc @example 的 declare namespace Cypress { interface Chainable { ... } }),这样就能获得自动补全和编译时检查。
cy.session 需要 validate() 回调。 cy.session 会自动缓存 cookies、localStorage 和 sessionStorage,但如果没有 validate(),缓存的会话就不会重新验证——过时或已过期的令牌会被静默复用,导致会话失效。务必传入一个请求已认证端点的 validate(),例如 cy.request('/api/me').its('status').should('eq', 200)。
可重试的查询使用 Cypress.Commands.addQuery(),且回调必须是非箭头 function () {}——Cypress 会绑定 this 以应用命令超时,因此使用箭头函数会悄悄破坏重试能力。(拦截处理器则相反:在那里使用 (req) => {} 没问题,因为它们不会用到 this。)
完整的命令定义、validate() 回调、addQuery 示例和 TypeScript 声明,请参阅 references/config-and-commands.md。
cy.intercept 模式
cy.intercept 涵盖完整的网络控制功能:
- Stub 响应 —— 使用
{ statusCode, body }返回预设数据,然后调用cy.wait('@alias')。 - 仅监视,不 Stub —— 调用
cy.intercept('POST', '/api/orders').as('createOrder'),然后断言interception.request.body和interception.response?.statusCode。 - 条件响应 —— 使用
callCount驱动闭包,模拟轮询(202 → 200)。此处使用箭头函数处理器(req) => { ... }是正确的。 - 网络错误 —— 使用
{ statusCode: 500 }、{ forceNetworkError: true }或针对缓慢响应使用req.reply({ delay })。 - 修改真实响应 —— 使用
req.continue((res) => { ...; res.send(); })。 - 基于 Fixture —— 使用
{ fixture: 'api-responses/checkout-success.json' }。
请在触发请求的操作之前注册拦截,否则别名将永远无法匹配。
每种模式的可运行代码以及跨来源流程,请参阅 references/intercept-patterns.md。
组件测试
组件测试会在真实浏览器中挂载单个组件,而无需运行完整应用——速度比 E2E 快,提供的视觉反馈也比单元测试更多。使用 cy.mount(<Component .../>),通过 cy.stub()/cy.spy() 传入回调,并使用与 E2E 中相同的 cy.contains/cy.get 链进行断言。组件测试中绝不要使用 cy.visit。对于 Vue,使用 cy.mount(Component, { props: { ... } })。
完整的 React ProductCard 组件测试套件,请参阅 references/component-and-fixtures.md。
使用固定数据进行数据驱动测试
分为三个层次,具体取决于数据来源:
- 静态固定数据 — 对很少变化的 JSON,使用
cy.fixture('users').as('users');在beforeEach(function () { ... })中通过this.users读取。 - 通过
cy.task获取动态数据 — 在setupNodeEvents中注册 Node 端任务,用于必须在浏览器之外运行的 API 调用或数据库初始化(任务主体在 Node 中运行,因此其中的fetch是 Node 的全局 fetch,而不是 Cypress API)。 - 特定环境的配置 — 在
setupNodeEvents中合并按环境配置的baseUrl映射,并通过--env ENVIRONMENT=...选择。
关于固定数据、通过 cy.task 初始化数据以及环境配置的代码,请参阅 references/component-and-fixtures.md。
跨源流程
对于重定向到另一个域名的正规流程(SSO、OAuth 提供方、独立的身份验证主机),请将要在另一来源上运行的命令封装在 cy.origin 中。这取代了旧的 chromeWebSecurity: false / experimentalSessionAndOrigin 变通方案——不要通过禁用 Web 安全来绕过重定向。这与第三方支付 iframe(Stripe/PayPal)不同;对于后者,应使用 cy.intercept 进行存根,绝不要访问 iframe 内部。
cy.origin 示例请参阅 references/intercept-patterns.md(跨源流程)。
CI 集成
Action 版本: 固定使用 cypress-io/github-action@v7(最新版本为 7.2.0,2026 年 5 月)。v7 在 Node 24 下运行,是当前主版本;仅在 Node 20 运行器上使用 @v6(旧版分支)。
Cypress / Node 支持情况: 当前版本为 Cypress 15.x,支持 Node 20、22 和 24(已停止支持 Node 18 和 23)。未来 Cypress 16 / action-v7.2 对 Node 20 的移除计划,是在跟进 Node 20 的 EOL(2026-04-30),并非 Cypress 15 已经停止支持。
- 使用 Cypress Cloud: 设置
projectId,运行npx cypress run --record --key $CYPRESS_RECORD_KEY,并通过容器矩阵(fail-fast: false)并行运行,以检测不稳定测试、使用 Test Replay 和分析功能。 - 不使用 Cloud: 使用
cypress-io/github-action@v7配置build/start/wait-on,并在失败时将cypress/screenshots+cypress/videos作为构建产物上传。
两种完整的 GitHub Actions 工作流请参阅 references/ci-recipes.md。
**Cypress AI(付费 Cloud 附加组件,2026 年正式发布)**提供 Auto Heal(选择器自愈)、AI Test Generation 和 AI Bug Triage。现已正式发布,值得了解:cy.prompt(通过自然语言英语编写测试并在运行时自愈)和 Cloud MCP(2026 年 5 月正式发布,所有 Cloud 计划均免费)——一个 MCP 服务,可将已录制运行中的错误、堆栈跟踪和 Test Replay 链接提供给 AI 助手。这与 test-reliability(选择器自愈)、ai-bug-triage(失败聚类)和 ai-test-generation(测试编写)存在功能重叠。如果团队已在使用 Cypress Cloud,购买附加组件可能比自行构建同等功能更划算——在选择框架时请将其列入考量。
反模式
1. 使用 cy.wait(milliseconds) 进行同步
// BAD
cy.get('[data-testid="submit"]').click();
cy.wait(3000);
// GOOD -- wait for network
cy.intercept('POST', '/api/submit').as('submit');
cy.get('[data-testid="submit"]').click();
cy.wait('@submit');
仅在测试节流/防抖时可以接受。其他情况都应等待网络别名或 DOM 断言。
2. 根据 DOM 状态进行条件测试
不要通过检查 $body.find(selector).length > 0 来执行条件操作。应确定性地控制状态——对驱动条件元素的 API 进行存根处理。
3. 使用 CSS 选择器而不是数据属性
cy.get('.btn.btn-primary > span') 会在每次 CSS 重构时失效。请使用 cy.getByTestId('submit') 或 cy.contains('button', 'Place Order')。
4. 在测试之间共享状态
在一个 it() 中设置模块级变量 let orderId,再在另一个 it() 中读取,会导致测试依赖执行顺序,且无法安全并行运行。每个测试都应在 beforeEach 中通过 cy.request 或 cy.task 设置自己的数据。
5. 测试第三方 iframe
不要访问 Stripe/PayPal iframe 内部。使用 cy.intercept 模拟支付 API,并对自己的 UI 进行断言。
6. 登录时未使用 cy.session()(或遗漏 validate())
在每个测试中都通过 UI 登录既缓慢又脆弱。使用 cy.session 通过 API 进行一次身份验证并缓存会话;同时添加 validate() 回调,以免令牌过期后仍悄无声息地复用失效会话。
7. 在 addQuery 中使用箭头函数
使用 addQuery('name', (arg) => { ... }) 编写的自定义查询会悄无声息地丢失重试超时,因为 Cypress 需要 this。请改用 function (arg) { ... }。
8. 在 CI 中串行运行所有测试
套件运行时间超过 5 分钟后就应并行化——可使用 Cypress Cloud、cypress-split,或在 CI 矩阵中手动分片。
失败模式
| 症状 | 可能原因 | 修复方法 |
|---|---|---|
element is detached from the DOM | 重新渲染后复用了已返回的元素 | 在 .should/.then 中重新查询,而不是持有旧引用 |
cy.intercept 未匹配/别名始终无法解析 | 方法或 glob 有误,或在操作触发后才注册了拦截 | 在触发命令之前注册拦截;核对方法和 URL glob |
重定向时出现 cross origin 错误 | 登录或流程跳转到了另一个域名 | 将另一个源上的命令放入 cy.origin;不要禁用 chromeWebSecurity |
| 会话被复用,但用户已退出登录 | cy.session 没有 validate(),令牌已过期 | 添加一个访问已验证身份端点的 validate() 回调 |
| 自定义查询始终不超时/无限重试 | addQuery 回调是箭头函数 | 改为 function () {},以便 Cypress 绑定 this |
验证
结束前请确认测试套件能够运行:
npx cypress verify— 确认已安装 Cypress 二进制文件且可以运行。npx cypress run --spec "cypress/e2e/<file>.cy.ts"— 应以状态码 0 退出(无头模式,在 CI 模式下)。npx cypress run --component --spec "cypress/component/<File>.cy.tsx"— 组件测试应以状态码 0 退出。npx tsc --noEmit— 确认index.d.ts中的自定义命令声明可通过测试文件编译。
完成标准
- 存在
cypress.config.ts,其中的baseUrl从环境变量读取(而非在 CI 中硬编码为localhost),并显式设置viewportWidth/viewportHeight;npx cypress verify通过。 - 自定义命令已提取到
cypress/support/commands.ts,并在cypress/support/index.d.ts中提供 TypeScript 声明;npx tsc --noEmit以状态码 0 退出。 login命令使用带validate()回调的cy.session。- 套件中没有用于同步的
cy.wait(<number>)(grep -rn "cy.wait([0-9]" cypress/除文档记录的 throttle/debounce 场景外不返回任何内容)。 - 组件测试位于
cypress/component/**/*.cy.tsx下,并通过npx cypress run --component运行且以状态码 0 退出。 - E2E 测试在 CI 中通过(
npx cypress run以状态码 0 退出),并且有 Cypress Cloud 运行记录(并行运行),或在失败时上传本地视频/截图制品。
参考文件(位于 references/ 中)
- config-and-commands.md — 项目目录树、完整的
cypress.config.ts,以及包含 TypeScript 声明的自定义命令(cy.session+validate()、非箭头函数形式的addQuery)。 - intercept-patterns.md — 所有
cy.intercept示例(存根、监听、有条件/轮询、错误模拟、响应修改、基于 fixture),以及使用cy.origin的跨域流程。 - component-and-fixtures.md — React 组件测试套件以及数据驱动测试(静态 fixture、使用
cy.task填充数据、特定环境的配置)。 - ci-recipes.md — 使用和不使用 Cypress Cloud 的 GitHub Actions 工作流,基于
@v7,包含并行化和制品上传。
相关技能
- playwright-automation — 如果测试套件使用的是 Playwright 而非 Cypress,请改用此技能。E2E 目标相同,但运行器和 API 不同。
- test-reliability — 前往此处了解运行时的逐测试不稳定问题修复、自愈定位器和隔离。此技能用于编写稳定的测试;该技能用于修复失败的测试。
- selector-drift-recovery — 在 UI 重构或重新设计后,批量重新生成失效的选择器;此技能用于编写测试,而非批量修复。
- test-migration — 将 Selenium 或其他测试套件迁移到 Cypress。
- ci-cd-integration — 用于在 GitHub Actions / GitLab CI 中运行 Cypress 的流水线模板、并行化和工件管理。
- visual-testing — 通过视觉回归测试补充 Cypress 功能测试;Cypress 不内置像素对比功能。
- unit-testing — 使用 Jest/Vitest 测试无需浏览器的逻辑;Cypress 组件测试则填补单元测试与 E2E 测试之间的空白。
- test-data-management — 为 Cypress 测试准备、管理和清理所用的测试数据。
- qa-project-context — 记录框架选择、CI 平台和约定的项目上下文文件。