工具自动生成 自动化测试脚本-交互篇
开发工具原因
在小程序端使用自动化测试脚本,无非都是加载页面,获取节点,获取事件,获取值,获取data等操作
在断言时,也是千篇一律的拿值比较,本人觉得写一万行也是工作量的事,对自身也没有提升,也浪费时间。
但自动化在一些场合还是特别有用,修改公共组件方法,增加新的函数,尤其是与原来的逻辑存在交集的情况下,会出现漏掉检查的问题,导致模块报错出现白屏,展示不全等问题,在自动化测试交互上,可以避免一些常见容易遗忘检查的问题点。
使用方式
手动执行
进入common 执行 node start.js
根据events 里面的配置信息生成 默认auto-script(可配置修改)文件夹里面的文件engine执行逻辑拿到case类型,通过caseTmp里面的类型组装最后的文件
jest 执行对应文件名称 如 jest xxx.test.js
待完成
使用shell 执行语法一步命令解决全部终端命令
自动执行
仅仅的输入一句命令就可以执行一些复杂的人工操作
比如shell语法,在linux 系统上的脚本命令
输入 start script
执行 node start 生成脚本 -> jest xxx.text.js 执行脚本 -> 生成报告并自动打开
内部方法
获取节点名称
自动生成脚本语言,命名可以区分,单每次取名称都很繁琐
采用了
代码语言:javascript复制/**
* @despripe 根据对应的 class 或 对应数据 转化为对应的驼峰命名
* @param {String} domName 节点
* @detail get name-my or .name-my.data-in or .name-my .data-in
* @returns input nameMy or nameMyDataIn or dataInNameMy
*/
const handleComposeDomName = (domName) => {
let name = ''
const doms = domName.split(' ').reverse()
for (let i = 0; i < doms.length; i ) {
const rep = doms[i].replace(/[-.#_][__]{0,2}(w)/g, (_, c) => c ? c.toUpperCase() : '')
name = name rep
}
const first = name.substr(0,1).toLowerCase()
return first name.substr(1, name.length)
}
获取节点并做出操作
采用链式调用,使调取结构更加清晰
代码语言:javascript复制// 三个基本判断
/* url correct example
1 初始化页面 relaunch page url 1
2 获取节点元素 page.$$
3 节点元素点击 ele[0].tap()
4 新页面路径对比 expect
*/
/* text corrent example
1 初始化页面 relaunch page url 1
2 获取节点元素 page.$$
3 节点元素点击 ele[0].tap()
4 新跳转页面找到目标文案 page.$$
5 新页面文案对比 expect
*/
/* data corrent example
1 初始化页面 relaunch page url 1
2 获取节点元素 page.$$
3 节点元素点击 ele[0].tap()
4 新跳转页面找到目标文案 page.$$
5 新页面内部data对比 expect
*/
/**
* @despripe 根据对应的 class 或 对应数据 转化为对应的驼峰命名
* 节点操作
* getDom first get dom
* tap second tap
* getMethod
* getText
* getData
*/
const domOperate = () => {
return {
statement: '',
domName: '',
page: getPageNum(pageFactory.currentPage()),
getDom(dom) {
this.domName = handleComposeDomName(dom)
this.statement =
`await ${this.page}.waitFor('${dom}')
const ${this.domName} = await ${this.page}.$$('${dom}')`
return this
},
tap(order) {
const tap = `
await ${this.domName}[${order}].tap()
await ${this.page}.waitFor(1000)`
this.statement = this.statement tap
return this.statement
},
getMethod() {
return this.statement
},
getText(order) {
const text = `
const text = await ${this.domName}[${order}].text()
await ${this.page}.waitFor(1000)`
this.statement = this.statement text
return this.statement
}
}
}
用例类型
根据对象得格式 前两种优化版本,最后一个为未优化版本对比
代码语言:javascript复制const allCase = {
// 判断路径是否正确 -> 通过点击按钮tap事件 跳转路径 对比目标路径
urlCorrect: () => {
return (total) => {
const { enterBtnDom, btnOrder, mockPage, itName, targetPath } = total
return `
it('${itName}', async(done) => {
${getRelaunchPage(mockPage)}
${domOperate().getDom(enterBtnDom).tap(btnOrder)}
${getCurrentPage(pageFactory.increasePage()).statement}
${expect('toBe', targetPath, getPageNum(pageFactory.currentPage()), {type: 'path'})}
done()
})
`
}
},
textCorrect: () => {
return (config) => {
const {
enterBtnDom,
textDom,
targetText,
itName,
mockPage,
btnOrder = 0,
textOrder = 0,
} = config
/*
函数链式调用
*/
return `
it('${itName}', async(done) => {
${getRelaunchPage(mockPage)}
${domOperate().getDom(enterBtnDom).tap(btnOrder)}
${getCurrentPage(pageFactory.increasePage()).statement}
${domOperate().getDom(textDom).getText(textOrder)}
${expect('toBe', targetText, getPageNum(pageFactory.currentPage()), {type: 'text', isSingle: true})}
done()
})`
}
},
// 提交流程模版 未改造版本
submit: (fn) => {
const { mocks } = fn
const mockData = {
'formItems[0].value': 'test1',
'formItems[1].value': '11111111111',
[`formItems[${imgIndex}].value`]: mocks['img'],
[`formItems[${imgIndex}].tempFilePaths`]: mocks['img_url'],
[`formItems[${imgIndex}].require`]: '0',
[`formItems[${imgIndex}].showValue`]: '1张截图',
}
return (fn) => {
const {
firstStep,
secondStep,
testArea
} = fn
return `
it('xxxxxx提单流程', async() => {
const page = await miniProgram.reLaunch('/xxx/xxx/xxx')
await page.waitFor('.xxx-xxx')
const chooseItem = await page.$$('.xxx-xxx')
await chooseItem[${firstStep}].tap()
await page.waitFor(2000) // 列表页元素
const pageTwo = await miniProgram.currentPage()
await pageTwo.waitFor('.xxx-xxx') // 列表页元素
const twoItem = await pageTwo.$$('.xxx-xxx')
await twoItem[${secondStep}].tap()
await pageTwo.waitFor(2000)
const pageThree = await miniProgram.currentPage();
await pageThree.waitFor('.xxx-xxx')
const btnItem = await pageThree.$$('.xxx-xxx')
const chickItem = await pageThree.$$('.xxx-xxx')
const inputItme = await pageThree.$$('.xxx-xxx-xxx-xxx')
const textareatme = await pageThree.$$('.xxx-xxx-xxx-xxx')
// pageThree.callMethod('onPrivacyCheckBoxChange')
await inputItme[0].input('test1')
await textareatme[0].input('xxx-xxx测试自动化-xxx')
await chickItem[0].tap()
pageThree.setData(${mockData})
await inputItme[0].input('test2')
await textareatme[0].input('${testArea}测试自动化-xxx')
const data = await pageThree.data('xxx')
// pageThree.setData({privacyChecked: true})
await pageThree.waitFor(2000)
await btnItem[0].tap()
await pageThree.waitFor(2000)
const pageFour = await miniProgram.currentPage();
await pageFour.waitFor(4000)
})
`
}
}
}
配置文件
通过编写对象配置文件,生成对应的文件
提单流程测试格式:
代码语言:javascript复制 const config = {
isSingle: true,
fileName: 'submitTotal',
mocks: {},
describes: [
{
describeNam: 'xxxx测试',
cases: [
{
caseType: 'submit',
caseName: 'submit',
firstStep: 1,
secondStep: 0,
testArea: 'xxxx-xxxx',
itName: 'xxxxxxxxx',
mockPage: '/pages/xxxx/xxxxxxxxx',
mockData: {},
enterBtn: '.btn',
expect: true,
subList: {
}
}
]
},
],
order: 1,
targetPath: '/pages/xxxx/xxxxx',
timeout: 300000,
port: 9420,
},
使用 js 对象配置
isSingle 控制 文件的 数量 单文件 存放多个 describes
fileName 文件 名称前缀 最后 存放 到 固定目录格式为 xxxx.test.js
mocks: 输入框与图片模拟信息(需加入名称电话后期增加)
describes: 数组形式, 生成对应的describe
port: 监听端口 默认 9420
目标路径判断
代码语言:javascript复制 const config = {
describeName: 'XXXX测试', // describe名称
caseName: 'XXXX', // 文件名称
itName: 'XXX页进入路径正确', // it 描述
caseType: 'urlCorrect', // case类型
mockPage: '/XXX/XXXX/XXXX', // 进入路径
mockData: {}, // mock数据
expect: true, // 断言
enterBtn: '.XXXX-XXXX', // 路径进入按钮
order: 1, // 顺序
targetPath: '/XXXX/XXXX/XXXX', // 目标比较路径
timeout: 300000, // jest延长响应
port: 9420 // 监听端口
}
目标文案判断
caseType 修改为 textCorrect 类型
对应增加
代码语言:javascript复制 targetText: 'XXXX', // 判断文案
textDom: '.XXXX', // 判断文案节点
textOrder: 0, // 第几个节点
查找节点元素
通过casetmp 生成dom查找语句,需要获取节点的 value text 值
或者后期的对比值
操作wx内置函数
待更新
storage操作
待更新