前言
前端自动化测试是前端同学在开发过程中必不可少的技能,拥有了这项技能,我们可以及时发现问题解决问题,让代码更健壮,让功能更可靠,让性能更优化!
搭建一个简单的测试项目
执行命令 npm init -y
然后打开编译器(我用vsCode)的终端,安装依赖 npm install,一个简单的项目就搭建成功了!
这里我们借助于Puppeteer, 它是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。 Puppeteer API 是分层次的,反映了浏览器结构。www.w3cschool.cn/puppeteer/p…
执行命令 npm install puppeteer-core
puppeteer-core的体积相对puppeteer小很多,因为它不包含浏览器内核,我们每个人的电脑上都有浏览器,只要指定浏览器的安装地址即可使用。
实现一个首屏渲染时间测试功能
在我们创建好的项目根目录下,新建一个index.js文件,直接上代码
const pup = require("puppeteer-core");
async function run() {
//注册浏览器
//由于puppeteer-core不包含浏览器内核,需要给出电脑浏览器的安装地址
const browser = await pup.launch({
executablePath: "C:/Program Files/Google/Chrome/Application/chrome.exe", //浏览器安装地址
});
//打开页面
const page = await browser.newPage();
//开始时间
const startTime = performance.now();
await page.goto("https://sports.qq.com/");
//结束时间
const endTime = performance.now();
//计算时间差(秒)
const time = endTime - startTime;
console.log("页面打开时间:", time);
//关闭浏览器
//await browser.close();
}
run();
我们随便测试一个网页的打开时间,然后在终端执行命令 node index.js
获取performance.timing
performance有一个timing属性,里面记录了很多指标,我们可以查看一下
const pup = require("puppeteer-core");
async function run() {
//注册浏览器
//由于puppeteer-core不包含浏览器内核,需要给出电脑浏览器的安装地址
const browser = await pup.launch({
executablePath: "C:/Program Files/Google/Chrome/Application/chrome.exe", //浏览器安装地址
headless: false, //是否无头浏览器
});
//打开页面
const page = await browser.newPage();
//开始时间
const startTime = performance.now();
await page.goto("https://www.baidu.com/");
//结束时间
const endTime = performance.now();
//计算时间差(秒)
const time = endTime - startTime;
console.log("页面打开时间:", time);
//打开浏览器环境 获取performance.timing
let timing = JSON.parse(
await page.evaluate(() => {
//获取performance.timing
return JSON.stringify(window.performance.timing);
})
);
console.log("timing:", timing);
//关闭浏览器
//await browser.close();
}
run();
再到控制台运行 node index.js
就可以看到timing对象的各种属性值。
计算页面某个核心区域出现的时间
背景:页面区域的内容需要异步请求从后端获取来渲染,我们需要知道这部门的内容用户需要等待多久才可以看到。
我准备了一个例子,看代码:
import { useEffect, useState } from "react";
import "./inde.css";
const Login = () => {
//定义一个数组类型
type ArrayObj = Array<number>;
const [dataList, setDataList] = useState([] as ArrayObj);
useEffect(() => {
setTimeout(() => {
setDataList([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
}, 2000);
}, []);
return (
<div className="login-container">
{/* <div className="point"></div> */}
{dataList.map((item, index) => {
return (
<div className="list-item" key={index}>
{item}
</div>
);
})}
</div>
);
};
export default Login;
这是一个用react写的页面,里面模拟了异步请求,渲染数据列表,页面是这样的:
我们接下来就要测试这个列表开始获取,到浏览器渲染完成需要多久!!!
我们重新在测试项目中创建一个index2.js,代码如下:
const pup = require("puppeteer-core");
async function run() {
//注册浏览器
//由于puppeteer-core不包含浏览器内核,需要给出电脑浏览器的安装地址
const browser = await pup.launch({
executablePath: "C:/Program Files/Google/Chrome/Application/chrome.exe", //浏览器安装地址
headless: false, //是否无头浏览器
});
//打开页面
const page = await browser.newPage();
//开始时间
const startTime = performance.now();
await page.goto("http://localhost:5173/#/login");
//等到list-item这个元素可以被选择,即等到list-item这个元素被渲染出来
await page.waitForSelector(".list-item");
//结束时间
const endTime = performance.now();
//计算时间差(秒)
const time = endTime - startTime;
console.log("list渲染完成时间:", timing);
//关闭浏览器
//await browser.close();
}
run();
这里我们用了一个 page.waitForSelector(".list-item") 函数,意思就是等到list-item这个元素可以被选择,即等到list-item这个元素被渲染出来,然后我们再计算时间差,执行代码:
计算某个链路的完成时间(不考虑人类反应速度,纯粹程序本身完成某个操作链路需要的时间)
我创建了一个登录环境,登录成功后跳转到上面包含列表的页面,上代码:
const pup = require("puppeteer-core");
async function run() {
//注册浏览器
//由于puppeteer-core不包含浏览器内核,需要给出电脑浏览器的安装地址
const browser = await pup.launch({
executablePath: "C:/Program Files/Google/Chrome/Application/chrome.exe", //浏览器安装地址
headless: false, //是否无头浏览器
});
//打开页面
const page = await browser.newPage();
//开始时间
const startTime = performance.now();
await page.goto("http://localhost:5173/#/login");
const user = await page.$(".username"); //获取用户名
const password = await page.$(".password"); //获取密码
await user.type("admin"); //输入用户名
await password.type("admin"); //输入密码
const button = await page.$(".login-btn"); //获取登录按钮
await button.click(); //点击登录按钮
await page.waitForNavigation(); //等待页面跳转
//等到list-item这个元素可以被选择,即等到list-item这个元素被渲染出来
await page.waitForSelector(".list-item");
//结束时间
const endTime = performance.now();
//计算时间差(秒)
const time = endTime - startTime;
console.log("list渲染完成时间:", time);
//关闭浏览器
//await browser.close();
}
run();
从登录到list-item渲染完成,这个过程被称为一个功能链路,这个过程的完整消耗时间我们就可以计算出来了,如图:
这种测试其实人工来完成是比较难的,我们还可以进行多次循环,比如调用run()方法100次,来看一个平均值等。
通过脚本link为全局指令
我们每次测试都更改源码显然是不合适的,我们需要把每一个测试独立出来,放到配置文件中,通过命令的形式指定执行某一个文件。
//package.json文件增加bin属性
{
"name": "autoTest",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"stest": "./index3.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"puppeteer-core": "^23.4.1"
}
}
最终我们只要在控制台输入stest,就可以自动执行index3.js这个测试任务,但在这之前,需要给index3.js指定环境,如图:
#! /usr/bin/env node
//指定使用node环境
const pup = require("puppeteer-core");
async function run() {
//注册浏览器
//由于puppeteer-core不包含浏览器内核,需要给出电脑浏览器的安装地址
const browser = await pup.launch({
executablePath: "C:/Program Files/Google/Chrome/Application/chrome.exe", //浏览器安装地址
headless: false, //是否无头浏览器
});
//打开页面
const page = await browser.newPage();
//开始时间
const startTime = performance.now();
await page.goto("http://localhost:5173/#/login");
const user = await page.$(".username"); //获取用户名
const password = await page.$(".password"); //获取密码
await user.type("admin"); //输入用户名
await password.type("admin"); //输入密码
const button = await page.$(".login-btn"); //获取登录按钮
await button.click(); //点击登录按钮
await page.waitForNavigation(); //等待页面跳转
//等到list-item这个元素可以被选择,即等到list-item这个元素被渲染出来
await page.waitForSelector(".list-item");
//结束时间
const endTime = performance.now();
//计算时间差(秒)
const time = endTime - startTime;
console.log("list渲染完成时间:", time);
//关闭浏览器
//await browser.close();
}
run();
如上图,在index3.js顶部添加 #! /usr/bin/env node,来查找node环境进行运行。
然后我们打开控制台 输入指令 npm link (npm link用来在本地项目和本地npm包之间建立连接,可以在本地进行模块测试),然后输入 stest ,就可以自动执行index3.js文件中的测试功能了,效果如图:
我们也可以将地址进行动态处理,如图:
这样我们在输入stest 后面就可以跟一个地址参数,比如 stest http://localhost:5173/#/login 这样就可以动态测试任何地址了,如图: