网页在提测流转给 QA 后,如何能帮他们更有效而准确的完成测试,是我一直在思考的一个问题。

  QA 他们会对网页编写测试用例,在提测之前会让我们将优先级最高的用例跑通,这在一定程度上能够避免频繁的返工,保证测试的顺畅。

  自己之前想过做 UI 的单元测试,一有修改就跑一遍用例,但是维护成本太高,并且每次留给我们的开发时间并不多。

  最近在看多份测试记录的 BUG 单中发现,45%~70% 之间的 BUG 都是内容性问题,例如网页中缺了个字、少了段话、图片呈现不对等问题。

  这些用肉眼看,其实很容易辨别。只要有个工具,能呈现不同操作下的网页,就可以大大提升 QA 的验收效率。

  于是就想到了 Puppeteer(傀儡师),它是一个 Node.js 库,提供了一套 API 控制 Chrome 或 Chromium 浏览器,可生成页面快照截图、模拟用户行为等。

  Chromium 是 Chrome 的开源版本,两者在界面、功能等方面会存在些区别。

  虽然 Puppeteer 可以模拟用户行为,但是它不能模拟用户在客户端 WebView 中的行为,例如点击头像进入用户客户端中的主页。

  简单理解,就是 Puppeteer 能呈现 Chrome 浏览器中的页面,但如果要测试客户端的样式兼容性和各种交互行为,就无法实现了。

  而内容展示异常的问题,无论是在哪一端,都能表现一致,因此可以用 Puppeteer 来作为自动化测试工具。

一、服务端实现

  当前 Puppeteer 的最新版本是 19.2.2,API 分为 20 多个模块,可查找页面 DOM 元素、屏幕截图、处理 WebSocket、模拟移动端设备、植入脚本、请求拦截等操作。

  我当前的目标是查看页面内容,所以在页面中也需要有些交互。

  先基于 KOA,快速搭建一个新项目,因为 Puppeteer 库比较大,所以为了不影响其他项目的构建和运行,就单独开了个项目。

  再引入相关的 Node 库,fs 用于创建目录,path 用于拼接绝对路径,config 用于读取配置文件。

const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');
const config = require('config');
const domain = config.get('domain');

  接着是声明一条路由,例如用 get 方法访问 test/game,传递类型和环境。

router.get("/test/game", async (ctx) => {
const { type, env = "www" } = ctx.query;
let data = [];
switch (type) {
case "1":
data = await hot(env);
break;
}
ctx.body = { code: 0, data };
});

  hot() 函数就是自动化测试的主体,核心逻辑其实就是点击某一栏,呈现页面后,再截一张图。

async function hot(env) {
const savePath = path.resolve(__dirname, "../static/hot"); // 将相对路径转换成绝对路径
const iPhone = puppeteer.KnownDevices["iPhone 6"]; // 模拟iPhone 6
// 当指定目录不存在时,就将其创建,Sync 后缀表示同步,recursive 参数表示递归创建
!fs.existsSync(savePath) && fs.mkdirSync(savePath, { recursive: true });
// 要返回的图片路径
const paths = [];
/**
* 本地环境可以不需要配置 args
* 但是在 Linux 服务器中在启动 puppeteer 时,默认要带上 --no-sandbox 参数
*/
return puppeteer.launch({
args: ["--no-sandbox", "--disable-setuid-sandbox"]
}).then(async (browser) => {
const page = await browser.newPage(); // 创建新的浏览器上下文
await page.emulate(iPhone); // 模拟设备
// 默认主页
await page.goto(`https://${env}.xxx.com/game/hot.html`, {
waitUntil: "networkidle0" // 等待到没有网络请求
});
// 截图
await screenshot(page, `${savePath}/1.png`);
paths.push(`${domain}/static/hot/1.png`);
// 查找符合样式的菜单栏
const tabs = await page.$$(".green_calss");
// 点击第二个菜单栏
tabs[1].tap();
await page.waitForNetworkIdle();
await screenshot(page, `${savePath}/2.png`);
paths.push(`${domain}/static/hot/2.png`);
// 点击第三个菜单栏
tabs[2].tap();
await page.waitForNetworkIdle();
await screenshot(page, `${savePath}/3.png`);
paths.push(`${domain}/static/hot/3.png`);
await page.close();
await browser.close();
return paths;
});
}

  path.resolve()、fs.existsSync() 和 fs.mkdirSync() 都是 Node.js 提供的方法

  page.goto() 可跳转到指定 URL 的网页,networkidle0 可等待到页面无网络请求。

  在自动化测试时,需要有个页面完成的时间点,如果用延时的方式,会不太准确,所以就想到了网络请求。

  我们这边的网页以移动端居多,所以需要选择要模拟的设备,例如 iPhone 6。

  page.$$() 是 ElementHandle 提供的一个方法,相当于 Document.querySelectorAll() 方法。

  tabs[1].tap() 就是模拟用户触摸屏幕,另外支持的事件还包括 click()、drag()、focus() 等。

  screenshot() 是一个截屏函数,内部调用 page.screenshot() 方法,可截取完整页面,包括滚动区域。

