E2E 测试:Cypress 入门
端到端(E2E)测试是验证 Vue 3 应用整体功能的重要手段,模拟真实用户行为,确保从界面到后端的完整流程按预期运行。Cypress 是一款现代化的 E2E 测试框架,以其简单易用、强大的调试能力和实时反馈受到广泛欢迎。本节将介绍 Cypress 的基本概念、安装配置和使用方法,并通过示例展示如何为 Vue 3 项目编写 E2E 测试,帮助你快速入门并提升应用质量。
什么是 E2E 测试?
E2E 测试(End-to-End Testing)是对整个应用的集成测试,从用户视角验证功能是否正确。它不同于单元测试,关注的是应用的外部行为而非内部实现。
为什么选择 Cypress?
- 简单易用:基于 JavaScript,API 直观。
- 实时调试:内置浏览器界面,可视化测试过程。
- 快照与时间旅行:记录每步状态,支持回溯。
- 无需额外配置:开箱即用,支持 Vue 3 项目。
安装与配置
安装
在 Vue 3 项目中添加 Cypress:
npm install -D cypress
初始化
运行命令生成 Cypress 配置和示例文件:
npx cypress open
- 生成结构:
cypress/ ├── e2e/ # 测试用例目录 │ └── example.cy.js # 示例测试 ├── support/ # 支持文件 │ ├── commands.js │ └── e2e.js └── cypress.config.js # 配置文件
配置 cypress.config.js
// cypress.config.js
import { defineConfig } from 'cypress';
export default defineConfig({
e2e: {
baseUrl: 'http://localhost:5173', // Vite 默认端口
specPattern: 'cypress/e2e/**/*.cy.{js,ts}', // 测试文件模式
setupNodeEvents(on, config) {
// 自定义事件
}
}
});
package.json
{
"scripts": {
"test:e2e": "cypress open",
"test:e2e:run": "cypress run"
}
}
项目结构
src/
├── components/
│ └── Counter.vue
├── cypress/
│ ├── e2e/
│ │ └── counter.cy.js
│ └── cypress.config.js
├── vite.config.js
└── package.json
基本使用
测试组件:Counter.vue
<!-- src/components/Counter.vue -->
<template>
<div>
<p data-testid="count">计数: {{ count }}</p>
<button data-testid="increment" @click="increment">增加</button>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const count = ref(0);
const increment = () => count.value++;
return { count, increment };
}
});
</script>
编写 E2E 测试
counter.cy.js
// cypress/e2e/counter.cy.js
describe('Counter Component', () => {
beforeEach(() => {
cy.visit('/'); // 访问根路径
});
it('displays initial count', () => {
cy.get('[data-testid="count"]').should('have.text', '计数: 0');
});
it('increments count when button is clicked', () => {
cy.get('[data-testid="increment"]').click();
cy.get('[data-testid="count"]').should('have.text', '计数: 1');
});
it('increments multiple times', () => {
cy.get('[data-testid="increment"]').click().click();
cy.get('[data-testid="count"]').should('have.text', '计数: 2');
});
});
运行测试
- 启动开发服务器:
npm run dev - 运行 Cypress:
npm run test:e2e- 打开 Cypress 界面,选择
counter.cy.js执行。
- 打开 Cypress 界面,选择
- 效果:浏览器显示测试过程,验证计数器功能。
命令行运行
npm run test:e2e:run
- 输出:终端显示测试结果。
核心测试技巧
1. 选择器与断言
- 使用 data-testid:
<p data-testid="count">{{ count }}</p>cy.get('[data-testid="count"]').should('contain', '计数: 0'); - 断言:
should('have.text', 'value'):验证文本。should('be.visible'):验证可见性。
2. 模拟用户交互
it('increments on button click', () => {
cy.get('[data-testid="increment"]').click();
cy.get('[data-testid="count"]').should('have.text', '计数: 1');
});
3. 测试异步行为
AsyncComp.vue
<template>
<p data-testid="data">{{ data }}</p>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
async setup() {
const data = ref('');
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
data.value = (await response.json()).title;
return { data };
}
});
</script>
测试
// cypress/e2e/asyncComp.cy.js
describe('AsyncComp', () => {
it('loads async data', () => {
cy.visit('/');
cy.get('[data-testid="data"]').should('not.be.empty');
cy.get('[data-testid="data"]').should('contain', 'delectus aut autem');
});
});
4. 测试路由导航
router/index.js
import { createRouter, createWebHistory } from 'vue-router';
const routes = [
{ path: '/', component: () => import('@/components/Counter.vue') },
{ path: '/async', component: () => import('@/components/AsyncComp.vue') }
];
export default createRouter({
history: createWebHistory(),
routes
});
测试
it('navigates to async page', () => {
cy.visit('/');
cy.get('[data-testid="count"]').should('have.text', '计数: 0');
cy.visit('/async');
cy.get('[data-testid="data"]').should('contain', 'delectus aut autem');
});
高级技巧
1. 自定义命令
support/commands.js
Cypress.Commands.add('incrementCounter', () => {
cy.get('[data-testid="increment"]').click();
});
使用
it('uses custom command', () => {
cy.visit('/');
cy.incrementCounter();
cy.get('[data-testid="count"]').should('have.text', '计数: 1');
});
2. Mock API 请求
- 拦截请求:
it('mocks API response', () => { cy.intercept('GET', 'https://jsonplaceholder.typicode.com/todos/1', { statusCode: 200, body: { title: 'Mocked Title' } }).as('getTodo'); cy.visit('/async'); cy.wait('@getTodo'); cy.get('[data-testid="data"]').should('contain', 'Mocked Title'); });
3. 截图与视频
- 自动记录:
- 运行
cypress run时生成视频(cypress/videos)。
- 运行
- 手动截图:
it('takes screenshot', () => { cy.visit('/'); cy.screenshot('home-page'); });
注意事项
- 测试环境:
- 确保开发服务器运行,避免端口冲突。
- 异步等待:
- 使用
cy.wait()或.should()确保状态稳定。
- 使用
- 覆盖范围:
- E2E 测试不需覆盖所有单元测试场景,聚焦关键流程。
整合到 CI
package.json
{
"scripts": {
"test:e2e:ci": "start-server-and-test 'vite' http://localhost:5173 'cypress run'"
}
}
- 安装依赖:
npm install -D start-server-and-test
总结
Cypress 为 Vue 3 提供了简单高效的 E2E 测试方案,通过直观的 API 和强大的调试工具,你可以轻松验证应用的整体功能。本节介绍了安装配置、基本测试和高级技巧,下一节将探讨项目打包与部署,带你完成开发的最后一步!
