本文将讲解如何使用Cypress对Vue 3 + Quasar 2项目开展端到端(E2E)测试,涵盖测试环境搭建、用例编写、常用API及实用技巧等方面。

一、技术框架与测试工具

本项目采用TypeScript作为主要开发语言,结合Vue 3的强大功能以及Composition API的便捷性进行开发,同时使用Quasar 2.15.1构建用户界面。在测试工具的选择上,选用了Cypress,它为E2E测试提供了丰富的功能和简洁的操作方式。此外,还需安装以下依赖:

  • @quasar/quasar-app-extension-testing-e2e-cypresst:用于Quasar测试集成,帮助在项目中更好地整合Cypress进行测试。
  • @cypress/code-coverage:用于统计测试的覆盖率,方便了解测试对代码的覆盖程度。
  • cypress:核心测试库,提供了一系列测试功能和API。
  • eslint-plugin-cypress:用于在TypeScript项目中对Cypress相关代码进行检查和规范。

二、根目录配置(cypress.config.ts)

在项目的根目录下,cypress.config.ts文件用于配置Cypress的各项参数。具体代码如下:

import registerCodeCoverageTasks from '@cypress/code-coverage/task' import { injectQuasarDevServerConfig } from '@quasar/quasar-app-extension-testing-e2e-cypress/cct-dev-server' import { defineConfig } from 'cypress' export default defineConfig({ // 测试数据存储路径,用于存放测试过程中需要用到的数据文件 fixturesFolder: 'test/cypress/fixtures', // 截图存储路径,测试过程中截图会保存在此目录 screenshotsFolder: 'test/cypress/screenshots', // 视频存储路径,录制的测试视频会存储在这里 videosFolder: 'test/cypress/videos', // Cypress Cloud项目标识符,方便在Cypress Cloud平台上管理项目测试 projectId: 'ecb187bc-5198-45a2-8da8-1c418e87363d', // 启用测试过程录屏,方便查看测试执行过程 video: true, e2e: { // 注册代码覆盖率检测插件,用于分析测试对代码的覆盖情况 setupNodeEvents(on, config) { registerCodeCoverageTasks(on, config) return config }, // 被测应用基础地址,这里是本地开发服务器地址 baseUrl: 'http://localhost:8080/', // 测试支撑文件路径,包含一些自定义的测试命令或辅助函数 supportFile: 'test/cypress/support/e2e.ts', // 测试文件匹配模式,指定哪些文件是测试文件,这里匹配test/cypress/e2e目录下的.cy.ts文件 specPattern: 'test/cypress/e2e/**/*.cy.{js,jsx,ts,tsx}', }, component: { // 注入Quasar框架的Vite开发服务器配置,确保组件测试环境正确 setupNodeEvents(on, config) { registerCodeCoverageTasks(on, config) return config }, // 组件测试的支撑文件路径 supportFile: 'test/cypress/support/component.ts', // 组件测试文件直接扫描src目录下的.cy.ts文件 specPattern: 'src/**/*.cy.{js,jsx,ts,tsx}', // 自定义组件测试的HTML模板,用于渲染组件进行测试 indexHtmlFile: 'test/cypress/support/component-index.html', // 注入Quasar的开发服务器配置,为组件测试提供服务 devServer: injectQuasarDevServerConfig(), }, }) 

三、测试用例编写与目录结构

项目中的测试用例主要存放在test/cypress/e2e目录下,例如home.cy.tsorder.cy.ts。整个测试相关的目录结构如下:

├─ test │ ├─ cypress │ │ ├─ e2e // 存放测试文件 │ │ │ ├─ home.cy.ts │ │ │ └─ order.cy.ts │ │ ├─ fixtures // 存放测试环境相关数据 │ │ │ └─ example.json │ │ ├─ screenshots // 保存测试过程中的截图 │ │ ├─ support // 放置支撑文件 │ │ │ ├─ commands.ts │ │ │ ├─ component-index.html │ │ │ ├─ component.ts │ │ │ └─ e2e.ts │ │ ├─ tsconfig.json │ │ ├─ videos // 保存测试过程录制的视频 │ │ └─ wrappers │ │ ├─ DialogWrapper.vue │ │ └─ LayoutContainer.vue 

四、Cypress常用API详解

(一)元素操作

在测试过程中,经常需要对页面元素进行各种操作。

  • cy.get(selector):通过选择器获取页面元素。例如cy.get('#submit-btn'),表示获取id为submit-btn的元素。
  • cy.contains(text):用于获取包含特定文本的元素。比如cy.contains('登录'),能找到页面上包含“登录”文本的元素。
  • .click():对获取到的元素进行点击操作。像cy.get('button').click(),就是点击页面上的按钮元素。
  • .type(text):在输入框中输入文本。例如cy.get('input').type('Hello'),会在找到的输入框中输入“Hello”。
  • .clear():清空输入框内容。如cy.get('input').clear(),可清空指定输入框。
  • .check() / .uncheck():用于勾选或取消勾选复选框。cy.get('[type="checkbox"]').check()表示勾选类型为checkbox的元素。
  • .select(value):选择下拉框中的选项。cy.get('select').select('option1')会选择下拉框中值为option1的选项。
  • .trigger(event):触发DOM事件。cy.get('div').trigger('mouseover')能对指定的div元素触发鼠标悬停事件。

(二)导航与路由

Cypress提供了一系列方法来模拟页面导航和路由操作。

  • cy.visit(url):用于访问指定的页面。例如cy.visit('/login'),会访问项目中的登录页面。
  • cy.go(direction):实现浏览器的前进或后退操作。cy.go('back')表示返回上一页。
  • cy.reload():重新加载当前页面。cy.reload(true)可以强制重新加载页面。
  • cy.intercept(method, url):拦截网络请求。cy.intercept('GET', '/api/data').as('getData')表示拦截对/api/data的GET请求,并将其命名为getData ,之后可以通过cy.wait('@getData').its('response.statusCode').should('eq', 200)来验证该请求的响应状态码是否为200。

(三)断言与验证

断言是测试中用于验证预期结果的重要手段。

  • should(chainers):用于断言元素的状态。比如cy.get('h1').should('have.text', 'Welcome'),验证h1元素的文本内容是否为“Welcome”;cy.get('.list').should('have.length', 5),检查类名为list的元素数量是否为5。
  • cy.url():用于验证当前页面的URL。cy.url().should('include', '/dashboard'),判断当前URL是否包含/dashboard
  • cy.title():验证页面标题。cy.title().should('eq', 'Home'),检查页面标题是否为“Home”。
  • cy.wrap(value):包装对象以便进行断言。cy.wrap({ name: 'John' }).its('name').should('eq', 'John'),验证包装对象的name属性是否为“John”。

(四)调试与日志

在测试过程中,调试和记录日志有助于排查问题。

  • cy.log(message):输出日志信息。cy.log('正在执行登录操作'),会在测试日志中记录“正在执行登录操作”。
  • cy.pause():暂停测试执行,方便检查中间状态。
  • cy.debug():进入调试模式,例如cy.get('input').debug(),可以在调试模式下查看输入框元素相关信息。
  • cy.screenshot():截取屏幕截图。cy.screenshot('login-page'),会截取当前屏幕并保存为login-page截图。

(五)文件与数据

在测试中,处理文件和数据是常见需求。

  • cy.fixture(filePath):加载测试数据文件。cy.fixture('user.json').then((user) => { cy.get('input').type(user.name) }),从user.json文件中读取数据,并在输入框中输入用户名。
  • cy.readFile(path):读取本地文件。如cy.readFile('cypress/fixtures/data.txt'),读取指定路径的文件内容。
  • cy.writeFile(path, content):写入文件。cy.writeFile('logs.txt', '测试完成'),会在logs.txt文件中写入“测试完成”。

(六)浏览器控制

Cypress还提供了控制浏览器行为的方法。

  • cy.viewport(width, height):设置浏览器视口尺寸。cy.viewport('iphone-6')可使用预设的iPhone 6设备尺寸;cy.viewport(1024, 768)则可以自定义视口尺寸。
  • cy.scrollTo(position):用于滚动页面。cy.scrollTo('bottom')会将页面滚动到底部。
  • cy.clearCookies():清除浏览器中的Cookies。

(七)钩子函数

钩子函数可以在测试的不同阶段执行特定操作。

  • before(() => {}):在所有测试用例执行前执行一次。例如before(() => cy.resetDatabase()),在所有测试开始前重置数据库。
  • beforeEach(() => {}):在每个测试用例执行前都会执行。beforeEach(() => cy.login()),每次测试前都会执行登录操作。
  • afterEach(() => {}):在每个测试用例执行后执行。afterEach(() => cy.screenshot()),每次测试后截取屏幕截图。
  • after(() => {}):在所有测试用例执行后执行一次。after(() => cy.clearCookies()),所有测试结束后清除Cookies。

五、常用技巧分享

(一)链式调用

Cypress支持链式调用,使测试代码更加简洁和易读。例如cy.get('form').find('input').first().type('test@example.com '),先获取表单元素,再找到其中的输入框,选择第一个输入框并输入内容。

(二)自定义命令

可以通过自定义命令来封装一些常用的测试操作。例如:

Cypress.Commands.add('login', (email, password) => { cy.visit('/login') cy.get('#email').type(email) cy.get('#password').type(password) cy.get('form').submit() }) 

在测试中就可以使用cy.login('user@test.com', 'pass123')来执行登录操作。

(三)动态等待

在测试中,有时需要等待某些元素出现或消失。cy.get('.loading', { timeout: 10000 }).should('not.exist')表示等待类名为loading的元素在10秒内消失,如果10秒内元素未消失则测试失败。

通过上述内容,相信你对Vue 3 + Quasar 2项目的E2E测试有了更深入的理解。掌握这些知识,能够帮助大家更好地进行项目测试,有兴趣的测试友友们赶紧去试试吧。