1.前要
无聊无聊好无聊,感觉上班很无聊,学习很无聊,什么都很无聊,反正时间浪费也是浪费,不如水篇文章算了,里面的内容覆盖面可能不全,希望大家见谅。
2.为什么要用puppeteer?
这是一个说来话长的故事,我也不知道从哪说去,简单来说,自从我在某个夜晚接到领导的电话,领导告诉我刚刚上线的功能出bug,让我赶紧去看看,虽然这个功能不是我写的,这次上线我也不负责,但是因为我离公司近,领导就让我去赶紧处理bug,我也只好放下手上的游戏去改bug了。到了现场三下五除二就把bug解决了,原来是一个数据处理的有问题导致一个核心功能出了问题,但是理论上上线后这个功能是肯定会被测试到的,但是却被人为疏忽了。可恶啊!居然因为其他人的不严谨导致我加班,岂可修!就没有什么东西可以规范一下测试的流程吗,至少核心的流程可以走一遍,于是乎我就想到了UI自动化测试,而作为一个前端,UI自动化测试的工具肯定首推puppeteer了,因为它是node环境下运行的,安装也简单。
3.puppeteer的安装与引入以及基本使用
puppeteer的基本使用逻辑很简单,就2步
- 获取对应的节点
- 执行相应的操作,此文只涉及点击以及输入
本文将重点介绍这2部分功能
-
安装 Puppeteer:在项目目录中运行命令安装 Puppeteer。
// 根据node版本选择对应的puppeteer版本,不然可能会安装失败 npm install puppeteer
-
引入 Puppeteer:在代码中引入 Puppeteer 模块。
const puppeteer = require('puppeteer');
-
启动浏览器实例:使用
puppeteer.launch()
方法启动一个新的浏览器实例。// launch的的时候可以设置参数 const browser = await puppeteer.launch({ headless:false, //设置为true就不会打开浏览器,设置成false会打开游览器 defaultViewport: { width: 1920, height: 880 }, // 设置页面大小 args: ['--start-maximized'] // 设置游览器启动时最大化 });
-
创建页面:通过浏览器实例的
newPage()
方法创建一个新的页面。const page = await browser.newPage();
-
页面导航:使用
page.goto()
方法导航到指定的 URL。await page.goto('https://example.com');
-
进行操作:使用页面实例的方法进行各种操作,例如点击按钮、填写表单等。
await page.click('#myButton'); await page.type('#myInput', 'Hello, World!');
-
获取数据:使用页面实例的方法获取需要的数据。
const title = await page.title(); console.log('页面标题:', title);
-
关闭浏览器实例:完成操作后,关闭浏览器实例。
await browser.close();
4.定位Dom节点
- 根据css定位dom节点
await page.$('css选择器') // 返回第一符合css选择器的dom
await page.$$('css选择器') // 返回所有符合css选择器的dom
// 例子
await page.$('.test') // 返回类为test的第一个dom
await page.$$('.test') // 返回类名为test的所有dom
- 根据属性内容定位
await page.$('.test[属性名=属性值]') // 返回类名为test,且属性值满足要求的第一个dom
// 例子
await page.$('.test[placeholder="123"]') // 返回类名为test,且placeholder值为123的第一个dom
- xpath定位
await page.$x(xpath语法) // xpath语法这边不做详细介绍,因为我也是个彩笔,只会简单使用
// 例子
await page.$x('//span[text()="重置"]') //选择所有内容为重置的span标签
基本上学会了这3个在html中就没有你选不中的dom
5.模拟用户操作操作
- 点击操作
let ele = await page.$('.test[placeholder="test"]')
await ele?.click() // 对元素进行点击
- 输入操作
let ele = await page.$('.test[placeholder="test"]')
await ele?.type("testing") // 对元素进行输入‘testing’ 内容,前提是该元素可输入,否则会报错
- 键盘模拟按键
page.keyboard.down(key, options) //模拟按下指定的键。`key` 参数表示要按下的键位,可以是单个字符或键码值。`options` 参数可选,可以设置按键的修饰符,比如 `shift`、`ctrl` 等。
page.keyboard.up(key) //模拟松开指定的键。与 `down()` 方法对应,用于模拟按键事件的释放。
page.keyboard.press(key, options) //模拟按下并松开指定的键。相当于调用 `down()` 和 `up()` 方法的组合。
page.keyboard.type(text, options) //将指定的文本输入到当前聚焦的元素中。`text` 参数表示要输入的文本,`options` 参数可选,可以设置文本输入的延迟、修改器键等。
- 鼠标模拟
page.mouse.down(options) //模拟按下鼠标按键。`options` 参数可以设置 `button` 属性来指定按下哪个鼠标按键。
page.mouse.up(options) //模拟松开鼠标按键。`options` 参数与 `down()` 方法类似,可以指定松开哪个鼠标按键。
page.mouse.click(x, y, options) //模拟鼠标点击事件。会先调用 `move()` 将鼠标移动到指定位置,再调用 `down()` 和 `up()` 方法模拟按下和松开鼠标按键。
page.mouse.move(x, y, options) //将鼠标移动到指定位置。
page.mouse.wheel(options) //模拟鼠标滚动事件。可通过设置 `options` 对象的 `deltaX` 和 `deltaY` 属性来模拟鼠标滚动方向和速度。
page.mouse.buttons //表示当前鼠标按下的按钮状态。返回一个整数值,使用二进制位掩码表示不同的按钮状态。例如,`1` 表示左键,`2` 表示右键,`4` 表示中键。
其中对于键鼠操作options的值有所不同,如下:
对于键盘操作,options
对象可以包含以下属性:
delay
:指定输入文本的延迟时间(以毫秒为单位),即每个字符之间的间隔时间。默认值为 0。text
:指定要输入的文本内容。可以与type()
方法一起使用,将指定的文本输入到当前聚焦的元素中。modifiers
:用于设置修饰键的状态。例如,modifiers: ['Shift']
表示按下 Shift 键。可以与down()
、up()
或press()
方法一起使用。
对于鼠标操作,options
对象可以包含以下属性:
button
:用于指定鼠标按键,可以是'left'
、'right'
或'middle'
中的一个,默认为'left'
。clickCount
:用于指定鼠标点击的次数,默认为 1。deltaX
和deltaY
:用于模拟鼠标滚动事件时设置滚动的偏移量。
6.监听网络接口加载
Puppeteer 可以获取页面中的指定接口。你可以通过监视网络请求,并筛选出符合条件的请求来获取特定的接口数据。
下面展示如何使用 Puppeteer 获取页面中的指定接口数据:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch(); // 运行游览器
const page = await browser.newPage(); // 创建page实例
// 监听页面中的网络请求
await page.setRequestInterception(true);
page.on('request', (request) => {
// 判断请求的 URL 是否符合条件
if (request.url().includes('/api')) {
request.continue(); // 继续请求
} else {
request.abort(); // 中止请求
}
});
// 导航到指定的 URL
await page.goto('http://example.com');
// 等待页面加载完成
await page.waitForNavigation();
// 获取符合条件的网络响应
const responses = await page.waitForResponse(response => response.url().includes('/api'));
// 获取接口数据
const responseData = await responses.json();
console.log(responseData);
await browser.close();
})();
7.一些需要注意的点
- 注意iframe的切换
很多页面会通过iframe内嵌其他页面,此时如果不指定该iframe的话,是无法获取到该iframe下的dom元素的。
let iframe = await page.$('#myIframe') // 获取id为myIframe的iframe框架
const frame = await iframe.contentFrame(); // 获取iframe的框架内容
let ele = await frame.$('#test') // 获取iframe下id为test的元素
- await的使用
puppeteer中很多操作都是非阻塞异步操作,需要用await来确保程序的执行顺序
let frame = await (await page.$('#myIframe'))?..contentFrame(); // 灵活使用await减少代码行数
- 等待元素出现
很多时候我们无法确定元素什么时候加载出现,这个时候就需要等待dom的加载,不然会报错
await page.waitForTimeout(1000) // 等待1s
await page.waitForNavigation(); // 等待页面跳转完成
await page.waitForSelector(`input[placeholder="请输入账号"]`); // 等待匹配的输入框加载完成
await page.waitForXPath("//span[text()='退出']"); // xpath写法的等待元素加载
8.总结
此文只写了如何获取dom,如何对dom进行操作,以及一些特别需要注意的点,若想进行UI测试,让程序识别功能是否完整,其内部逻辑还需各位自己设计。在我看来此物甚是有趣,可堪大用。此文只做基础入门使用,也是我本人的学习笔记,望与君共勉。