引言

对于编写应用程序,尤其是要部署上线投入生产使用的应用,QA是其中重要的一环,在过去的工作经历中,我参与的项目开发,大多是由测试同学主要来把控质量的,我很少编写前端方面的测试代码,对于测试工具的使用,也基本停留在一个小玩具的样子,所以接触的也少,回忆上一次写单元测试,还是在一个vue3的课程中使用jest实现TDD,记得之前有的时候面试,会被问到有没有在项目中用单测,但是因为以前工作中大多数时候需求排期都只考虑开发的时间,就很少考虑到这方面,然后就,面试中这方面也说不出什么东西,最近因为一个偶然的机会,我接触了puppeteer用来做前端自动化测试,用着还感觉蛮有点小意思。

puppeteer能做什么

puppeteer是一个Node.js库,通过puppeteer的文档,我们可以快速的了解我们能使用puppeteer来做些什么:

Most things that you can do manually in the browser can be done using Puppeteer! Here are a few examples to get you started:

  • Generate screenshots and PDFs of pages.
  • Crawl a SPA (Single-Page Application) and generate pre-rendered content (i.e. "SSR" (Server-Side Rendering)).
  • Automate form submission, UI testing, keyboard input, etc.
  • Create an automated testing environment using the latest JavaScript and browser features.
  • Capture a timeline trace of your site to help diagnose performance issues.
  • Test Chrome Extensions.

第一句作为总领,点出了puppeteer可以模拟用户与浏览器的交互。包括页面截图、生成SPA的预渲染内容、触发用户交互事件等等,可以用于进行UI和功能测试,另外可以看出除了普通的前端测试外,还可以作为爬虫工具使用。本文针对简单的用户交互事件的模拟和页面截图,实现一个puppeteer的使用示例。

准备工作

  • 首先在使用之前,需要先安装依赖

    npm i puppeteer
    # or using yarn
    yarn add puppeteer
    # or using pnpm
    pnpm i puppeteer

    我这里使用yarn global进行了全局的安装。

  • 然后我们来准备待测试的页面

    我这里准备了一个简单的页面,直接预览如下所示:

    页面分为两部分,最上面是标题,下面展示的是一个canvas。我们即将测试的内容除了基本的请求页面和获取页面元素外,主要有两项功能,分别为:

    • 点击canvas后展示一个弹窗,使用文字描述“土”与其他五行的关系,测试点击事件的模拟和弹窗的展示
    • 点击canvas后在canvas上绘制,使用图像描述“土”与其他五行的关系,测试puppeteer的截图功能并引入blink-diff模块,用于图像的对比

接下来我们就可以开始编写测试代码。

使用示例

因为是模拟交互,所以会有许多异步的操作,我们可以通过await获取结果,所以这个例子中的代码会使用异步函数async来包裹。

另外由于要模拟操作,所以选择器也是核心功能,类似于document.querySelectordocument.querySelectorAll的作用,puppeteer使用css选择器语法的超集进行查询,也就是说我们可以使用.class#id等css选择器来进行元素查询。

基本功能

以下是基本的代码:

/*
* check.js
*/
const puppeteer = require('puppeteer'); (async () => {
// Launch the browser and open a new blank page
const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
const page = await browser.newPage(); // Set screen size
await page.setViewport({width: 1920, height: 1080}); // Navigate the page to a URL
await page.goto('http://0.0.0.0:8080'); // 关闭puppeteer
browser.close(); // ...
})()

在模拟交互前,我们需要先启动浏览器并打开页面,以上代码就可以完成这些操作:

  • puppeteer.launch:启动浏览器

    在启动浏览器时,我们可以设置一些启动参数,这里的'--no-sandbox'代表取消沙盒模式,放开权限,--disable-setuid-sandbox也是类似的作用,此两者的区别可以参考这个discuss

  • browser.newPage:可以理解为打开一个浏览器tab

  • page.setViewport:设置视窗尺寸

  • page.goto:跳转页面到指定地址,这里跳转到了我们本地启动的8080服务页面

  • browser.close:关闭浏览器。我们可以在获取到数据后就进行关闭操作,再在后续中使用抓取到的数据

可以看到在每步操作之前,我们都使用了await来等待操作完成,每一步都需要等待上一步操作完毕才能开始。

接下来我们就可以开始获取页面上的元素,比如示例页面上的h3标签。

const elm = await page.waitForSelector('h3');
// OR
const elm = await page.$('h3'); console.log(elm);
// CdpElementHandle {
// handle: CdpJSHandle {},
// [Symbol(_isElementHandle)]: true
// }
console.log(elm.innerText); // undefined

可以通过.waitForSelector或简写的.$方法获取元素,可以看到打印出来的并不是DOM对象,而是一个经过封装的CdpElementHandle类型的对象,因此我们无法通过elm.innerText的方式来获取h3标签内的文本内容,似乎这个选择器方法只能用于判断页面上是否存在某个或某类匹配的元素。

