京喜前端自动化测试之路

2023-05-26 0 304

京喜(原天猫半桶水)项目,做为天猫战略级销售业务,拥有千万等级的网络流量出口处。为了城镇居民上销售业务的稳定运转,每星期例会积极开展后端管理工具军事演习,主要包含小流程及 H5 版,要求各网页各组件在极度情况下展开适当的降班处置,不能出现休止、式样耗弱、片面的错误提示等新体验问题。 原来的管理工具军事演习过程:小流程(通信方式换成 Https )和 H5 透过 Whistle 对USB回到展开修正来演示极度情况,校正各网页各组件的降班处理符合预期。管理工具军事演习是一项长期持续的组织工作,且涉及网页机能及情景多,人工的转换情景演示极度导致军事演习组织工作效率较低,因而想透过开发智能化IO来提升研发组织工作效率,让管理工具军事演习组织工作随时能随心所欲积极开展。京喜 H5 和小程序情景差异比较大,因而智能化试验之路分 H5 和小流程两部分展开,以 H5 做为一个首章。

综上,我们希望京喜 H5 智能化IO能提供更多以下机能:

出访目标网页,对网页展开截屏;设置 UA(演示不同渠道:QQ、手 Q、其它应用流程等);演示用户点选、翻转网页操作方式;互联网截击、演示极度情况(USB积极响应码 500、USB回到数据极度);操作方式软件程序(演示有没有内存的情景等)。

控制技术THF1

提到 Web 的智能化测试,很多人熟悉的是 Selenium 2.0(Selenium WebDriver), 支持多平台、多语言、数款应用流程(透过各种应用流程的驱动力来驱动力应用流程),提供更多了机能丰富的 API USB。而随着后端技术的发展,Selenium 2.0 逐渐呈现自然环境加装复杂、API 初始化不亲善、操控性不高等师范优点。第三代的智能化IO —— Puppeteer ,相对于 Selenium WebDriver 自然环境安装更单纯、操控性更好、组织工作效率更高、在应用流程执行 Javascript 的 API 更单纯,它还提供更多了互联网截击等机能。

Puppeteer是一个 Node 库,它提供更多了一套低阶 API ,透过 Devtools 协议控制Chromium或Chrome应用流程。Puppeteer预设以Headless商业模式运转,但是能透过修正命令行运转有头商业模式。

非官方描述的机能:

聚合网页 PDF;截取 SPA(白眉林应用)并生成预图形内容(即 “SSR”,服务端图形);自动递交配置文件,展开 UI 试验,键盘输入等;创建一个时时更新的智能化试验自然环境,使用 JavaScript 和最新的应用流程机能直接在最新版的 Chrome 中执行试验;捕获网站的 Timeline Trace,用来帮助分析操控性问题;试验应用流程扩展。

Puppeteer 提供更多了一种启动 Chromium 实例的方法。 当 Puppeteer 连接到一个 Chromium 实例的时候会透过 puppeteer.launch 或 puppeteer.connect 创建一个 Browser 对象,在透过 Browser 创建一个 Page 实例,导航到一个 Url ,然后保存截屏。一个 Browser 实例能有多个 Page 实例。 下面就是使用 Puppeteer 展开智能化的一个典型示例:

