mochawesome如何合并测试报告_Vue项目采用Cypress做e2e自动化测试,手把手一撸到底...

本文介绍了如何在Vue项目中集成Cypress进行端到端测试,包括Cypress的安装、vue-cli的集成、运行示例、实战测试中的登录、配置及自定义命令。此外,文章还探讨了测试报告的生成,特别是使用mochawesome报告生成器,并分享了在Linux服务器上安装Cypress时可能遇到的问题及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Cypress 介绍

cypress是一款支持现代浏览器的端到端的自动化测试工具。

项目地址 :https://github.com/cypress-io/cypress

目前22.5k star,还是很受欢迎的。

官方文档相当给力,不懂的直接看官方文档更好

cypress安装

cypress核心概念

二、vue项目与cypress集成

已有项目集成

根据官方文档,直接执行如下命令即可

npm install -g vue-cli #先安装vue-cli

vue add @vue/e2e-cypress # 再安装插件

可视化创建全新项目集成

由于不熟悉cypress

我选择先通过可视化方式创建全新项目来快速体验

了解vue集成cypress的最小依赖

npm install -g vue-cli #先安装vue-cli

vue ui # 启动ui服务

执行以上命令启动vue-cli的可视化界面,会自动打开浏览器

image.png

然后创建一个带cypress测试的初始项目,预设选择手动,功能选e2e testing,配置选择cypress

配置选择cypress

然后点击创建项目,等待安装依赖。(时间会比较久,耐心等待,因为下载cypress比较慢)

image.png

进入这个页面之后,vue ui 可以关掉了。项目已经创建并安装好依赖。

image.png

三、运行示例

npm run test:e2e

