Cypress 前端测试框架全面指南

Cypress 是一个现代化的前端测试工具,专为现代网络应用设计。与传统的 Selenium 等测试工具不同,Cypress 直接在浏览器中运行,提供了更快速、更可靠的测试体验。

2025年9月18日
DocsLib Team
Cypress前端测试自动化测试JavaScript

Cypress 前端测试框架全面指南

什么是Cypress?

Cypress 是一个现代化的前端测试工具,专为现代网络应用设计。与传统的 Selenium 等测试工具不同,Cypress 直接在浏览器中运行,提供了更快速、更可靠的测试体验。它已经成为前端开发者和测试工程师的首选工具之一。

Cypress 的主要特点

  1. 时间旅行:Cypress 在测试运行时记录快照,可以查看测试执行过程中每个步骤的状态
  2. 实时重载:修改测试代码后,Cypress 会自动重新运行测试
  3. 自动等待:无需手动添加等待或睡眠,Cypress 会自动等待元素出现或命令完成
  4. 网络流量控制:轻松模拟和拦截网络请求
  5. 一致的测试结果:专为现代网络应用设计,避免了传统测试工具的脆弱性
  6. 调试简单:直接从开发者工具调试测试失败
  7. 截图和视频:测试失败时自动截图,也可以录制整个测试过程的视频

安装与设置

前提条件

  • Node.js (建议使用最新LTS版本)
  • npm 或 yarn
  • 现代浏览器 (Chrome, Firefox, Edge, Electron)

安装步骤

  1. 创建项目目录(如果还没有):

    mkdir cypress-demo && cd cypress-demo
  2. 初始化 npm 项目:

    npm init -y
  3. 安装 Cypress:

    npm install cypress --save-dev
  4. 打开 Cypress:

    npx cypress open

第一次运行时会创建默认的 Cypress 文件夹结构:

/cypress
  /fixtures - 测试数据
  /integration - 测试文件
  /plugins - 插件配置
  /support - 可重用配置和命令

编写第一个测试

让我们创建一个简单的测试来验证网页标题。

  1. cypress/integration 文件夹中创建 first_test.spec.js 文件

  2. 添加以下代码:

describe('我的第一个Cypress测试', () => {
  it('访问网站并验证标题', () => {
    // 访问网站
    cy.visit('https://example.com')

    // 验证标题
    cy.title().should('include', 'Example Domain')
  })
})
  1. 保存文件后,Cypress 测试运行器会自动检测新测试

  2. 点击测试文件名运行测试

常用命令详解

元素选择与交互

// 通过CSS选择器获取元素
cy.get('#some-id')
cy.get('.some-class')
cy.get('button')

// 通过文本内容获取元素
cy.contains('Submit')

// 点击元素
cy.get('button').click()

// 输入文本
cy.get('input').type('Hello World')

// 清除输入
cy.get('input').clear()

// 选择下拉选项
cy.get('select').select('Option 1')

断言

// 元素存在性
cy.get('#element').should('exist')
cy.get('#nonexistent').should('not.exist')

// 元素可见性
cy.get('#element').should('be.visible')
cy.get('#element').should('not.be.visible')

// 元素属性
cy.get('#element').should('have.attr', 'href', '/page')
cy.get('#element').should('have.class', 'active')

// 元素文本
cy.get('#element').should('have.text', 'Hello')
cy.get('#element').should('contain', 'Hello')

// 元素数量
cy.get('li').should('have.length', 3)

导航

// 访问URL
cy.visit('/about')

// 返回上一页
cy.go('back')

// 前进
cy.go('forward')

// 重载页面
cy.reload()

网络请求

// 拦截和模拟API请求
cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers')

// 等待请求完成
cy.wait('@getUsers').its('response.statusCode').should('eq', 200)

// 验证请求参数
cy.wait('@getUsers').its('request.body').should('include', { name: 'John' })

高级功能

自定义命令

cypress/support/commands.js 中添加:

Cypress.Commands.add('login', (email, password) => {
  cy.get('#email').type(email)
  cy.get('#password').type(password)
  cy.get('#login-button').click()
})

然后在测试中使用:

cy.login('user@example.com', 'password123')

钩子函数

describe('钩子函数示例', () => {
  before(() => {
    // 在所有测试之前运行一次
    cy.log('测试套件开始')
  })

  after(() => {
    // 在所有测试之后运行一次
    cy.log('测试套件结束')
  })

  beforeEach(() => {
    // 在每个测试之前运行
    cy.log('测试开始')
  })

  afterEach(() => {
    // 在每个测试之后运行
    cy.log('测试结束')
  })

  it('测试1', () => {
    cy.log('测试1执行')
  })

  it('测试2', () => {
    cy.log('测试2执行')
  })
})

数据驱动测试

const testData = [
  { username: 'user1', password: 'pass1', expected: true },
  { username: 'user2', password: 'wrong', expected: false }
]

testData.forEach(({username, password, expected}) => {
  it(`测试登录 ${username}`, () => {
    cy.login(username, password)
    if (expected) {
      cy.get('.welcome-message').should('contain', username)
    } else {
      cy.get('.error-message').should('be.visible')
    }
  })
})