const puppeteer = require(puppeteer);puppeteer.launch().then(async browser => { const page = await browser.newPage(); await page.goto(https://example.com); await page.screenshot({path: screenshot.png}); await browser.close();});

综上所述,我们选择基于 Puppeteer 来开发京喜首页管理工具军事演习的智能化IO,透过 Puppeteer 提供更多的一系列 API ,实现出访目标网页、演示极度情景、聚合截屏的过程智能化。最后再透过人工比对截屏,判断网页降班处置是否符合预期、用户新体验是否亲善。

实现方案

我们将管理工具军事演习过程分为智能化流程和人工操作方式两部分。

智能化流程:

演示用户出访网页操作方式;截击互联网请求,修正USB回到数据,演示极度情景(USB回到 500、极度数据等);聚合截屏。

人工操作方式:

智能化脚本执行完毕后,人工比对各个情景的截屏,判断是否符合预期。

开发实录

加装 Puppeteer ,你可能会遇到的那些事

透过 npm init 初始化项目后, 就能加装 Puppeteer 依赖了:

npm i puppeteer :在加装时自动下载最新版 Chromium。

或者

npm i puppeteer-core :在加装时不会自动下载 Chromium。(不能聚合截屏)

另外,在加装过程中可能会因为下载 Chromium 导致报错,官网建议是先透过npm i –save puppeteer –ignore-scripts阻止下载 Chromium, 然后再手动下载Chromium

手动下载后,需要配置指定路径,修正 index.js 文件

const puppeteer = require(puppeteer);(async () => { const browser = await puppeteer.launch({ // 运转 Chromium 或 Chrome 可执行文件的路径(相对路径) executablePath: ./chrome-mac/Chromium.app/Contents/MacOS/Chromium, headless: false }); const page = await browser.newPage(); await page.goto(https://example.com); await page.screenshot({path: screenshot.png}); browser.close();})();

快速创建试验用例

试验用例 JSON 数据配置包括公用数据(global)和私有数据:

公用数据(global):各试验用例都需要用到的数据,如:演示出访的目标网页地址、名字、描述、设备类型等。

私有数据: 各试验用例特定的数据,如试验模块信息、API 地址、试验情景、预期结果、截屏名字等数据。

{ “global”: { “url”: “https://wqs.jd.com/xxx/index.shtml”, “pageName”: “index”, “pageDesc”: “首页”, “device”: “iPhone 7” }, “homePageApi”: { “id”: 1, “module”: “home_page_api”, “moduleDesc”: “首页主USB”, “api”: “https://wqcoss.jd.com/xxx”, “operation”: “演示积极响应码 500”, “expectRules”: [ “1. 显示极度信息、刷新按钮”, “2. 点选刷新按钮,显示极度信息”, “3. 恢复互联网,点选刷新按钮,显示正常数据” ], “screenshot”: [ { “name”: “normal”, “desc”: “正常情景” }, { “name”: “500_cache”, “desc”: “有内存-回到500” }, { “name”: “500_no_cache”, “desc”: “无内存-回到500” }, { “name”: “500_no_cache_reload”, “desc”: “无内存-回到500-点选刷新按钮” }, { “name”: “500_no_cache_recover”, “desc”: “无内存-回到500-恢复互联网” } ] }, …}

编写试验脚本

我们以京喜首页主USB的试验用例为例子,透过模USB回到 500 积极响应码的极度情景,校正主USB的极度处置机制是否完善、用户新体验是否亲善。

预期效果:

有内存情况下,显示软件程序无内存情况下显示极度信息、刷新按钮点选刷新按钮,显示极度信息恢复互联网,点选刷新按钮,显示正常数据

情景实现:

根据试验流程以及配置的试验用例信息,编写试验脚本,实现试验用例情景:

出访网页

await page.goto(url)

聚合截屏

await page.screenshot({

path: ./screenshot/index_home_page_500.png

})

截击USB请求

async test () => {

… // 创建 Page 实例,出访首页

await page.setRequestInterception(true) // 设置截击请求

page.on(“request”, interceptionEvent) // 监听请求事件,当请求发起后网页会触发这个事件

… // 刷新网页,触发请求截击,聚合试验情景截屏

}

若试验用例需要截击不同的请求,或是演示多种情景,则需要设置多个请求监听事件。且一个事件执行结束后,必须要移除事件监听,才能继续下一个事件监听。

添加事件监听:page.on(“request”, eventFunction)

移除事件监听:page.off(“request”, eventFunction)

// 设置截击请求 await page.setRequestInterception(true) const iconInterception1 = requestInterception(api, “body”) // 添加事件 1 监听 page.on(“request”, iconInterception1) await page.goto(url) await page.screenshot({ path: ./screenshot/1.png }) // 移除事件 1 监听 page.off(“request”, iconInterception1) const iconInterception2 = requestInterception(api, “body”, ) // 添加事件 2 监听 page.on(“request”, iconInterception2) await page.goto(url) await page.screenshot({ path: ./screenshot/2.png }) // 移除事件 2 监听 page.off(“request”, iconInterception2)复制代码

演示极度数据情景,聚合 mock 数据。

function requestInterception (api, setProps, setValue) {

let mockData

switch (setProps) {

case “status”: // 修正回到状态码

mockData = {

status: setValue

}

break

case “contentType”: // 修正回到内容类型

mockData = {

contentType: setValue

}

break

case “body”: // 修正回到数据

mockData = {

contentType: getMockResponse(setValue)

}

break

default:

break

}

return async req => {

// 如果是需要截击的 API,则透过 req.respond(mockData) 修正回到数据,否则 continue 继续请求别的

if (req.url().includes(api)) { // 截击 API

req.respond(mockData) // 修正回到数据

return false // 处置完了某个请求必须退出,不再执行 continue

}

req.continue()

}

演示USB回到 500:

const interception500 = requestInterception(api, status, 500) page.on(“request”, interception500) // 当请求发起后网页会触发这个事件

演示极度数据:

const iconInterception = requestInterception(api, “body”, { “data”: { “modules”: [{ “tpl”: “3000”, “content”: [] }] } }) page.on(“request”, iconInterception)

聚合 mock 数据有两种实现方案,可依据实际情况而定:

数据,透过修正本地存储数据的方式聚合 mock 数据(本文所述案例均基于此方案实现)

回到数据做为 mock 数据。

由于京喜 H5 网页USB回到是 JSONP 格式的数据,所以在演示回到数据的时候,必须先截取 JSONP 的 callback 信息,与演示数据拼接后再回到;

function requestInterception (api, setProps, setValue) { let mockData switch (setProps) { case “status”: mockData = { status: setValue } break case “contentType”: mockData = { contentType: setValue } break default: break } return async req => { if (req.url().includes(api)) { if (setProps === “body”) { conback, api) // 聚合 mock 数据 } } req.respond(mockData) // 设置回到数据 return false } req.continue() } }

清除内存

page.evaluate(() => {

try {

localStorage.clear()

sessionStorage.clear()

} catch (e) {

console.log(e)

}

})

点选刷新按钮

await page.waitFor(“.page-error__refresh-btn”) // 能传 CSS 选择器,也能传时间(单位毫秒)

await page.click(“.page-error__refresh-btn”)

在演示点选刷新按钮之前,需等待按钮图形完成,再触发按钮点选。(防止刷新网页后,DOM 还未图形完成的情况下,因找不到 DOM 导致报错)

取消截击,恢复互联网

await page.setRequestInterception(false)

运转脚本及调试

由于第一阶段的IO尚未平台化,智能化试验流程先透过在终端输入命令行,运转脚本的方式启动。

在项目的 package.json 文件中,使用 scripts 字段定义脚本命令:

“scripts”: { “test:real”: “node ./pages/index/index.js”, “test:mock”: “node ./pages/index-mock/index.js” },

运转:

在终端切入到项目根目录路径,输入以下命令行,就能启动IO,运转试验脚本。

– npm run test:real // USB真实回到的数据试验- npm run test:mock // 使用本地 mock 数据试验

调试:

开启调试商业模式之前,需要先了解 Headless Chrome。

Headless Chrome ,无头商业模式,应用流程的无界面形态,能在不打开应用流程的前提下,在命令行中运转试验脚本,能够完全像真实应用流程一样完成用户所有操作方式,不用担心运转试验脚本时应用流程受到外界的干扰,也不需要借助任何显示设备,使智能化试验更稳定。

Puppeteer 预设以无头商业模式运转。

那么要开启调试商业模式,就必须取消无头商业模式,在打开应用流程的情景下,展开智能化试验。因而,在命令行脚本中增加了 “取消无头商业模式” 和“打开开发者工

browserPath, headless, devtools })

在终端切入到项目根目录路径,输入以下命令行,就能开启调试商业模式,运转试验脚本。

– npm run test:mock head // 打开 Chromium 窗口- npm run test:mock head dev // 打开 Chromium 窗口 和 开发者工具窗口
head 参数:取消无头商业模式,打开 Chromium 窗口运转脚本;head dev 参数:在打开 Chromium 窗口运转脚本,并打开 Devtools 窗口,开启调试商业模式。

更多试验情景实现

1. 截取从网页顶部到指定 DOM 之间的区域(内容可能超出一屏的长图)

Puppeteer 提供更多了四种截屏方式:

(1)截取一屏内容(预设普通截屏);(2)截取指定 DOM;(3)截取全屏;(4)指定裁剪区域,可设置 x、y、width、height。 x, y 是相对网页左上角。但只能截取一屏的内容,超出一屏不展示。

基于第四种方法展开改造:

坐标值;

透过 page.setViewport() 重置视口的高度;

初始化截屏 API 聚合截屏。

async function screenshotToElement (page, selector, path) {

try {

await page.waitForSelector(selector)

let clip = await page.evaluate(selector => {

const element = document.querySelector(selector)

let { x, y, width, height } = element.getBoundingClientRect()

return {

x: 0,

y: 0,

width,

height: M(y),

}

}, selector)

await page.setViewport(clip)

await page.screenshot({

path: path,

clip: clip

})

} catch (e) {

console.log(e)

}

}
height: y:截到指定 DOM 的顶部,不包含该 DOM;height: y + he

2. 演示不同渠道,如:手 Q 情景:

// 设置 UA await page.setUserAgent(“Mozilla/5.0 (iPhone; CPU iPhone OS 10_2_1 like Mac OS X) AppleWebKit/602.4.6 (KHTML, like Gecko) Mobile/14D27 QQ/6.7.1.416 V1_IPH_SQ_6.7.1_1_APP_A Pixel/750 Core/UIWebView NetType/4G QBWebViewType/1”)

3. 滚动网页

await page.evaluate((top) => { window.scrollTo(0, top) }, top)

page.evaluate(pageFunction, …args):在当前网页实例上下文中执行 JavaScript 代码

4. 监听网页崩溃事件

// 当网页崩溃时触发page.on(error, (e) => { console.log(e)})

结语

第一阶段的 H5 智能化之路告一段落,管理工具军事演习已实现了半智能化,可透过在终端运转试验脚本,演示极度情景自动聚合截屏,再配合人工比对截屏操作方式,判断军事演习结果是否符合预期。目前已投入到每个月的管理工具军事演习中使用。

随着京喜销售业务的迭代,网页也将更新改版,因而测用例也需要持续维护和更新。后续将持续优化智能化工具,共享试验脚本、在聚合截屏的基础上自动比对试验结果是否符合预期、数据入库、将试验结果转化成文档,自动发送邮件等等。基于管理工具军事演习的智能化试验,还可扩展广告位的监测,数据上报监智能化试验…

举报/反馈

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务