e2e测试要用到的文档库
e2e测试要用到cypress, cypress中测试框架用的是mocha; 断言库用的是chaiJS, 模拟函数用用的是sinon
测试内容
- e2e测试主要以功能为主, 也就是说要站在用户的角度去测试项目, 不需要关注功能的实现方式
- 主要测试的功能包括
1
2
3
|
关键元素是否显示
按钮点击后的效果是否符合预期
网络接口执行结果
|
元素操作
这些方法都返回一个被Cy包裹的一个元素, 暂且就叫它 QueryResult
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
cy.
get(selector, {timeout:5000}) 获取某个元素, 支持所有的CSS选择器, timeout表示查找元素的超时时间
contains(str) (在当前结果中)获取text内容包含指定str的元素
find(selector) 在当前结果中查找指定元素
eq(index) 获取当前结果中的第n个元素,和JQuery的eq一样
not(selector) 获取当前结果中不符合select的元素
first() 获取当前结果中的第一个元素
last() 获取当前结果中的第一个元素
siblings() 获取当前元素的所有兄弟元素
prev() 获取上一个兄弟元素
next() 获取下一个兄弟元素
prevAll() 获取当前元素之前的所有兄弟元素
nextAll() 获取当前元素之后的所有兄弟元素
prevUntil(selector) 获取当前元素到之前指定元素所有兄弟元素
nextUntil(selector) 获取当前元素到之后指定元素所有兄弟元素
focused() 获取当前焦点所在的元素
children() 获取当前元素的所有子元素
filter() 在当前结果中筛选指定的元素
closet(selector) 获取当前元素最近的某个指定元素
parent() 获取当前元素的父元素
parents() 获取当前元素DOM链上的所有父元素
parentsUntil(selector) 获取当前元素DOM链上的所有父元素(截止到selector元素)
document() // 返回window.document对象
|
1
2
3
4
5
6
7
8
|
QueryResult.
its(str) 获取QueryResult的一些属性
its('length') 获取QueryResult中的元素数量
each($el, $index, $list) 遍历QueryResult
invoke(str) 获取/设置某个元素的属性,使用方法可以参考JQuery中的属性名
invoke('val') 获取元素的表单值(多用于多选框和下拉选择器)
invoke('show') 类似于执行jquery中的show方法
scrollIntoView() 滚动到可视区域
|
表单操作
1
2
3
4
5
6
7
8
9
10
11
|
QueryResult.
type(string, {force:true}) 向输入框中注入内容 force:true表示禁用状态下强制注入内容
clear() 清空输入框内容
focus() 获取焦点
blur() 移除焦点
check(value, {force:true}) 勾选单个多选框, force:true表示禁用状态下强制勾选
check([value1, value2], {force:true}) 勾选多个多选框, force:true表示禁用状态下强制勾选
uncheck(value, {force:true}) 取消单个勾选 force:true表示禁用状态下强制取消勾选
uncheck([value1, value2], {force:true}) 取消多个勾选 force:true表示禁用状态下强制取消勾选
select([value1, value2],{force:true}) 向下拉框注入值
submit() 提交表单
|
事件操作
1
2
3
4
5
6
7
8
|
QueryResult.
click({multiple:false,force: false}) multiple:true表示多个元素结果时, 同时点击这些元素,
force:true表示忽略错误检查强制点击
dbclick()
rightclick()
// 等
trigger(eventName,options) // 触发某个事件
|
cypress自带的should断言
cypress的should中封装了chaiJS的断言库, 所以should方法中可以使用chai的断言语句, 也可以在嵌套语句中直接使用chai断言
cypress中封装的chai断言语句使用的BDD风格, 所以在直接使用Chai断言的时候, 建议也使用BDD风格
shuld的返回值不固定, 会根据他的实际参数返回不同的值, 可以搭配and链式调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
should(method, value) 快捷调用chai断言库
should(res=>{
// res是调用链上一层的数据, 可以自行处理, 这里就可以用chai自己的语法 expect
})
cy.get(select).should($el=>{
// 这里就可以处理$el的东西
expect($el.className).to.include('foo')
})
// 举例
const a = {name:'zhangsan'}
cy.wrap(a).should('have.property', 'name')
// 相当于
cy.wrap(a).should(a=>{
expect(a).to.have.property('name')
})
// should 与 and
cy.get('nav') // 返回nav本身
.should('have.class','nav') // 会返回nav的class 列表
.and('include','nav1')
|
元素断言should(method, value)
1
2
3
4
5
6
7
8
9
|
visible // 判断元素是否在可视区域
have.html, // str 判断元素的html内容是否包含str字符
contain, str // 判断元素的text内容是否包含str
match, str // 判断元素的text是否匹配str, str可以为正则表达式
have.value, str // 判断输入框的值是否与str相同
have.class, str // 判断元素是否包含类名str
have.attr, str // 判断元素是否包含属性str
have.id, str // 判断元素的id属性值是否等于str
checked // 判断复选框是否被勾选
|
字符串断言should(method, value)
1
2
3
4
|
include, str // 判断是否包含字符串str;
include, str // 判断数组中是否包含元素str,
include, {k:v} // 判断对象中是否包含属性k及属性值v
empty // 判断是否为空字符串
|
数字断言should(method, value)
1
2
|
gt, n // 判断是否大于数字n
lt, n // 判断是否小于数字n
|
对象断言should(method, value)
1
2
|
have.property, k // 判断是否包含k属性
have.property, k, v // 判断是否包含k属性且属性值为v
|
cookie, storage, location, navigation操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
cy.
clearCookie(name) // 清除指定cookie, 返回null
clearCookies() // 清除所有cookie, 返回null
getCookie(name) // 获取指定cookie , {name:'',value:'',path:'',secure:false, httpOnly=false, doman=""}
getCookies() // 获取所有的cookie, 是一个[{},{}]的数组
setCookie(name, value)
clearLocalStorage() // 清除所有的localstorage, 返回localstorage对象本身
location() // 返回location对象
location('hash') // 返回hash内容
hash() // 相当于location('hash')c
go('back') // 返回一页
go(-1) // 返回一页
go('forward') // 前进一页
go(1) // 前进一页
reload() // 重载页面
visit(url,{timeout, onLoad,...}) // 访问指定页面, timeout表示超时时间
|
网络请求操作
该部分包含网络请求与网络请求拦截两部分内容. request类的方法都返回标准的 response 内容,
- 网络请求类似于ajax, 操作方法类似于axios; 具体的使用方法可以参考文档https://docs.cypress.io/api/commands/request
1
2
3
4
5
6
7
8
9
10
|
cy.
request(url) // get方式请求接口 ,
request('POST', url) // post方式请求接口
request({
url:'',
qs:{
// url参数, 会被序列化后添加到url的后面
}
})
// 等等
|
- 网络请求拦截主要用于拦截页面中发出的请求, 判断请求结果是否符合预期, 同时还可以返回自己mock的数据来测试接口不同的状态
1
2
3
4
5
6
7
8
9
|
cy.
intercept(method, url<glob string>) // 添加一个拦截器, method是请求类型,
url是一个glob的字符串, 用来简要说明要拦截的url
.as(name) // 给拦截器添加一个别名 , 可以通过这个别名获取到拦截到的接口信息
wait(name) // 等待指定的网路请求结束, name就是上面的别名, 别名需要用'@name'的格式, 返回{request,response}
.should(res) // wait的结果
intercept({method, url}, mock) // 添加一个拦截器, 并返回mock数据, mock数据应该返回标准的response格式,比如:
|
response标准格式实例:
1
2
3
4
5
6
|
{
statusCode: 404,
body: { error: message },
headers: { 'access-control-allow-origin': '*' },
delayMs: 500, // 延迟返回时间
}
|
其他操作
1
2
3
4
5
6
7
8
|
cy.
wrap(val) // 包裹一个原始的数据类型, 包裹后可以调用cy的一些方法去处理数据, val会向后出传递给调用链
.spread(fn) // 相当于ES6 中的扩展运算符 , 多用于扩展数组
.then(res) // res接收val的值
screenshot(name) // 保存一个截图, name是截图名字, 截图会保存在sceeenshots文件夹内,
可以通过Cypress.Screenshot.defaults({})修改截图设置
pause() // 暂停自动执行, 下一条命令的执行权交给用户
scrollTo(x, y, options) // 调整滚动条到指定位置
|
函数模拟
函数模拟用的是sinon的插件, 函数模拟插件都返回该函数的执行状态, 从返回值中可以判断该函数是否执行过, 执行次数, 执行时的参数等, 具体断言属性可以参考 https://sinonjs.org/releases/v12.0.1/spies/
1
2
3
4
5
6
7
8
9
10
11
12
13
|
cy.
spy(objName, propertyName) // 模拟一个包含原函数的函数
.as(name) // 这里的name可以在后续通过它访问模拟函数的执行状态
stub(objName, propertyName) // 模拟一个替换原有函数的函数, 他俩最大的区别就是spy依然会执行原有函数, stub不会
.as(name) // 这里的name可以在后续通过它访问模拟函数的执行状态
clock(timestamp) // 设置一个时钟, 返回一个sinonTime相关的对象, 可以链式调用tick, restore方法
这个函数可以重写与时间有关的函数及Date对象, 所以代码中如果使用newDate()取值时,
会始终返回timestamp的值
.tick(duration) // 快进指定时间, 单位是毫秒, 可以加速程序中时间相关的函数执行
.restore() // 释放sinonTime, 此时代码中的时间相关函数及Date对象都恢复正常
.then(sinonTime) // 在then中也可以拿到sinonTime对象, 也可以在此调用tick, restore函数
tick(duration)
restore()
|