如果想获取元素对应的DOM属性,可以使用Page.$eval()来实现,用法如下所示:

const elmText = await page.$eval('h3', h3 => h3.innerText);
console.log(elmText); // "土"与其他五行的关系

判断DOM属性

在本文的测试页面中,实现了点击canvas显示弹窗的功能,弹窗的显示是通过js代码添加样式类实现的,并且会在2s后关闭弹窗的显示,所以我们需要测试样式类的添加和移除。

同样的,我们需要先获取到canvas元素。

const canvas = await page.$('canvas');

接着模拟点击,并获取弹窗对应div的classList。

await canvas.click();
const popupClassList = await page.$eval('.popup-dialog', popup => popup.classList);
console.log(popupClassList); // { '0': 'popup-dialog', '1': 'visible' }

可以看到弹窗的classList中按照预期出现了代表显示的样式类visible。

接着我们继续测试2s后弹窗关闭。

await new Promise(r => setTimeout(r, 2000));
const postPopupClassList = await page.$eval('.popup-dialog', popup => popup.classList);
console.log(postPopupClassList); // { '0': 'popup-dialog' }

可以看到在2s后,样式类visible按照预期被移除了。这里我们使用一个promise来计时。

截图功能

最后我们来使用puppeteer的截图功能。在使用之前,先把测试页面的点击canvas显示弹窗改为绘制图像,然后我们来测试。

在截图之前,我们需要先指定一个目录用于存放截图,这里我直接创建一个imgs文件夹,然后编写以下代码:

const imgDir = './imgs/';
canvas.screenshot({ path: `${imgDir}canvas.png` });

执行node check.js后,我们就可以看到imgs目录下生成了一张图片,和我们在浏览器中看到的是一样的。

如果这是一个UI效果图,我们可以把他重命名为target.png,然后使用代码实现后,配合使用blink-diff模块,对比UI设计图与实际代码实现所存在的差异大小;blink-diff模块也可以通过NPM来安装。blink-diff是一个轻量级的图片对比工具,以下是一个简单的使用展示:

const puppeteer = require("puppeteer"),
BlinkDiff = require('blink-diff'); // ... // 关闭puppeteer
browser.close(); const diff = new BlinkDiff({
imageAPath: imgDir + 'target.png', // ui
imageBPath: imgDir + 'canvas.png', // 页面截图
imageOutputPath: imgDir + 'Diff.png', // 差异对比图
threshold: 0.02
});

因为已经得到截图,所以此时已经不需要浏览器了,new BlinkDiff可以在puppeteer关闭后执行。

imageAPath和imageBPath分别是设计图和页面截图的存放路径,imageOutputPath输出两张图片的差异对比图,threshold是一个百分比阈值,当差异比例低于该值时忽略差异,在这里这就是说,当差异比例低于2%,就认为两张图是相同的。

接下来就通过调用diff.run()方法来执行对比:

diff.run(function (error, result) {
if (error) {
throw error;
} else {
let rel = Math.round((result.differences /
result.dimension) * 100);
console.log(result.code);
console.log(diff.hasPassed(result.code));
console.log(diff.hasPassed(result.code) ? 'Passed' : 'Failed');
console.log('总像素:' + result.dimension);
console.log('发现:' + result.differences + ' 差异,差异占⽐'
+ rel + "%");
}
});

当正常执行后,会返回一个result对象包含对比结果的信息。

result.differences表示存在不同的像素数量,result.dimension表示像素的总数量,因此这里rel计算得到的就是像素的差异比例。

result.code就是一个结果状态码,调用diff.hasPassed方法会根据diff的配置对状态码进行解析,从而得出通过或失败的判断。

到这里为止就是一个截图功能和图像对比的简单示例,看上去使用起来挺不错的样子,但实际还是存在一些问题,比如我最近遇到的,使用渐变函数设置样式,得到的截图会存在问题,并没有得到应用渐变后的样式截图,不知道是兼容上的问题还是我的使用方式问题,所以暂时我使用了getComputedStyle作为替代方案。

总结

好啦,以上就是puppeteer的简单使用,有感兴趣的小伙伴可以继续阅读官方文档深入研究。

