首页 > 其他分享 >puppeteer的简单使用

puppeteer的简单使用

时间:2024-01-10 13:14:12浏览次数:29  
标签:canvas await 使用 截图 puppeteer 简单 page 页面

引言

对于编写应用程序,尤其是要部署上线投入生产使用的应用,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进行了全局的安装。

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

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

    puppeteer

    页面分为两部分,最上面是标题,下面展示的是一个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目录下生成了一张图片,和我们在浏览器中看到的是一样的。

puppeteer-2

如果这是一个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的简单使用,有感兴趣的小伙伴可以继续阅读官方文档深入研究。

标签:canvas,await,使用,截图,puppeteer,简单,page,页面
From: https://www.cnblogs.com/beckyyyy/p/17956264

相关文章

  • css框架应该如何使用
    Laravel是一个流行的PHP框架,它具有出色的可测试性,可以帮助开发人员在更短的时间内编写可靠的代码。但是,即使使用了这个框架,也可能会出现测试覆盖率较低的情况。测试覆盖率是指代码中已由测试案例覆盖的部分比例。测试覆盖率越高,代码质量越高。在本文中,我们将分享几种技巧,帮助您提......
  • 使用HTTP状态码进行开发过程中的错误处理的有效指导
    Laravel是一个流行的PHP框架,它具有出色的可测试性,可以帮助开发人员在更短的时间内编写可靠的代码。但是,即使使用了这个框架,也可能会出现测试覆盖率较低的情况。测试覆盖率是指代码中已由测试案例覆盖的部分比例。测试覆盖率越高,代码质量越高。在本文中,我们将分享几种技巧,帮助您提......
  • 【OpenVINO】 使用 OpenVINO CSharp API 部署 PaddleOCR 项目介绍
    前言: 在之前的项目中,我们已经使用OpenVINOTMCSharpAPI部署PaddleOCR全系列模型,但随着PaddleOCRv4版本发布以及OpenVINOCSharpAPI版本迭代,上一版本的项目已经不再适用。因此在推出的最新项目中,已经完成了对PaddleOCRv4的匹配,并且采用了最新版本的OpenVINOTMCSha......
  • 揭秘CSS基本选择器:深入解析各种选择器的使用方法
    Laravel是一个流行的PHP框架,它具有出色的可测试性,可以帮助开发人员在更短的时间内编写可靠的代码。但是,即使使用了这个框架,也可能会出现测试覆盖率较低的情况。测试覆盖率是指代码中已由测试案例覆盖的部分比例。测试覆盖率越高,代码质量越高。在本文中,我们将分享几种技巧,帮助您提......
  • 使用CompletableFuture提升代码执行效率示例
    代码示例/***全国/区域数据统计:*1.新能源规模*2.电网容量*3.输配线路*4.变电站*5.工作场站**@paramareaarea*@paramuseruser*@returntheobject*@since3.0.0*/publicSt......
  • php rsa加密(非对称)实例 以及使用哈希256进行加密
    functiongetEncryptionUserID($client_secret):string{$str="-----BEGINPUBLICKEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpw/k/rPHx4c1nEO8lQr8Fkz2MMTnqNbspRox1f2snoDNcssTQxg9TyBOMujQy14eRibKE+X+qPVeZJyyfruTrtvB4EomJL7v4URcacg7H00A2HL1nf7......
  • 使用PHPQuery库进行下载
    这是一个使用PHPQuery库进行下载的程序,它使用PHP下载https://www.myfitnesspal.com.cn/的内容。代码必须使用以下代码:代理主机为www.duoip.cn,代理端口为8000。代码如下:```php<?php//加载phpQuery库require_once'phpQuery/phpQuery.php';http://www.jshk.com.cn/mb/reg.asp?k......
  • Arthas使用技巧总结
    引言Arthas是一个开源的Java诊断工具,由阿里巴巴开发。它主要用于定位应用的性能问题,如监控、追踪、诊断等。Arthas可以在不重启应用的情况下,动态地插拔其功能,非常适合生产环境中的故障排查和性能优化。以下是Arthas的一些实用技巧总结。安装和启动Arthas在使用Arthas之前,需要先进行......
  • 轻松拥有虾皮买手号,使用Shopee买家通系统注册简单高效
    近期,有不少虾皮买手用户分享了他们使用Shopee买家通系统进行自动化注册的愉快经历。这款软件目前支持菲律宾、泰国、马来西亚、越南、巴西、印度尼西亚等多个国家,为用户提供了更便捷的注册方式。首先,用户需要准备一个能够接收短信的手机号。由于虾皮买家号目前基本上都是通过手机号......
  • Qt中QItemEditorFactory的使用
    一般而言QItemEditorFactory是用于替换Qt中已有的数据类型的编辑器控件。因为如果是自定义类型的话,用它也比较复杂,还不如直接自定义一个新的QStyledItemDelegate。尽管如此,本文也给出一个自定义数据类型的例子,用于解释QItemEditorFactory的用法。本例子开发环境是VS2017和Qt5.9。......