puppeteer的简单使用
引言
对于编写应用程序,尤其是要部署上线投入生产使用的应用,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.querySelector或document.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也是类似的作用,此两者的区别可以参考这个discussbrowser.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的简单使用的更多相关文章
- puppeteer(headless chrome)实现网站登录
puppeteer简介 puppeteer是Chrome团队开发的一个node库,可以通过api来控制浏览器的行为,比如点击,跳转,刷新,在控制台执行js脚本等等.有了这个神器,写个爬虫,自动签到,网 ...
- 使用Puppeteer进行数据抓取(一)——安装和使用
Puppeteer是 Google Chrome 团队官方的Chrome 自动化工具.它本身是基于Chrome Dev Protocol协议实现的,但它提供了更高层次API封装,使用起来更加方便快捷. ...
- puppeteer 试用
puppeteer 是chrome 团队提供的Headless chrome node api 库,我们可以用来方便的进行chrome 操作,同时 可以做好多事情(web 爬虫,生成pdf,截图... ...
- 【工具篇】在.Net中实现HTML生成图片或PDF的几种方式
前段时间由于项目上的需求,要在.Net平台下实现把HTML内容生成图片或PDF文件的功能,特意在网上研究了几种方案,这里记录一下以备日后再次使用.当时想着找一种开发部署都比较清爽并且运行稳定的方案,但 ...
- Net中实现HTML生成图片或PDF
Net中实现HTML生成图片或PDF的几种方式 前段时间由于项目上的需求,要在.Net平台下实现把HTML内容生成图片或PDF文件的功能,特意在网上研究了几种方案,这里记录一下以备日后再次使用.当时想 ...
- 使用Puppeteer进行数据抓取(三)——简单的示例
本文以一个示例简单的介绍一下puppeteer的用法,我们的目的是:获取我博客上的文章的前十页的所有随笔的标题和链接.由于puppeteer本身是自动化chorme,因此这里我们的步骤和手动操作浏览器 ...
- puppeteer(二)操作实例——新Web自动化工具更轻巧更简单
一.入门实例 了解puppeteer见上一篇文章: https://www.cnblogs.com/baihuitestsoftware/p/9957343.html 1)本例主要是启动浏览器 con ...
- 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 ...
- 一个简单的puppeteer爬虫
const puppeteer = require("puppeteer"); const path = require('path'); const pathToExtensio ...
- 使用Puppeteer抓取受限网站
不要相信前端是安全的,今天简单验证一下,但是希望大家支持正版,支持原作者,毕竟写书不易. 安装Puppteer npm install --save puppeteer 选择目标网站 我们这里选择胡子 ...
随机推荐
- Codechef - Maximize Colours(IQ)
题目大意 有红绿蓝三种颜色,三种颜色当中任意两个颜色混合都可以产生出一个新的颜色(然而混合产生的颜色不能与任何其它的颜色进行混合).输入三个整数,分别代表红色,绿色,蓝色的颜色个数(每次混合各消耗 ...
- 算法2:寻找吸血鬼数(JS)
任务二:寻找吸血鬼数 打印所有4位吸血鬼数和它们的獠牙 提示:一共有7个: 吸血鬼数: -该鬼的位数为偶数: -该数的所有位中.是0的位少一半: -该数每一位上的数字重新组合为两个位数相等的数,乘 ...
- IntelliJ IDEA安装中文插件
1.运行IntelliJ IDEA程序2.点击左上角"File"//文件3.点击下拉的"Settings" //设置4.点击"Plugins" ...
- 关于 Python 字符串切片的小领悟
1. 什么是 Python 字符串切片? 例如存在字符串 str2 = "abcd1234" ,有以下简单的切片应用. str2[0] # a str2[0:3] # abc st ...
- c#中适配器模式详解
基础介绍: 想象这样一个场景,原项目中接口返回的数据是XML格式的数据,但现在来了一个新客户,它期望接口返回的数据类型为json格式的. 想要实现要么就是改原有接口,但这样就违反了开闭原则,容 ...
- 不可复制的PDF转成双层可复制PDF
有些PDF是通过扫描或者虚拟打印机生成的,这些PDF不可复制里边的内容 市面上的工具一般都是收费或者有水印,所以就萌生了自己搞一个的想法: 使用了以下三个开源库 PdfiumViewer PDF预览及 ...
- JAVA类的加载(1) ——类的加载及类加载器介绍
过程:当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过加载.连接.初始化三个步骤来对该类进行初始化,有时候称为类加载(类初始化) 类加载 定义:类加载 指的是将类的class文件读入 ...
- [Python急救站课程]正方形螺旋线的绘制
正方形螺旋线的绘制 import turtle turtle.speed('fastest') # 加快画笔速度 length = 3 # 正方形边长 angle = 90 # 转向角度 for i ...
- 使用JWT、拦截器与ThreadLocal实现在任意位置获取Token中的信息,并结合自定义注解实现对方法的鉴权
1. 简介 1.1 JWT JWT,即JSON Web Token,是一种用于在网络上传递声明的开放标准(RFC 7519).JWT 可以在用户和服务器之间传递安全可靠的信息,通常用于身份验证和信息交 ...
- Mysql报:error while loading shared libraries libtinfo.so.5的解决办法
版权声明:原创作品,谢绝转载!否则将追究法律责任. ----- 作者:kirin #.今天闲来无事,想在Anolis8的系统上装一个MySQL8.0玩.前期在安装和配置的过程中没有什么问题,但是在我想 ...