框架与库
- 使用 TypeScript 作为主要开发语言
- 使用 Vue 3 + Composition API
- 使用 quasar 2.15.1
- 测试工具库:cypress
需要安装的依赖
- @quasar/quasar-app-extension-testing-e2e-cypresst // quasar测试集成
- @cypress/code-coverage // 覆盖率
- cypress // 测试库
- eslint-plugin-cypress // TS
根目录配置(cypress.config.ts)
javascript
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', // 视频存储路径
projectId: 'ecb187bc-5198-45a2-8da8-1c418e87363d', // Cypress Cloud项目标识符
video: true, // 启用测试过程录屏
e2e: {
setupNodeEvents(on, config) { // 注册代码覆盖率检测插件
registerCodeCoverageTasks(on, config)
return config
},
baseUrl: 'http://localhost:8080/', // 被测应用基础地址(本地开发服务器)
supportFile: 'test/cypress/support/e2e.ts', // 测试支撑文件路径
specPattern: 'test/cypress/e2e/**/*.cy.{js,jsx,ts,tsx}', // 测试文件匹配模式(匹配test/cypress/e2e目录下的.cy.ts文件)
},
component: { // 组件测试(component)配置
setupNodeEvents(on, config) { // 注入Quasar框架的Vite开发服务器配置
registerCodeCoverageTasks(on, config)
return config
},
supportFile: 'test/cypress/support/component.ts',
specPattern: 'src/**/*.cy.{js,jsx,ts,tsx}', // 组件测试文件直接扫描src目录下的.cy.ts文件
indexHtmlFile: 'test/cypress/support/component-index.html', // 自定义组件测试的HTML模板
devServer: injectQuasarDevServerConfig(),
},
})
测试用例编写
arduino
目录结构
├─ 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
常用API
一、元素操作
csharp
cy.get(selector)
通过选择器获取元素
vbnet
cy.get('#submit-btn')
cy.contains(text)
获取包含文本的元素
scss
cy.contains('登录')
.click()
点击元素
scss
cy.get('button').click()
.type(text)
输入文本
bash
cy.get('input').type('Hello')
.clear()
清空输入框
csharp
cy.get('input').clear()
.check()
/ .uncheck()
勾选/取消复选框
csharp
cy.get('[type="checkbox"]').check()
.select(value)
选择下拉框选项
csharp
cy.get('select').select('option1')
.trigger(event)
触发DOM事件
csharp
cy.get('div').trigger('mouseover')
二、导航与路由
arduino
cy.visit(url)
访问页面
arduino
cy.visit('/login')
cy.go(direction)
浏览器前进/后退
go
cy.go('back')
cy.reload()
重新加载页面
scss
cy.reload(true)
cy.intercept(method, url)
拦截网络请求
csharp
cy.intercept('GET', '/api/data').as('getData')
cy.wait('@getData').its('response.statusCode').should('eq', 200)
三、断言与验证
scss
.should(chainers)
断言元素状态
csharp
cy.get('h1').should('have.text', 'Welcome')
cy.get('.list').should('have.length', 5)
cy.url()
验证当前URL
scss
cy.url().should('include', '/dashboard')
cy.title()
验证页面标题
lua
cy.title().should('eq', 'Home')
cy.wrap(value)
包装对象进行断言
lua
cy.wrap({ name: 'John' }).its('name').should('eq', 'John')
四、调试与日志
arduino
cy.log(message)
输出日志
arduino
cy.log('正在执行登录操作')
cy.pause()
暂停测试
scss
cy.pause()
cy.debug()
进入调试模式
scss
cy.get('input').debug()
cy.screenshot()
截取屏幕
arduino
cy.screenshot('login-page')
五、文件与数据
scss
cy.fixture(filePath)
加载测试数据
scss
cy.fixture('user.json').then((user) => {
cy.get('input').type(user.name)
})
cy.readFile(path)
读取本地文件
lua
cy.readFile('cypress/fixtures/data.txt')
cy.writeFile(path, content)
写入文件
arduino
cy.writeFile('logs.txt', '测试完成')
六、浏览器控制
arduino
cy.viewport(width, height)
设置视口尺寸
scss
cy.viewport('iphone-6') // 预设设备
cy.viewport(1024, 768) // 自定义尺寸
cy.scrollTo(position)
滚动页面
scss
cy.scrollTo('bottom')
cy.clearCookies()
清除Cookies
scss
cy.clearCookies()
七、钩子函数
scss
before(() => {})
所有测试前执行
scss
before(() => cy.resetDatabase())
beforeEach(() => {})
每个测试前执行
scss
beforeEach(() => cy.login())
afterEach(() => {})
每个测试后执行
scss
afterEach(() => cy.screenshot())
after(() => {})
所有测试后执行
scss
after(() => cy.clearCookies())
常用技巧
-
链式调用
cy.get('form') .find('input') .first() .type('[email protected]')
-
自定义命令
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('[email protected]', 'pass123')
-
动态等待
cy.get('.loading', { timeout: 10000 }).should('not.exist')