Skip to content

Commit

Permalink
feat(e2e): 支持项目依赖安装使用e2e
Browse files Browse the repository at this point in the history
re #80
  • Loading branch information
fanniehuang committed Mar 5, 2021
1 parent 1f7ccf4 commit 2bceed3
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 78 deletions.
68 changes: 49 additions & 19 deletions packages/wxa-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,32 @@
* 主动操作返回(因无法监听返回事件,所以录制过程中 *点击物理返回键*、*小程序titlebar返回键*、*ios手势返回*等返回操作,暂无法支持)
* 已知bug:
* 暂无
* 待优化:
* 待优化&计划
* 不带-r参数时,即回放模式,仅添加元素id(回放测试用例时能找到对应元素),不侵入过多代码(现在会劫持各种tap等事件,植入全局按钮组件)
* 高大上网页版测试报告
* 【用例复用】:支持用例复用-公共用例不用重复录制(如:登陆模块只需要录制一次,其他用例复用,当登录模块更改时,只需要重新录制一次登录,不需要每个用例都重新录制)
* 【真机】:支持真机
* 【服务器】:有个公共服务器解决用例执行的问题
* 各种未知bug

2020年3月2日
# 使用手册

### 安装
1. `npm i -g wxa-cli2-apple`
2. `npm i -g jest`
3. 项目下安装 `npm i -DE miniprogram-automator looks-same`
* 项目下安装 `npm i -DE miniprogram-automator looks-same wxa-cli2-apple jest`

### 测试脚本录制
* 微信开发者工具,打开对应项目,勾选`不校验合法域名`
* windows系统,wxa.config.js里配置wechatwebdevtools: 微信开发者工具目录
* 项目目录下执行`wxa2-apple test --e2e -r`,开启录制模式
* 开始脚本录制,录制完成后脚本会保存在`__wxa_e2e_test__`目录下
* 脚本都录制完毕后需执行,`wxa2-apple test --e2e --base ` 回放用例并检查录制内容是否正确,且此次回放的截屏会作为后续回放用例的比较基准,用于判断测试是否通过,`--test=test1,test2`可指定要回放的用例,多个用例逗号分隔
1. 微信开发者工具,打开对应项目,勾选`不校验合法域名`
2. windows系统,wxa.config.js里增加属性`wechatwebdevtools `,配置微信开发者工具的安装目录
3. 项目目录下执行`wxa2-apple test --e2e -r`,开启录制模式
* 用开发者工具打开项目,页面左上角有`结束录制`button,说明已成功开启录制模式
* 此时与小程序的每一步交互都会录制为脚本,完成操作后,点击`结束录制`,输入用例名,对应脚本保存在`__wxa_e2e_test__`目录下

### 进行基准截屏
脚本录制过程中不会截屏,需要跑一次case脚本,完成基准截屏。若无基准截屏,用例回归时就不知道测试结果是否正确,所以这一步骤是必须的

* 脚本录制完毕后,需执行`wxa2-apple test --e2e --base ` 回放用例,检查录制操作是否正确,且此次回放的截屏会作为后续回放用例的比较基准,用于判断测试是否通过
* 基准截屏存放在`__wxa_e2e_test__/用例名/base_screenshot`中(`--test=test1,test2`可指定要回放的用例,多个用例逗号分隔)

