mcpField
C
cypress-automation

cypress-automation

github.com/petrkindlmann测试与质量2221.0k 次安装6 天前更新
代码仓库

关于 cypress-automation

cypress-automation 是面向编写 Cypress TypeScript 测试套件的技能,涵盖端到端与组件测试。它强调命令队列和重试机制,并通过网络拦截与别名等待减少不稳定测试。

主要功能

  1. 01Cypress 命令队列与重试机制
  2. 02网络请求拦截与断言
  3. 03端到端和组件测试
  4. 04自定义命令与会话登录
  5. 05跨域认证流程
  6. 06CI 与 Cypress Cloud 配置

适用场景

  1. 01编写稳定的端到端测试
  2. 02在浏览器中隔离测试组件
  3. 03模拟 API 响应和网络错误
  4. 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.md
component-and-fixtures.md
config-and-commands.md
intercept-patterns.md

详细介绍

使用 TypeScript 编写生产级 Cypress 测试套件。它可以避免以下问题:把 Cypress 命令当作同步命令编写测试(将 `cy.get()` 存入变量、使用 `await cy.click()`),以及用 `cy.wait(3000)` 而不是网络别名来等待,从而导致测试不稳定。本技能涵盖其心智模型(命令队列、重试能力)、项目结构、自定义命令、使用 `cy.intercept` 控制网络、组件测试、使用 `cy.origin` 处理跨源身份验证,以及 Cypress Cloud / CI 集成。

快速导航

你需要……前往
编写 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
存根、监视、模拟错误或轮询 APIcy.intercept 模式 + references/intercept-patterns.md
在 CI 中运行 / 在 Cypress Cloud 上并行运行CI 集成 + references/ci-recipes.md
处理 SSO / OAuth 重定向跨源流程 + references/intercept-patterns.md

探索问题

先检查 .agents/qa-project-context.md——如果该文件存在,就使用其中的信息,并跳过已回答的问题。

  1. 组件测试、E2E,还是两者都需要? 组件测试会在隔离环境中挂载单个组件;E2E 则通过浏览器测试整个应用。大多数项目两者都需要。组件测试需要针对具体框架的挂载方式(React、Vue、Angular、Svelte)。
  2. 是否使用 Cypress Cloud? Cloud 提供并行运行、波动检测、分析、Test Replay 和 AI 插件。如果团队使用它,请配置 projectId 和记录密钥。否则,所有测试都可以在本地或 CI 中运行,无需 Cloud。
  3. 是否使用 TypeScript? 强烈推荐,本指南也默认使用 TypeScript——Cypress 原生支持它。所有示例均使用 TypeScript。
  4. 使用什么框架和打包工具? React + Vite、Next.js + Webpack、Vue + Vite、Angular——组件测试配置取决于这些选择。
  5. 是否涉及跨源身份验证? 如果登录会重定向到其他域名(SSO、OAuth 提供方),就需要使用 cy.origin。请提前说明,以便据此构建登录命令。
  6. 现有测试套件还是从头开始? 如果正在迁移,请从最不稳定或最关键的测试开始,不要一次性全部重写(参见 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) 会等待元素数量达到 5
  • cy.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 平台和约定的项目上下文文件。

评论

支持 Markdown