一份关于强大的端到端测试框架 Cypress 的综合指南,内容涵盖安装、编写测试、调试、CI/CD 集成以及最佳实践。
Cypress:Web 应用终极端到端测试指南
在当今快速发展的 Web 开发领域,确保 Web 应用的质量和可靠性至关重要。端到端(E2E)测试在从用户角度验证应用所有组件能否无缝协同工作方面扮演着关键角色。Cypress 已成为领先的 E2E 测试框架,它提供了对开发者友好的体验、强大的功能和卓越的性能。本综合指南将引导您了解开始使用 Cypress 并有效测试您的 Web 应用所需的一切知识。
什么是 Cypress?
Cypress 是为现代 Web 构建的下一代前端测试工具。与在浏览器中运行测试的传统测试框架不同,Cypress直接在浏览器中运行,让您对应用的行为拥有无与伦比的控制力和可见性。它的设计宗旨是快速、可靠且易于使用,这使其成为全球开发者和 QA 工程师的热门选择。Cypress 使用 JavaScript 编写并在浏览器内执行,这使其性能非常高,并能提供对应用内部无与伦比的访问权限。
使用 Cypress 的主要优势
- 开发者友好: Cypress 提供简洁直观的 API,使编写和调试测试变得容易。
- 时间旅行: Cypress 在每个测试命令执行期间都会为您的应用状态拍摄快照,让您可以回溯时间,精确查看任何时间点发生的事情。
- 实时重载: 当您对测试文件进行更改时,Cypress 会自动重载,提供即时反馈。
- 自动等待: Cypress 在执行操作前会自动等待元素变为可见或可交互状态,无需显式等待。
- 网络控制: Cypress 允许您对网络请求和响应进行打桩,从而能够模拟不同场景并测试应用的错误处理能力。
- 可调试性: Cypress 提供出色的调试工具,包括功能强大的调试器和详细的错误信息。
- 跨浏览器测试: Cypress 支持多种浏览器,包括 Chrome、Firefox、Edge 和 Electron。
- 无头测试: 在无头模式下运行测试,以便在 CI/CD 环境中更快地执行。
- 内置断言: Cypress 提供了一套丰富的内置断言,用于验证应用的预期行为。
安装与设置
开始使用 Cypress 非常简单。以下是安装方法:
- 先决条件: 确保您的系统上已安装 Node.js 和 npm(Node 包管理器)。您可以从 Node.js 官网下载它们。
- 安装 Cypress: 打开您的终端或命令提示符,导航到您的项目目录,并运行以下命令:
- 打开 Cypress: 安装完成后,您可以通过运行以下命令打开 Cypress 测试运行器:
npm install cypress --save-dev
npx cypress open
此命令将启动 Cypress 测试运行器,它提供了一个用于运行和调试测试的图形界面。
编写您的第一个 Cypress 测试
让我们创建一个简单的测试来验证网站主页是否能正确加载。在您项目的 `cypress/e2e` 目录下创建一个名为 `example.cy.js` 的新文件。
// cypress/e2e/example.cy.js
describe('My First Test', () => {
it('Visits the Kitchen Sink', () => {
cy.visit('https://example.cypress.io')
cy.contains('type').click()
cy.url().should('include', '/commands/actions')
cy.get('.action-email')
.type('fake@email.com')
.should('have.value', 'fake@email.com')
})
})
让我们来分解一下这个测试:
- `describe()`:定义一个测试套件,它是一组相关测试的集合。
- `it()`:在测试套件中定义一个单独的测试用例。
- `cy.visit()`:导航到指定的 URL。
- `cy.contains()`:查找包含指定文本的元素。
- `.click()`:点击选定的元素。
- `cy.url()`:获取页面的当前 URL。
- `.should()`:对应用状态进行断言。
- `cy.get()`:使用 CSS 选择器选择一个元素。
- `.type()`:在选定的元素中输入文本。
- `.should('have.value', 'fake@email.com')`:断言该元素的值等于 'fake@email.com'。
在 Cypress 测试运行器中运行此测试以查看其效果。您应该会看到浏览器导航到 Cypress Kitchen Sink 网站,点击 “type” 链接,并验证 URL。
Cypress 命令
Cypress 提供了广泛的命令用于与您的应用进行交互。以下是一些最常用的命令:
- `cy.visit(url)`: 导航到指定的 URL。
- `cy.get(selector)`: 使用 CSS 选择器选择一个元素。
- `cy.contains(content)`: 选择包含指定文本的元素。
- `cy.click()`: 点击选定的元素。
- `cy.type(text)`: 在选定的元素中输入文本。
- `cy.clear()`: 清除输入框或文本域元素的内容。
- `cy.submit()`: 提交一个表单。
- `cy.check()`: 选中一个复选框或单选按钮。
- `cy.uncheck()`: 取消选中一个复选框。
- `cy.select(value)`: 从下拉列表中选择一个选项。
- `cy.scrollTo(position)`: 将页面滚动到指定位置。
- `cy.trigger(event)`: 在选定元素上触发一个 DOM 事件。
- `cy.request(url, options)`: 向指定的 URL 发出 HTTP 请求。
- `cy.intercept(route, handler)`: 拦截与指定路由匹配的 HTTP 请求。
- `cy.wait(time)`: 等待指定的时间。
- `cy.reload()`: 重新加载当前页面。
- `cy.go(direction)`: 在浏览器历史记录中导航到上一页或下一页。
- `cy.url()`: 获取页面的当前 URL。
- `cy.title()`: 获取页面的标题。
- `cy.window()`: 获取 window 对象。
- `cy.document()`: 获取 document 对象。
- `cy.viewport(width, height)`: 设置视口大小。
这些只是 Cypress 中众多可用命令的一部分。有关命令及其选项的完整列表,请参阅 Cypress 文档。
Cypress 中的断言
断言用于验证您的应用的预期行为。Cypress 提供了一套丰富的内置断言,您可以用它来检查元素的状态、URL、标题等。断言使用 `.should()` 方法链接在 Cypress 命令之后。
以下是一些常见的断言示例:
- `.should('be.visible')`: 断言元素是可见的。
- `.should('not.be.visible')`: 断言元素是不可见的。
- `.should('be.enabled')`: 断言元素是启用的。
- `.should('be.disabled')`: 断言元素是禁用的。
- `.should('have.text', 'expected text')`: 断言元素具有指定的文本。
- `.should('contain', 'expected text')`: 断言元素包含指定的文本。
- `.should('have.value', 'expected value')`: 断言元素具有指定的值。
- `.should('have.class', 'expected class')`: 断言元素具有指定的类。
- `.should('have.attr', 'attribute name', 'expected value')`: 断言元素具有指定的属性和值。
- `.should('have.css', 'css property', 'expected value')`: 断言元素具有指定的 CSS 属性和值。
- `.should('have.length', expected length)`: 断言元素具有指定的长度(例如,列表中的元素数量)。
您还可以创建自定义断言以满足您的特定需求。
编写 Cypress 测试的最佳实践
遵循最佳实践可以帮助您编写更易于维护、更可靠、更高效的 Cypress 测试。以下是一些建议:
- 编写清晰简洁的测试: 每个测试都应专注于一个特定的功能或场景。避免编写过于复杂、难以理解和维护的测试。
- 使用有意义的测试名称: 为您的测试提供描述性的名称,清楚地表明它们在测试什么。
- 避免硬编码值: 使用变量或配置文件来存储可能随时间变化的值。
- 使用自定义命令: 创建自定义命令来封装可重用逻辑,使您的测试更具可读性。
- 隔离测试: 每个测试都应独立于其他测试。避免依赖于先前测试留下的应用状态。
- 测试后清理: 在每个测试后重置应用状态,以确保后续测试从一个干净的状态开始。
- 使用数据属性: 在测试中使用数据属性(例如 `data-testid`)来选择元素。数据属性比 CSS 类或 ID 更不容易改变,使您的测试对 UI 的变化更具弹性。
- 避免显式等待: Cypress 会自动等待元素变为可见或可交互。除非绝对必要,否则避免使用显式等待(例如 `cy.wait()`)。
- 测试用户流程: 专注于测试用户流程而不是单个组件。这将帮助您确保应用从用户的角度看是正常工作的。
- 定期运行测试: 将 Cypress 测试集成到您的 CI/CD 管道中,并定期运行它们,以便在开发过程的早期发现错误。
Cypress 高级技巧
桩件 (Stubbing) 与模拟 (Mocking)
Cypress 允许您对网络请求和响应进行打桩,从而能够模拟不同场景并测试应用的错误处理能力。这对于测试依赖外部 API 或服务的功能特别有用。
要对网络请求进行打桩,您可以使用 `cy.intercept()` 命令。例如,下面的代码对 `/api/users` 的 GET 请求进行打桩,并返回一个模拟响应:
cy.intercept('GET', '/api/users', {
statusCode: 200,
body: [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Doe' }
]
}).as('getUsers')
然后,您可以使用 `cy.wait('@getUsers')` 等待被拦截的请求,并验证您的应用是否正确处理了模拟响应。
处理 Local Storage 和 Cookies
Cypress 提供了与 local storage 和 cookies 交互的命令。您可以在测试中使用这些命令来设置、获取和清除 local storage 和 cookies。
要设置一个 local storage 项,您可以使用 `cy.window()` 命令访问 window 对象,然后使用 `localStorage.setItem()` 方法。例如:
cy.window().then((win) => {
win.localStorage.setItem('myKey', 'myValue')
})
要获取一个 local storage 项,您可以使用 `cy.window()` 命令,然后使用 `localStorage.getItem()` 方法。例如:
cy.window().then((win) => {
const value = win.localStorage.getItem('myKey')
expect(value).to.equal('myValue')
})
要设置一个 cookie,您可以使用 `cy.setCookie()` 命令。例如:
cy.setCookie('myCookie', 'myCookieValue')
要获取一个 cookie,您可以使用 `cy.getCookie()` 命令。例如:
cy.getCookie('myCookie').should('have.property', 'value', 'myCookieValue')
处理文件上传
Cypress 提供了一个名为 `cypress-file-upload` 的插件,可以简化测试中的文件上传操作。要安装该插件,请运行以下命令:
npm install -D cypress-file-upload
然后,将以下行添加到您的 `cypress/support/commands.js` 文件中:
import 'cypress-file-upload';
然后您就可以使用 `cy.uploadFile()` 命令来上传文件。例如:
cy.get('input[type="file"]').attachFile('example.txt')
处理 IFrame
测试 IFrame 可能有些棘手,但 Cypress 提供了一种与之交互的方法。您可以使用 `cy.frameLoaded()` 命令等待 IFrame 加载完成,然后使用 `cy.iframe()` 命令获取 IFrame 的 document 对象。
cy.frameLoaded('#myIframe')
cy.iframe('#myIframe').find('button').click()
Cypress 与持续集成/持续部署 (CI/CD)
将 Cypress 集成到您的 CI/CD 管道中对于确保应用质量至关重要。您可以在 CI/CD 环境中以无头模式运行 Cypress 测试。方法如下:
- 安装 Cypress: 确保 Cypress 作为项目依赖项安装。
- 配置 CI/CD: 配置您的 CI/CD 管道,在每次构建后运行 Cypress 测试。
- 无头模式运行 Cypress: 使用 `cypress run` 命令以无头模式运行 Cypress 测试。
CI/CD 配置示例(使用 GitHub Actions):
name: Cypress Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
cypress-run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Install dependencies
run: npm install
- name: Cypress run
uses: cypress-io/github-action@v5
with:
start: npm start
wait-on: 'http://localhost:3000'
此配置将在代码被推送到 `main` 分支或针对 `main` 分支创建拉取请求时运行 Cypress 测试。`cypress-io/github-action` 这个 action 简化了在 GitHub Actions 中运行 Cypress 测试的过程。
调试 Cypress 测试
Cypress 提供了出色的调试工具,帮助您识别和修复测试中的问题。以下是一些调试 Cypress 测试的技巧:
- 使用 Cypress 测试运行器: Cypress 测试运行器提供了一个可视化界面,用于运行和调试您的测试。您可以逐个命令地单步执行测试,检查应用状态,并查看详细的错误信息。
- 使用 `cy.pause()` 命令: `cy.pause()` 命令会暂停测试的执行,并允许您在浏览器的开发者工具中检查应用的状态。
- 使用 `cy.debug()` 命令: `cy.debug()` 命令会将选定的元素打印到控制台,让您可以检查其属性和特性。
- 使用浏览器的开发者工具: 浏览器的开发者工具提供了关于您应用的大量信息,包括 DOM、网络请求和控制台日志。
- 仔细阅读错误信息: Cypress 提供详细的错误信息,可以帮助您确定错误原因。请注意错误消息和堆栈跟踪。
Cypress 与其他测试框架的比较
虽然 Cypress 是一个强大的端到端测试框架,但了解它与其他流行选项的比较至关重要。以下是简要概述:
- Selenium: Selenium 是一个广泛使用的自动化测试框架。虽然它很灵活并支持多种语言,但设置和维护可能很复杂。Cypress 提供了更简单、更对开发者友好的体验,尤其适用于基于 JavaScript 的应用。
- Puppeteer: Puppeteer 是一个 Node 库,它提供了一个高级 API 用于控制无头 Chrome 或 Chromium。它非常适合抓取数据和自动化浏览器任务,但与 Cypress 相比,进行端到端测试可能需要更多的手动配置。
- Playwright: Playwright 是由微软开发的另一个跨浏览器自动化框架。它与 Puppeteer 有相似之处,但提供了更广泛的浏览器支持。Cypress 拥有独特的时间旅行调试器和更集成的测试体验。
框架的选择取决于您项目的具体需求和要求。对于需要快速、可靠且对开发者友好的端到端测试的现代 Web 应用来说,Cypress 是一个绝佳的选择。
Cypress 实战示例
让我们探讨几个真实世界的例子,看看如何使用 Cypress 测试不同类型的 Web 应用:
测试电子商务应用
您可以使用 Cypress 来测试电子商务应用中的各种用户流程,例如:
- 搜索产品
- 将产品添加到购物车
- 结账并下单
- 管理账户设置
以下是一个 Cypress 测试示例,用于验证用户可以成功将产品添加到购物车:
it('Adds a product to the cart', () => {
cy.visit('/products')
cy.get('.product-card').first().find('button').click()
cy.get('.cart-count').should('have.text', '1')
})
测试社交媒体应用
您可以使用 Cypress 来测试社交媒体应用中的用户交互,例如:
- 创建新帖子
- 点赞帖子
- 评论帖子
- 关注其他用户
以下是一个 Cypress 测试示例,用于验证用户可以成功创建新帖子:
it('Creates a new post', () => {
cy.visit('/profile')
cy.get('#new-post-textarea').type('Hello, world!')
cy.get('#submit-post-button').click()
cy.get('.post').first().should('contain', 'Hello, world!')
})
测试银行应用
对于银行应用,Cypress 可用于测试关键功能,例如:
- 安全登录
- 查询账户余额
- 转账
- 管理收款人
一个验证资金转移的测试可能如下所示(为安全起见,使用了适当的打桩):
it('Transfers funds successfully', () => {
cy.visit('/transfer')
cy.get('#recipient-account').type('1234567890')
cy.get('#amount').type('100')
cy.intercept('POST', '/api/transfer', { statusCode: 200, body: { success: true } }).as('transfer')
cy.get('#transfer-button').click()
cy.wait('@transfer')
cy.get('.success-message').should('be.visible')
})
结论
Cypress 是一个功能强大且用途广泛的端到端测试框架,可以帮助您确保 Web 应用的质量和可靠性。其对开发者友好的 API、强大的功能和卓越的性能使其成为全球开发者和 QA 工程师的热门选择。通过遵循本指南中概述的最佳实践,您可以编写出有效的 Cypress 测试,帮助您在开发过程的早期发现错误,并向用户交付高质量的软件。
随着 Web 应用的不断发展,端到端测试的重要性只会与日俱增。拥抱 Cypress 并将其集成到您的开发工作流程中,将使您能够构建更健壮、更可靠、更友好的 Web 用户体验。