### 测试脚本回放
* 开发者工具修改调试基础库 2.7.3以上(src/project.config.json需同步修改libVersion)
Expand All @@ -33,36 +41,44 @@
```
const path = require('path');
const existsSync = require('fs').existsSync;
// try to find @babel/runtime to decide whether add @babel/plugin-transform-runtime.
const cwd = process.cwd();
const babelRuntime = path.join(cwd, 'node_modules', '@babel/runtime/package.json');
let hasRuntime = existsSync(babelRuntime);
const commonConfigs = {
'plugins': [
['@babel/plugin-proposal-decorators', {'decoratorsBeforeExport': true}],
['@babel/plugin-proposal-class-properties'],
],
'presets': ['@babel/preset-env'],
}
};
if (hasRuntime) {
const pkg = require(babelRuntime);
commonConfigs.plugins.unshift(['@babel/plugin-transform-runtime', {'version': pkg.version || '7.2.0'}]);
}
module.exports = {
'sourceMap': false,
'ignore': [],
overrides: [{
exclude: [/node_modules/, /wxa-cli/],
exclude: [/node_modules/, /wxa-cli/],
...commonConfigs
}
,{
},
{
test: /wxa-e2eTest/,
...commonConfigs
}]
}
}
]
};
```
* `wxa2-apple test --e2e` 进入测试用例回放模式,`--test=test1,test2`指定执行用例,多个用例逗号分隔,操作截屏以时间命名保存在测试用例目录中,带参数`--screenshot`则会与`base_screenshot`的截屏进行diff
* `wxa2-apple test --e2e` 进入测试用例回放模式,操作截屏以时间命名保存在测试用例目录中(`--test=test1,test2`指定执行用例,多个用例逗号分隔


### 二次开发录制好的测试用例
Expand All @@ -72,12 +88,26 @@ record.js是一个数组,每一项Object对应用户一次操作(点击、
|key|类型|默认值|备注|
| :-----| :---- | :---- | :---- |
| action | Object| 本次操作信息,小程序包装好的事件信息,可<a href="https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html">查看文档</a> | 【type:操作类型,tap touchstart点击,input输入】<br> 【currentTarget.dataset._wxatestuniqueid:触发事件的页面元素id】<br/>|
| screenshotDiff | Boolean| false | 每一步操作截屏,是否要和expect_screenshot进行diff比对。启动命令带--screenshot参数时,忽略该配置,都会截屏diff比对。 |
| screenshotDiff | Boolean| true | 此次交互后的截屏,是否要和base_screenshot目录下的首次截屏进行差异比对|
| coustomExpect | Function| - | 编写自定义期望条件 |

### wxa2-apple可支持的参数
* `--no-mock` `wxa2-apple test --e2e --no-mock`此次用例回归,不mock api,直连真实接口(默认会用录制时的api数据来mock)
* `--screenshot-diff` `wxa2-apple test --e2e --screenshot-diff=fasle` 此次用例回归,截屏是否要和base_screenshot目录下的首次截屏进行比对(不传值默认会比对,false不比对)
* `--custom-expect` 进行自定义期望匹配,需要record.js里每一步的customExpect函数编写期望代码



```
module.exports = [
{
"action": {
.....
},
customExpect() {
//自定义期望匹配函数
}
},{
...
```
# 开发文档
* wxa下增加.vscode/launch.json文件
```
Expand Down
16 changes: 7 additions & 9 deletions packages/wxa-cli/src/const/defaultBabelConfigs.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,31 @@ const babelRuntime = path.join(cwd, 'node_modules', '@babel/runtime/package.json
let hasRuntime = existsSync(babelRuntime);

const commonConfigs = {

'plugins': [
['@babel/plugin-proposal-decorators', {'decoratorsBeforeExport': true}],
['@babel/plugin-proposal-class-properties'],
],
'presets': ['@babel/preset-env'],

}
};
if (hasRuntime) {
const pkg = require(babelRuntime);

commonConfigs.plugins.unshift(['@babel/plugin-transform-runtime', {'version': pkg.version || '7.2.0'}]);
}

const defaultConfigs = {
export default {
'cwd': path.join(__dirname, '../../'),
'sourceMap': false,
'ignore': [],
overrides: [{
exclude: [/node_modules/, /wxa-cli/],
exclude: [/node_modules/, /wxa-cli/],
...commonConfigs
}
,{
},
{
test: /wxa-e2eTest/,
...commonConfigs
}

]
};


export default defaultConfigs;
2 changes: 0 additions & 2 deletions packages/wxa-cli/src/tester/e2eTester.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import Schedule from '../schedule.js';
import Compiler from '../compilers/index';
import domWalker from './domWalker.js';
import Server from './server.js';
import e2eRecord2js from './wxa-e2eTest/e2eRecord2js';
import logger from '../helpers/logger';
import simplify from '../helpers/simplifyObj';
import {applyPlugins, readFile, writeFile} from '../utils.js';
Expand All @@ -12,7 +11,6 @@ import {DirectiveBroker} from '../directive/directiveBroker';
import crypto from 'crypto';
import debugPKG from 'debug';
import path from 'path';
import mkdirp from 'mkdirp';
import runTestCase from './wxa-e2eTest/runTestcase.js'

const debug = debugPKG('WXA:E2ETester');
Expand Down
47 changes: 5 additions & 42 deletions packages/wxa-cli/src/tester/wxa-e2eTest/e2eTestCaseTpl.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -91,47 +91,6 @@ for (let j = 0; j < testCaseNameArr.length; j++) {
apiMockMap
)
<% }); %>
// }
// if (!noMockApi) {
// await miniProgram.mockWxMethod(
// 'request',
// function(reqObj, apiMockMap) {
// let mapKey = `${reqObj.url}__e2e__${reqObj.method}__e2e__${Object.keys(reqObj.data).join(',')}`;
// if (apiMockMap[mapKey] && apiMockMap[mapKey].length > 0) {
// console.log(mapKey, 'mock success')
// return apiMockMap[mapKey].shift();
// }
// return new Promise(resolve => {
// reqObj.success = res => resolve(res)
// reqObj.fail = res => resolve(res)
// // origin 指向原始方法
// console.log(mapKey, 'no mock')
// this.origin(reqObj)
// })
// },
// apiMockMap
// )
// }
// // mock modal框
// await miniProgram.mockWxMethod(
// 'showModal',
// function(config, apiMockMap) {
// let mapKey = `showModal__e2e__title__${config.titie}__e2e__content__${config.content}__e2e__editable__${config.editable}__e2e__showCancel__${config.showCancel}__e2e__confirText__${config.confirmText}`;
// console.log(mapKey)
// if (apiMockMap[mapKey] && apiMockMap[mapKey].length > 0) {
// console.log(mapKey, 'mock success')
// return apiMockMap[mapKey].shift();
// }
// return new Promise(resolve => {
// reqObj.success = res => resolve(res)
// reqObj.fail = res => resolve(res)
// // origin 指向原始方法
// console.log(mapKey, 'no mock')
// this.origin(reqObj)
// })
// },
// apiMockMap
// )

// 开始回放+截屏
page = await miniProgram.reLaunch(`/${record[0].action.page}`);
Expand All @@ -153,10 +112,14 @@ for (let j = 0; j < testCaseNameArr.length; j++) {
for (let j = 1; j < idPath.length; j++) {
element = await element.$(`.${idPath[j]}`)
}
let diff = screenshotDiff;
if (record[i-1] && typeof record[i-1].screenshotDiff !== 'undefined') {
diff = screenshotDiff;
}
let same = await screenShot({
screenshotDir,
screenCount: screenCount++,
diff: screenshotDiff || (record[i-1] && record[i-1].screenshotDiff)
diff
})
if (customExpect && i !== 0 && record[i - 1].customExpect && typeof record[i - 1].customExpect === 'function') {
record[i - 1].customExpect();
Expand Down
4 changes: 1 addition & 3 deletions packages/wxa-cli/src/tester/wxa-e2eTest/e2eTestSuite.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,7 @@ let $$testSuitePlugin = (options) => {
let originSuccess = config.success;
config.success = function() {
const res = arguments[0] || {};
apiRecord.get(key).push({
...res
})
apiRecord.get(key).push(JSON.parse(JSON.stringify(res)))

originSuccess.apply(this, arguments);
}
Expand Down
16 changes: 14 additions & 2 deletions packages/wxa-cli/src/tester/wxa-e2eTest/runTestCase.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,25 @@ export default async function(cmd, wxaConfigs) {
screenshotPath = timeStamp;
}
try {

let screenshotDiff = cmd.screenshotDiff;
if (typeof screenshotDiff === 'undefined') {
if (!cmd.base && !cmd.record) {
screenshotDiff = true;
} else {
screenshotDiff = false;
}
} else if (screenshotDiff === 'false'){
screenshotDiff = false;
}

let recordString = await testCase2js({
cliPath: cli,
testCaseNameArr: JSON.stringify(testCaseNameArr),
testDir,
screenshotPath,
base: !!cmd.base,
screenshotDiff: !!cmd.screenshotDiff,
screenshotDiff: screenshotDiff,
noMockApi: !!cmd.noMock,
customExpect: !!cmd.customExpect,
mockWxMethodConfig
Expand All @@ -71,7 +83,7 @@ export default async function(cmd, wxaConfigs) {


try {
execSync(`jest ${path.join(testDir, '.cache', 'index.test.js')}`, {
execSync(`./node_modules/.bin/jest ${path.join(testDir, '.cache', 'index.test.js')}`, {
stdio: 'inherit'
});
process.exit(0);
Expand Down
2 changes: 1 addition & 1 deletion packages/wxa-cli/src/wxa.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ commander
.option('-r, --record', 'e2e测试录制模式,启动小程序自动开始录制')
.option('-t, --test [testName]', 'e2e执行测试用例,缺省则执行所有用例,多个用例名用逗号区分')
.option('--base', '仅截屏,作为后续回放用例比较基准')
.option('--screenshot-diff', '是否进行截屏比对')
.option('--screenshot-diff [screenshotDiff]', '是否进行截屏比对')
.option('--custom-expect', '进行自定义期望匹配,record.js里每一步的customExpect函数编写期望代码')
.option('--no-mock', '不mock接口')
.action((cmd)=>{
Expand Down

0 comments on commit 2bceed3

Please sign in to comment.