puppeteer的简单使用的更多相关文章

  1. puppeteer(headless chrome)实现网站登录

    puppeteer简介 puppeteer是Chrome团队开发的一个node库,可以通过api来控制浏览器的行为,比如点击,跳转,刷新,在控制台执行js脚本等等.有了这个神器,写个爬虫,自动签到,网 ...

  2. 使用Puppeteer进行数据抓取(一)——安装和使用

    Puppeteer是 Google Chrome 团队官方的Chrome 自动化工具.它本身是基于Chrome Dev Protocol协议实现的,但它提供了更高层次API封装,使用起来更加方便快捷. ...

  3. puppeteer 试用

    puppeteer 是chrome 团队提供的Headless chrome node api 库,我们可以用来方便的进行chrome 操作,同时 可以做好多事情(web 爬虫,生成pdf,截图... ...

  4. 【工具篇】在.Net中实现HTML生成图片或PDF的几种方式

    前段时间由于项目上的需求,要在.Net平台下实现把HTML内容生成图片或PDF文件的功能,特意在网上研究了几种方案,这里记录一下以备日后再次使用.当时想着找一种开发部署都比较清爽并且运行稳定的方案,但 ...

  5. Net中实现HTML生成图片或PDF

    Net中实现HTML生成图片或PDF的几种方式 前段时间由于项目上的需求,要在.Net平台下实现把HTML内容生成图片或PDF文件的功能,特意在网上研究了几种方案,这里记录一下以备日后再次使用.当时想 ...

  6. 使用Puppeteer进行数据抓取(三)——简单的示例

    本文以一个示例简单的介绍一下puppeteer的用法,我们的目的是:获取我博客上的文章的前十页的所有随笔的标题和链接.由于puppeteer本身是自动化chorme,因此这里我们的步骤和手动操作浏览器 ...

  7. puppeteer(二)操作实例——新Web自动化工具更轻巧更简单

    一.入门实例 了解puppeteer见上一篇文章: https://www.cnblogs.com/baihuitestsoftware/p/9957343.html 1)本例主要是启动浏览器 con ...

  8. nodejs puppeteer linux(centos)环境部署以及用puppeteer简单截图

    1.安装Node环境 如果有安装Node请忽略第1点 #下载cd /usr/local/srcwget https://nodejs.org/dist/v10.15.3/node-v10.15.3-l ...

  9. 一个简单的puppeteer爬虫

    const puppeteer = require("puppeteer"); const path = require('path'); const pathToExtensio ...

  10. 使用Puppeteer抓取受限网站

    不要相信前端是安全的,今天简单验证一下,但是希望大家支持正版,支持原作者,毕竟写书不易. 安装Puppteer npm install --save puppeteer 选择目标网站 我们这里选择胡子 ...

随机推荐

  1. Springboot 实现QQ登录(界面跳转)

    Springboot 实现QQ登录(界面跳转) 现在第三方登录已经变成主流app的登录方式了 今天记录一下如何给自己的网站实现第三方登录(这里以QQ登录为例) 准备工作 首先确保你准备好你自己网站的域 ...

  2. 题解 hdu 1269 迷宫城堡

    找点图论练习题写,发现hdu又寄了,那就发到blog里吧. 思路:tarjan缩点判断DAG中点数是否为1.若是,则该图为强连通图. //produced by miya555 //stupid mi ...

  3. 小白CNN入门指导

    小白CNN入门指导 这几天一直在小白入门学习卷积层以准备组会,以下是我自学理解内容,若有错误的地方请各位评论指出 数学部分 一 卷积层 \[输入 32*32*3 (input neurons) \] ...

  4. 2023 版 Java和python开发线性代数探索

    目录 前景提示 需求 分析 1.初始化不需要指定矩阵的尺寸,并且可以直接传入数据. 2.可以计算2x2矩阵的逆 3.可以做2x2的矩阵乘法 Java版本开发 一. 开发详情 1.开发一个子类,如图所示 ...

  5. 动态规划的状态设计 | bot 讲课の补题

    sto james1badcreeper orz. 好厉害的题,但是怎么有人补了三天才补完呢? CF1810G The Maximum Prefix 线性 dp,怎么有 bot 说题目难度在 *240 ...

  6. CSP-2023 复赛游记

    10.15 决定以后每天晚上都来. 洛天依也是. 10.16 想住 首旅京伦. 大巴车要求车况良好,保险齐全,进校后限速 20 km是什么鬼啊,新型速度单位. 距离最远的考区相距4公里 懂了,大巴车开 ...

  7. CSP 2022 游寄

    Day -2147483648 官网有了通知,但选手注册不知为何坏掉了: 先开坑: Day -大概两个月 注册了,但老师还没给我审核呜呜呜 第一轮 早上 早上起床就直接来机房了,不用跑操欸嘿. 上午 ...

  8. Python 潮流周刊#24:no-GIL 提案正式被采纳了!

    你好,我是猫哥.这里每周分享优质的 Python.AI 及通用技术内容,大部分为英文.标题取自其中两则分享,不代表全部内容都是该主题,特此声明. 微信 | 博客 | 邮件 | Github | Tel ...

  9. JavaScript:数据类型详解

    ECMAScript中数据类型目前有两种:基本数据类型和引用数据类型. 基本数据类型 基本数据类型也称作简单数据类型,为Undefined,Null,Boolean,Number,String,Sym ...

  10. Langchain-Chatchat项目:4.2-P-Tuning v2使用的数据集

      本文主要介绍P-tuning-v2论文中的5种任务,分别为Glue任务.NER任务.QA任务.SRL任务.SuperGlue任务,重点介绍了下每种任务使用的数据集. 一.Glue任务   GLUE ...