如何使用 Vue 3 + Quasar 2 实现端到端(E2E)测试
本文将讲解如何使用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.ts
和order.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测试有了更深入的理解。掌握这些知识,能够帮助大家更好地进行项目测试,有兴趣的测试友友们赶紧去试试吧。