async function screenshot(page, savePath) {
await page.screenshot({
path: savePath,
type: "png",
fullPage: true //边滚动边截图
});
}

二、界面实现

  前端界面目前比较简洁,就一个活动下拉框和一个环境下拉框,以及一个提交按钮。

  提交后,就会从后台拿到页面快照,这些快照都会按照写好的脚本生成。

  

1)遇到的问题

  在实际使用中注意到,如果页面内包含一块定高区域,那么隐藏区域就需要滚动后才能呈现。

  当网页中有一个资源阻塞加载时,若是 waitUntil 参数的值是 networkidle0,那页面就会报超时的错误。

await page.goto(url, {
waitUntil: ["networkidle0"]
});

  但如果 goto() 方法不加等待时机,那就会一直等下去,没有结果。

await page.goto(url);

  可以改成 networkidle2,networkidle0 是指在 500ms 内没有任何网络连接,而 networkidle2 是指网络连接个数不超过 2 个。

  在部署到服务器后,由于字体的问题,页面内的中文会出现乱码,解决办法就是给服务器安装中文字体。

  

参考资料:

Automating Google Chrome with Node.js

京喜前端自动化测试之路

深入了解自动化:那些项目适合自动化测试

Puppeteer中文

Puppeteer 入门教程

Node.js躬行记(25)——Web自动化测试的更多相关文章

  1. Node.js躬行记(4)——自建前端监控系统

    这套前端监控系统用到的技术栈是:React+MongoDB+Node.js+Koa2.将性能和错误量化.因为自己平时喜欢吃菠萝,所以就取名叫菠萝系统.其实在很早以前就有这个想法,当时已经实现了前端的参 ...

  2. Node.js躬行记(1)——Buffer、流和EventEmitter

    一.Buffer Buffer是一种Node的内置类型,不需要通过require()函数额外引入.它能读取和写入二进制数据,常用于解析网络数据流.文件等. 1)创建 通过new关键字初始化Buffer ...

  3. Node.js躬行记(2)——文件系统和网络

    一.文件系统 fs模块可与文件系统进行交互,封装了常规的POSIX函数.POSIX(Portable Operating System Interface,可移植操作系统接口)是UNIX系统的一个设计 ...

  4. Node.js躬行记(6)——自制短链系统

    短链顾名思义是一种很短的地址,应用广泛,例如页面中有一张二维码图片,包含的是一个原始地址(如下所示),如果二维码中的链接需要修改,那么就得发代码替换掉. 原始地址:https://github.com ...

  5. Node.js躬行记(15)——活动规则引擎

    在日常的业务开发中,会包含许多的业务规则,一般就是用if-else硬编码的方式实现,这样就会增加逻辑的维护成本,若无注释,可能都无法理解规则意图. 因为一旦规则有所改变,那么就需要修改代码再发布代码, ...

  6. Node.js躬行记(19)——KOA源码分析(上)

    本次分析的KOA版本是2.13.1,它非常轻量,诸如路由.模板等功能默认都不提供,需要自己引入相关的中间件. 源码的目录结构比较简单,主要分为3部分,__tests__,lib和docs,从名称中就可 ...

  7. Node.js躬行记(21)——花10分钟入门Node.js

    Node.js 不是一门语言,而是一个基于 V8 引擎的运行时环境,下图是一张架构图. 由图可知,Node.js 底层除了 JavaScript 代码之外,还有大量的 C/C++ 代码. 常说 Nod ...

  8. Node.js躬行记(23)——Worker threads

    Node.js 官方提供了 Cluster 和 Child process 创建子进程,通过 Worker threads 模块创建子线程.但前者无法共享内存,通信必须使用 JSON 格式,有一定的局 ...

  9. Node.js躬行记(3)——命令行工具

    一.自定义 创建一个空目录,然后通过npm init命令初始化package.json文件,并按提示输入相关信息或直接回车使用默认信息,生成的内容如下所示. { "name": & ...

  10. Node.js躬行记(24)——低代码

    低代码开发平台(LCDP)是无需编码(0代码)或通过少量代码就可以快速生成应用程序的开发平台.让具有不同经验水平的开发人员可以通过图形化的用户界面,通过拖拽组件和模型驱动的逻辑来创建网页和移动应用程序 ...

随机推荐

  1. Kubernetes 监控--Prometheus

    在早期的版本中 Kubernetes 提供了 heapster.influxDB.grafana 的组合来监控系统,在现在的版本中已经移除掉了 heapster,现在更加流行的监控工具是 Promet ...

  2. 使用KVM的图形化界面安装centos7虚拟机

    前提条件 1.宿主机上已经安装KVM的图形化管理软件,参考网址:https://www.cnblogs.com/sanduzxcvbnm/p/15538881.html 2.宿主机上安装vnc服务器, ...

  3. 第一个Django应用 - 第二部分:Django数据库配置,模型和后台

    汇总操作 注:polls为应用名 1.执行命令:python manage.py migrate,生成默认的数据库表等 2.修改应用的models.py文件,添加数据库表模型等 3.INSTALLED ...

  4. Deepin系统navicat15安装

    Deepin系统安装navicat15(已验证) 下载Navicat15 通过下面地址下载Navicat15,默认下载到桌面即可 $ https://download.navicat.com.cn/d ...

  5. HDU3001 Travelling (状压DP)

    题目没有起点限制,且每个节点至少访问1次,最多访问2次,所以用三进制数表示节点的状态(选取情况). 因为三进制数的每一位是0或1或2,所以预处理z状态S的第j位的数是有必要的. 边界条件:dp[tri ...

  6. Taurus.MVC 微服务框架 入门开发教程:项目部署:7、微服务节点的监控与告警。

    系统目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 开源地址:https://github.com/cyq1162/Taurus.MVC 本系列第一篇:Tauru ...

  7. iptables使用详解

    iptables使用详解 @(linux)[iptables] 前言 最近买了一个VPS,并在上面搭了DOCKER,然后再DOCKER中安装Mysql.但只要将网络端口映射到宿主机上,那么外部网络就可 ...

  8. C++ 函数重载解析策略

    参考<C++ Primer Plus>(第6版)中文版,Stephen Prata 著,张海龙 袁国忠译,人民邮电出版社.C++ 使用重载解析策略来决定为函数调用使用哪一个函数定义.重载解 ...

  9. c++算法竞赛常用板子集合(持续更新)

    前言 本文主要包含算法竞赛一些常用的板子,码风可能不是太好,还请见谅. 后续会继续补充没有的板子.当然我太菜了有些可能写不出来T^T 稍微有些分类但不多,原谅我QwQ 建议 Ctrl + F 以快速查 ...

  10. 十八、Service的应用

    Service 的应用 ClusterIP ​clusterIP 主要在每个 node 节点使用 ipvs,将发向 clusterIP 对应端口的数据,转发到 kube-proxy 中.然后 kube ...