前端自动化测试
刀刀
4/8/2025
0 字
0 分钟
- UP主:三十的前端课,视频地址:前往学习
无头浏览器
首先认识一下无头浏览器,无头浏览器是一个没有 UI 界面的模拟浏览器,可以用 NodeJS 配合对应的库模拟用户在浏览器浏览的操作。
常见的无头浏览器有:Puppeteer【推荐】、PhantomJS【老牌,不维护】、Selenium 等。
思路实现
- 编写 NodeJS 脚本代码
- 脚本
link
为全局指令(可不做) js
代码立体无头浏览器模拟访问- 获取各项指标
首先搭建一个简单的项目,目录结构如下:
├── node_modules
├── index.js
├── package.json
下载 puppeteer-core
依赖,这里不下载 puppeteer
是因为该模块比较大,它包含了浏览器内核,而 puppeteer-core
是一个轻量级的模块,只包含浏览器控制功能。
在 index.js
文件内引入 puppeteer-core
,并编写代码:
const puppeteer = require("puppeteer-core");
(async () => {
// 打开浏览器
const browser = await puppeteer.launch({
headless: false, // 是否无头,设置为 `false` 可以看到浏览器界面,设置为 `true` 则会在后台运行,看不到浏览器界面
executablePath:
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", // 浏览器路径
defaultViewport: null, // 默认视窗大小 { width: 1920, height: 1080 }
});
// 打开新页签
const page = await browser.newPage();
// 跳转前到开始时间
const startTime = performance.now();
// 页签跳转到一个新地址(案例中是跳转到百度)
await page.goto("https://www.baidu.com");
console.log(Date.now() - startTime); // 跳转耗时
browser.close(); // 关闭浏览器
})();
终端命令行运行 node index.js
,即可成功打开浏览器。
想要获取项目各项指标,无需手动记录时间去计算,performance
对象可以帮我们记录各项指标,不过此时是在 Node 环境,Node 环境没有这个事件对象,因此需要搭配 page.evaluate
方法,将 performance
对象传递到浏览器环境,在浏览器环境获取各项指标。
const puppeteer = require("puppeteer-core");
(async () => {
// 打开浏览器
const browser = await puppeteer.launch({
headless: false, // 是否无头,设置为 `false` 可以看到浏览器界面,设置为 `true` 则会在后台运行,看不到浏览器界面
executablePath:
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", // 浏览器路径
defaultViewport: null, // 默认视窗大小 { width: 1920, height: 1080 }
});
// 打开新页签
const page = await browser.newPage();
// 跳转前到开始时间
const startTime = performance.now();
// 页签跳转到一个新地址(案例中是跳转到百度)
await page.goto("https://www.baidu.com");
await page.evaluate(() => {
return JSON.stringify(window.performance.timing);
});
console.log(Date.now() - startTime); // 跳转耗时
browser.close(); // 关闭浏览器
})();
明确
- 如果想要获取打开的页面里面的东西,如
window
对象,需要在page.evaluate
方法内获取。 - 如果想把页面的对象传到 Node ,则需要通过
JSON.stringify
返回回来。
可做的事
- 最常见的页面首屏渲染,DOM 渲染时间等
- 页面某个核心区域出现的时间,因为区域的内容需要异步请求从后端来才能渲染,所以需要记录这个区域渲染完成的时间
- 某个操作链路完成的时间(不考虑人类反应速度,单纯程序本身完成这个操作链路需要的时间)
有一个项目通过 v-for="item in list"
来渲染表格数据,想要知道该组件渲染完成的时间,可以借助 page.waitForSelector
方法,等待某个元素出现,然后记录时间。
<template>
<div class="app">
<div class="list-item" v-for="item in list" :key="item.id">
{{ item.name }}
</div>
</div>
</template>
const puppeteer = require("puppeteer-core");
(async () => {
// 打开浏览器
const browser = await puppeteer.launch({
headless: false, // 是否无头,设置为 `false` 可以看到浏览器界面,设置为 `true` 则会在后台运行,看不到浏览器界面
executablePath:
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", // 浏览器路径
defaultViewport: null, // 默认视窗大小 { width: 1920, height: 1080 }
});
// 打开新页签
const page = await browser.newPage();
// 跳转前到开始时间
const startTime = performance.now();
// 页签跳转到一个新地址(案例中是跳转到百度)
await page.goto("https://www.baidu.com");
await page.goto("http://locahost:5173");
await page.waitForSelector(".list-item"); // 获取对应的组件
console.log(Date.now() - startTime); // 渲染耗时
browser.close(); // 关闭浏览器
})();
另一个项目想要测试点击登录按钮后,登录成功后跳转到首页的时间【不想计算上人类输入点击等的时间进去】,可以借助 page.waitForNavigation
方法,等待页面跳转完成,然后记录时间。
<template>
<div class="app">
<button v-if="xx" class="login" @click="login">登录</button>
<template v-else>
<input class="username" type="text" placeholder="用户名" />
<input class="password" type="password" placeholder="密码" />
<button class="confirm-btn" @click="confirm">提交</button>
</template>
</div>
</template>
const puppeteer = require("puppeteer-core");
async () => {
// 打开浏览器
const browser = await puppeteer.launch({
headless: false, // 是否无头,设置为 `false` 可以看到浏览器界面,设置为 `true` 则会在后台运行,看不到浏览器界面
executablePath:
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", // 浏览器路径
defaultViewport: null, // 默认视窗大小 { width: 1920, height: 1080 }
});
// 打开新页签
const page = await browser.newPage();
// 跳转前到开始时间
const startTime = performance.now();
// 页签跳转到一个新地址(案例中是跳转到百度)
await page.goto("https://www.baidu.com");
await page.goto("http://locahost:5173/login");
const loginBtn = await page.$(".login"); // 获取登录按钮
await loginBtn.click(); // 模拟点击
const user = await page.waitForSelector(".username"); // 获取对应的用户输入框
await user.type("admin"); // 输入用户名
const pass = await page.$(".password"); // 获取对应的密码输入框,能够获取到用户输入框说明密码输入框也出来了,可以直接 page.$
await pass.type("123456"); // 输入密码
const comfirmBtn = await page.$(".comfirm-btn"); // 获取对应的提交按钮
await comfirmBtn.click(); // 模拟点击
await page.waitForNavigation(); // 等待页面跳转完成
console.log(Date.now() - startTime); // 操作耗时
browser.close(); // 关闭浏览器
};
拓展
page.waitForSelector
方法和 page.$
方法都是用于获取页面的 DOM 元素,二者区别在于 page.waitForSelector
方法会等待元素出现在页面上,而 page.$
方法则不会等待,只要元素存在即可。因此如果确保元素已经出现在页面上,可以使用 page.$
方法,否则可以使用 page.waitForSelector
方法。
全局工具
在 package.json
中配置 bin
对象,添加命令,配置对应要执行的 js
文件。在 index.js
文件中首行添加注释,表示该文件内容需要在 Node 环境下运行。
{
"bin": {
"mytest": "./index.js"
}
}
#! /usr/bin/env node
终端输入命令 npm link
即可发布到本地全局。如果想要不写死地址,而是在命令行后面加上地址测试,可以修改一下 index.js
文件获取地址那段代码,通过 process.argv
获取命令行携带的地址。
await page.goto("https://www.baidu.com");
await page.goto(process.argv[2] || "https://www.baidu.com");
mytest https://www.bilibili.com
类推扩展
工程化建设一大方向为项目自动化脚本建设,通过编写脚本,实现项目构建、测试、部署等自动化,提升开发效率,降低人工成本。
- 项目经常需要基于模板
copy
,然后做一些更改,可以编写一个自动化copy
脚本,copy
的时候自动把copy
后要进行的一些更改改好,不需要copy
后自己再去改 - 页面模板创建脚本
- 根据接口文档自动生成
mock
文件