此命令会先启动vue的服务(http://localhost:8081/)

然后再启动Cypress

DONE Compiled successfully in 8729ms

App running at:

- Local: http://localhost:8081/

- Network: http://192.168.3.114:8081/

App is served in production mode.

Note this is for preview or E2E testing only.

image.png

点击test.js即可看到测试效果

image.png

describe('My First Test', () => { // 一组测试

it('Visits the app root url', () => { //一个测试单元

cy.visit('/') // 打开 / 页面

cy.contains('h1', 'Welcome to Your Vue.js App') //查找

welcome...

,如果没有找到,会不断重试,直到找到(测试成功)或者4秒超时(测试失败)

})

})

四、实战测试

1. 测试目标

2. 修改启动命令

npm run test:e2e 实际上执行的是vue-cli-service test:e2e

通过给这个命令加--url 参数可以不启动vue项目直接测试目标url地址

vue-cli-service test:e2e --url http://qiniu.veryreader.com/D2CrudPlusExample/

你可以将此命令配置到package.json里面

"scripts": {

"test:e2e": "vue-cli-service test:e2e",

"test.url:e2e": "vue-cli-service test:e2e --url http://qiniu.veryreader.com/D2CrudPlusExample/"

},

然后执行如下命令即可

npm run test.url:e2e

3. 编写一个登录测试

specs目录下创建login.js

describe('登录', () => {

it('测试登录', () => {

const username = 'admin'

const password = 'admin'

cy.visit('/#/login')

cy.contains('button.button-login', '登录') // 查找button.button-login里包含登录字符串的元素,如果查找不到则失败

cy.get('input[placeholder="用户名"]') //获取input框,写法与jQuery的selector一致

.clear()

.type(username) // input框里面输入用户名

.should('have.value', username) // 断言 input的value=username

// 输入密码

cy.get('input[placeholder="密码"]')//获取input框,写法与jQuery的selector一致

.clear()

.type(password)

.should('have.value', password)

// 提交表单

cy.get('button.button-login').click() //查找按钮,然后点击

cy.contains('首页') //校验是否登录成功

})

})

测试成功

4. cypress.json配置文件

测试窗口太小,滚动条都出来了,可以按如下修改测试浏览器窗口大小

修改 cypress.json 文件

{

"pluginsFile": "tests/e2e/plugins/index.js",

"viewportWidth": 1920, //窗口宽度

"viewportHeight": 1080 //窗口高度

}

5. commond 命令

登录页面是每组测试都要跑一次的,每个测试文件里面都写那么一长串登录代码不现实

supports/commonds.js 中可以将多条测试命令组合成一条命令

Cypress.Commands.add('login', (username = 'admin', password = 'admin') => {

cy.visit('/#/login')

cy.contains('button.button-login', '登录')

cy.get('input[placeholder="用户名"]')

.clear()

.type(username)

.should('have.value', username)

// 输入密码

cy.get('input[placeholder="密码"]')

.clear()

.type(password)

.should('have.value', password)

// 提交表单

cy.get('button.button-login').click()

cy.contains('首页')

})

在测试用例中使用

test.js

describe('My First Test', () => {

it('Visits the app root url', () => {

cy.login('admin', 'admin') //调用 login 命令

})

})

6. before,beforeEach

describe('My First Test', () => {

before(() => {

cy.login()

cy.log('整个describe运行前运行一次,做一些准备工作')

})

beforeEach(() => {

cy.log('每个it之前都会执行,做一些准备工作')

})

it('Visits the app root url', () => {

cy.login('admin', 'admin')

})

afterEach(() => {

cy.log('每个it之后都会执行,做一些清理工作')

})

after(() => {

cy.login()

cy.log('整个describe运行完成后运行一次,做一些清理工作')

})

})

7. 测试一个crud页面

接下来我们要测试这个页面的添删改查功能。

image.png

// https://docs.cypress.io/api/introduction/api.html

describe('选择组件', () => {

before(() => {

cy.login() //测试开始前要登录

})

it('打开', () => {

cy.visit('/#/demo/form/select')

cy.wait(1000)

})

it('翻页', () => {

// 翻页

cy.log('翻页')

cy.get('.el-pagination ul.el-pager li').contains('2').click()

cy.checkId(context, '1', false) // 这是一个自定义命令,检查列表第一行id是否不为1

cy.get('.el-pagination ul.el-pager li').contains('1').click()

cy.checkId(context, '1') // 这是一个自定义命令,检查列表第一行id是否为1

})

it('添加', () => {

// 添加

cy.log('添加')

cy.openAdd(context) // 自定义命令,打开添加对话框

// 测试添加对话框里的表单选项

// 找到表单的选择框

cy.formItem('单选远程').find('.el-select').click()

cy.getSelectOptions().first().click() // 点击选择框,并选择第一项

// 点击单选框,选中第一项

cy.formItem('radio').find('.el-radio').first().click()

// 点击保存

cy.closeDialog(context) // 自定义命令,关闭对话框

// 检查是否保存成功

cy.checkId(context, '1', false) // 这是一个自定义命令,检查列表第一行id是否不为1,说明添加成功

// 校验其他列的值是否与添加表单时选的值一致

cy.checkColValue({ col: 2, value: '打开' }) // 校验列中展示的值是否是选择框里的第一项

cy.checkColValue({ col: 10, value: '打开' }) // 校验列中展示的值是否是radio里的第一项

})

it('编辑', () => {

cy.log('编辑')

// 打开编辑对话框

cy.openEdit(context) // 自定义命令,点击第一行的编辑按钮

// 测试表单对话框里的选项

// TODO

// 点击保存

cy.closeDialog(context) // 自定义命令

cy.wait(1000)

})

it('查看', () => {

cy.log('查看')

// 打开编辑对话框

cy.openView(context) // 自定义命令,点击第一行查看按钮

cy.closeDialog(context)// 自定义命令,点击保存

})

it('删除', () => {

cy.log('删除')

cy.doDelete(context) // 自定义命令,点击第一行的删除按钮

})

})

以上包含很多自定义命令,自定义命令封装了很多针对这个项目的通用操作

(只能用在这个项目的测试上,其他项目的命令需要另外自己写)

此处的自定义命令请见:github

image.png

8. 动态生成测试(通用骨架)

大部分页面都是crud,每个页面都有打开页面、翻页、添加、修改、删除。

其中只有添加和编辑对话框里的内容和列里面的内容不一样,其他都一样。

根据官方文档 动态生成测试 我们可以在describe 中动态生成it即可

封装之后我们只需要按如下编写少量的测试代码,即可测试大部分的crud页面了

test2.js

import { createCrudTest } from '../support/creator'

describe('选择组件', () => {

before(() => {

cy.login('admin', 'admin')

})

createCrudTest({

cy,

url: '/demo/form/select',

doAdd () {

//添加对话框要做的事

},

checkAdd () {

//添加成功后的检查,断言列里面的值与添加对话框里面选中的值一致

},

doEdit () {

//编辑对话框要做的事

},

checkEdit(){

//校验编辑是否成功

}

})

})

creator方法太长,请见 github

image.png

五 其他

1. 测试稳定性

1.1 断言

1.2 最佳实践(一定要看)

1.3 测试稳定性1

最佳实践中有讲,cy.wait()是不必要的

目前我的示例里面仍然有cy.wait 说明还有很大改进的空间

并且由于这些cy.wait的存在,使得我的测试用例的成功率变的有点捉摸不定。

所以一定要尽量消除cy.wait

1.4 测试稳定性2

我们要测试第一个img的src要等于https://xxxx.com/1

cy.get('div .el-image img').first().should($el=>{

expect($el.attr('src')).equal('https://xxxx.com/1')

})

其中img的创建是异步的。

当第二个img先创建,第一个img后创建,就会导致获取到第一个img的src=https://xxxx.com/2

然后断言失败

所以结果就是这个测试不稳定,时好时坏。

正确的写法是:先确保两个img都创建好了,再去下src的断言

cy.get('div .el-image img').should('have.length',2).first().should($el=>{

expect($el.attr('src')).equal('https://xxxx.com/1')

})

另外建议尽量少用first() 、last()等方法

first会打断重试链条,一旦first成功进入,之前的部分将不会被重试

2. 文件上传测试

//添加附加文件命令

Cypress.Commands.add(

'attachFile',

{

prevSubject: 'element'

},

(input, fileName, fileType) => {

return cy.fixture(fileName)

.then(content => Cypress.Blob.base64StringToBlob(content, fileType))

.then(blob => {

const testFile = new File([blob], fileName, { type: fileType })

const dataTransfer = new DataTransfer()

dataTransfer.items.add(testFile)

input[0].files = dataTransfer.files

return input

})

}

)

在/tests/e2e/fixtures放上要上传的文件logo.png

然后使用如下代码即可上传文件

cy.get('input[type=file]')

.attachFile('logo.png', 'image/png')

.trigger('change', { force: true })

3. runner选择器

在编写测试用例的过程中,很多时候我们需要找到元素的唯一选择器,来获取目标元素

image.png

4. debugger

cy.get('.xxxxx').then($el=>{ //$el 基本上就是一个jquery对象

debugger //即可进入调试,查看获取到的对象是否正确

})

5. 无头模式执行

给执行命令,添加 --headless参数, 将会不打开GUI,静默运行specs下的所有测试,并生成截图与视频,默认没有测试报告

{

scripts:{

"test.headless:e2e": "vue-cli-service test:e2e --headless --url http://qiniu.veryreader.com/D2CrudPlusExample/",

}

}

静默执行结果

image.png

六 测试报告

1. dashboard

官方提供了一个在线dashboard,用于查看测试结果,不过免费测试it数只有500个

点击runs,可以获得一串项目码

image.png

image.png

将--record 和 --key 加入到执行命令中,即可将测试结果上传到官方提供的dashboard上。

{

scripts:{

"test.dashboard:e2e": "vue-cli-service test:e2e --record --key 97e8d38c-3824-4cff-ab0d-3d04cbe107c7 --url http://qiniu.veryreader.com/D2CrudPlusExample/",

}

}

image.png

2. 报告生成器

下面是mochawesome测试报告的配置过程

1、安装依赖

npm install mocha mochawesome mochawesome-merge mochawesome-report-generator fs-extra -S -D

//或

yarn add mocha mochawesome mochawesome-merge mochawesome-report-generator fs-extra -S -D

2、 配置cypress.json

{

...

"reporter": "mochawesome",

"reporterOptions": {

"reportDir": "tests/e2e/results/reports",

"overwrite": false, //配置不覆盖,必须

"html": false,

"json": true, //必须

"toConsole": true

}

}

3、 执行脚本

创建 tests/e2e/report/index.js

const fse = require('fs-extra')

const { merge } = require('mochawesome-merge')

const generator = require('mochawesome-report-generator')

// const cypress = require('cypress')

async function runTests () {

await fse.remove('mochawesome-report')

// await cypress.run({ config: { baseUrl: 'http://localhost:8080/' } })

const options = {

files: [

// you can specify more files or globs if necessary:

'./tests/e2e/results/reports/*.json'

],

reportDir: './tests/e2e/results/'

}

const jsonReport = await merge(options)

// const totalFailed = jsonReport.stats.failures

await generator.create(jsonReport, options)

}

runTests()

4、 添加执行命令

package.json 添加执行命令

"scripts": {

"buildReport": "node tests/e2e/report/index.js"

},

5、 执行命令

# 先执行测试命令

npm run test.headless:e2e

# 再执行报告构建命令

npm run buildReport

报告文件就生成在 tests/e2e/results/mochawesome.html

合并测试报告

七 持续集成

cypress在linux服务器上安装比较慢的问题:

设置环境变量即可(仅支持cypress 3.8.3/4.9.0/5.0.0 这三个linux-x64版本)

export CYPRESS_DOWNLOAD_MIRROR=http://www.veryreader.com

echo $CYPRESS_DOWNLOAD_MIRROR

八 一些问题

1. 4.12.1版本的bug

升级cypress到4.12.1之后会持续重复请求静态文件,比如图片,js,css,然后奇慢无比。

issue中提到降级到4.9.0之后此问题消失

更新: 此问题在5.0.0仍没有改善

2. 更换cypress版本

目前官方vue插件对应的cypress版本是3.8.3

我这边改了一些版本

将@vue/cli-plugin-e2e-cypress

替换成如下依赖即可切换cypress版本

@d2-plus/vue-cli-plugin-e2e-cypress:4.5.3-3.8.3

@d2-plus/vue-cli-plugin-e2e-cypress:4.5.3-4.9.0 【没有8.1中说的问题】

@d2-plus/vue-cli-plugin-e2e-cypress:4.5.3-4.12.1

@d2-plus/vue-cli-plugin-e2e-cypress:4.5.3-5.0.0-1

3. linux上运行cypress问题还比较多

1、依赖安装问题(可以通过官方提供的docker-image解决)

2、在docker上运行又会引发共享内存不足的问题(issue上有解决方案)

3、修复内存不足问题之后,还有个运行卡住等问题

九 代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值