实际项目示例

让我们创建一个完整的测试套件来测试一个待办事项应用。

测试文件:todo_app.spec.js

describe('待办事项应用测试', () => {
  beforeEach(() => {
    // 每次测试前访问应用
    cy.visit('https://todomvc.com/examples/vue/')
  })

  it('应该添加新待办事项', () => {
    const newItem = '写Cypress测试'

    cy.get('.new-todo')
      .type(`${newItem}{enter}`)

    cy.get('.todo-list li')
      .should('have.length', 1)
      .last()
      .should('have.text', newItem)
  })

  it('应该标记待办事项为完成', () => {
    // 先添加两个事项
    cy.get('.new-todo').type('第一个事项{enter}')
    cy.get('.new-todo').type('第二个事项{enter}')

    // 标记第一个为完成
    cy.get('.todo-list li')
      .first()
      .find('.toggle')
      .check()

    // 验证已完成样式
    cy.get('.todo-list li')
      .first()
      .should('have.class', 'completed')
  })

  it('应该过滤已完成的事项', () => {
    // 添加三个事项
    cy.get('.new-todo').type('事项1{enter}')
    cy.get('.new-todo').type('事项2{enter}')
    cy.get('.new-todo').type('事项3{enter}')

    // 标记第二个为完成
    cy.get('.todo-list li')
      .eq(1)
      .find('.toggle')
      .check()

    // 点击"已完成"过滤器
    cy.contains('Completed').click()

    // 应该只看到一个
    cy.get('.todo-list li')
      .should('have.length', 1)
      .should('have.text', '事项2')
  })

  it('应该清除所有已完成事项', () => {
    // 添加两个事项
    cy.get('.new-todo').type('事项1{enter}')
    cy.get('.new-todo').type('事项2{enter}')

    // 标记第一个为完成
    cy.get('.todo-list li')
      .first()
      .find('.toggle')
      .check()

    // 点击清除按钮
    cy.contains('Clear completed').click()

    // 应该只剩下一个未完成
    cy.get('.todo-list li')
      .should('have.length', 1)
      .should('have.text', '事项2')
  })
})

最佳实践

  1. 使用数据属性而非CSS选择器:为测试元素添加 data-testid 属性,避免因样式变化导致测试失败

    <button data-testid="submit-button">Submit</button>
    cy.get('[data-testid="submit-button"]').click()
  2. 组织测试结构

    /cypress
      /integration
        /auth
          login.spec.js
          register.spec.js
        /dashboard
          overview.spec.js
          settings.spec.js
  3. 使用环境变量:在 cypress.json 中配置基础URL

    {
      "baseUrl": "http://localhost:3000",
      "env": {
        "apiUrl": "http://localhost:3001/api"
      }
    }

    然后在测试中使用:

    cy.visit('/about') // 访问 http://localhost:3000/about
    cy.request(Cypress.env('apiUrl') + '/users') // 访问 API
  4. 并行测试:使用 cypress-parallel 或 CI 服务来并行运行测试

  5. 视觉回归测试:集成 cypress-image-snapshot 进行视觉比较

常见问题与解决方案

1. 元素找不到

问题:测试失败因为元素不存在或不可见

解决方案

  • 确保元素已加载完成(Cypress 会自动等待)
  • 检查元素是否在 iframe 中(需要使用 cy.iframe() 插件)
  • 使用 cy.get(selector, { timeout: 10000 }) 增加等待时间

2. 跨域问题

问题:测试访问不同域的页面时失败

解决方案

  • cypress.json 中设置 "chromeWebSecurity": false
  • 或使用 cy.request() 直接访问API而不是UI

3. 测试不稳定

问题:测试有时通过有时失败

解决方案

  • 避免使用固定等待 cy.wait(1000),改用条件等待
  • 确保测试数据独立,不依赖其他测试的状态
  • 使用 cy.intercept() 稳定网络请求

持续集成

在 CI 环境中运行 Cypress 测试:

  1. 安装依赖:

    npm install cypress --save-dev
  2. 添加运行脚本到 package.json

    {
      "scripts": {
        "test": "cypress run"
      }
    }
  3. 示例 GitHub Actions 配置 (.github/workflows/cypress.yml):

    name: Cypress Tests
    on: [push]
    jobs:
      cypress-run:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout
            uses: actions/checkout@v2
          - name: Install dependencies
            run: npm install
          - name: Run Cypress
            uses: cypress-io/github-action@v2
            with:
              start: npm start
              wait-on: 'http://localhost:3000'

总结

Cypress是一个功能强大且开发者友好的测试框架,它改变了前端测试的方式。通过直接运行在浏览器中、提供实时反馈和强大的调试工具,Cypress使得编写和维护测试变得更加容易。无论是简单的单元测试还是复杂的端到端测试,Cypress都能提供出色的体验。

通过本教程,你已经学习了Cypress的基础知识、核心概念和一些高级技巧。现在你可以开始为你的项目编写可靠的自动化测试了。记住,良好的测试覆盖率不仅能提高代码质量,还能增强开发信心,使重构和添加新功能变得更加安全。

要了解更多信息,请访问Cypress官方文档

返回博客列表
感谢阅读!