找人做网站需要准备什么材料,百度制作的wordpress工具,优秀软文范例800字,aqqqcom查询很多UI自动化测试工具都具备录制UI自动化测试的能力#xff0c;例如playwright#xff0c;可以通过playwright vscode插件完成录制#xff0c;如下图所示#xff0c;当选择录制脚本时#xff0c;会打开一个浏览器#xff0c;在浏览器中输入被测应用url#xff0c;用户在… 很多UI自动化测试工具都具备录制UI自动化测试的能力例如playwright可以通过playwright vscode插件完成录制如下图所示当选择录制脚本时会打开一个浏览器在浏览器中输入被测应用url用户在web应用上的所有操作都能被录制下来并将录制内容存放在vscode创建的test文件中。 那么UI类测试工具是如何实现录制功能的呢大致原理是通过浏览器的开发者工具协议DevTools Protocol与浏览器进行通信注入和执行 JavaScript 代码并实时捕获和处理用户操作事件将捕获的用户操作事件转换为工具的client script。例如playwright就会转换成playwright得locatoraction脚本。 为了透彻理解UI自动化测试录制工作原理可以从0搭建一个具备录制能力的工具。
初始化项目代码
安装相关依赖和配置package.json文件
mkdir ui-test-tool
cd ui-test-tool
npm init -y
npm install puppeteer express socket.io
{name: ui-test-tool,version: 1.0.0,description: A UI test tool to record user interactions and generate code,main: index.js,scripts: {start: node index.js},dependencies: {express: ^4.17.1,puppeteer: ^19.0.0,socket.io: ^4.4.1}
}构建index.js文件
下面的文件中使用到了socket.io和puppeteer。Socket.IO 是一个基于事件的实时网络库用于在浏览器和服务器之间实现实时、双向通信。Puppeteer是一个Node.js 库它提供了一个高级API来通过开发工具协议控制Chrome/Chromium。 Express是一种保持最低程度规模的灵活 Node.js Web应用程序框架可以快速方便地创建强大的API。 Socket.IO 提供了一些关键的方法和函数用于实现客户端于服务器之间的通信。服务器端Node.js require(socket.io)引入 Socket.IO 库。 const io require(socket.io)(server)创建 Socket.IO 服务器实例并将其绑定到 HTTP 或 HTTPS 服务器。 io.on(connection, (socket) { ... })监听客户端连接事件当有新客户端连接时执行回调函数。 socket.emit(event, data)向特定的客户端发送消息。 socket.on(event, callback)监听客户端发送的消息事件并定义对应的处理逻辑。
客户端浏览器 script src/socket.io/socket.io.js/script在 HTML 中引入 Socket.IO 客户端库。 const socket io()创建客户端 Socket.IO 实例连接到服务器。 socket.emit(event, data)向服务器发送消息。 socket.on(event, callback)监听服务器发送的消息事件并定义对应的处理逻辑。 下面的代码中利用socket.io监听客户端发送的start-recordingmessage,当监听到该消息时会通过puppeteer启动浏览器并在浏览器中开启一个新tab页。另外下面代码中expose了两个方法emitClickEvent和emitHoverSelector这两个方法被window.socket里面的代码调用。实际就是下面的代码中调用window.socket.emit(event,data)的时候实际调用的是emitClickEvent和emitHoverSelector中的代码。 在page.evaluate((){...})方法中首先创建了一个tooltip用于显示当鼠标hover到页面element上的时候显示element的locatortooltip在默认情况下displaynone,只有hover的时候才显示。接着对“mouseover”添加了监听当监听到该操作时会获取目标element的locator当然下面的代码是使用css来获取element的locator。如果是其他UI自动化测试工具例如playwright这里就会生产plawright自己语法格式的locator。除了对“mouseover”添加监听还对click”操作也增加了监听。
import express from express;
import http from http;
import { Server } from socket.io;
import puppeteer from puppeteer;const app express();
const server http.createServer(app);
const io new Server(server);app.use(express.static(public));io.on(connection, (socket) {socket.on(start-recording, async () {const browser await puppeteer.launch({ headless: false });const page await browser.newPage();await page.exposeFunction(emitClickEvent, (selector) {socket.emit(record-action, await page.click(${selector});\n);});await page.exposeFunction(emitHoverSelector, (selector) {socket.emit(record-selector, selector);});await page.evaluateOnNewDocument(() {window.socket {emit: (event, data) {if (event click){window.emitClickEvent(data);} else if (event hover) {window.emitHoverSelector(data);}}};});await page.goto(https://angularjs.realworld.io/#/login);await page.evaluate(() {let path [];const tooltip document.createElement(div);tooltip.style.position absolute;tooltip.style.background rgba(0, 0, 0, 0.7);tooltip.style.color #fff;tooltip.style.padding 5px;tooltip.style.borderRadius 3px;tooltip.style.zIndex 9999;tooltip.style.display none;document.body.appendChild(tooltip);document.addEventListener(mouseover, (event) {const path [];let el event.target;while (el) {let selector el.nodeName.toLowerCase();if (el.id) {selector #${el.id};} else if (el.className) {selector .${Array.from(el.classList).join(.)};} else {let sib el, nth 1;while (sib sib.previousElementSibling) {if (sib.nodeName.toLowerCase() selector) nth;}selector :nth-of-type(${nth});}path.unshift(selector);el el.parentNode;}const selectorPath path.join( );tooltip.innerText selectorPath;tooltip.style.top ${event.pageY}px;tooltip.style.left ${event.pageX}px;tooltip.style.display block;window.socket.emit(hover, selectorPath);});// Hide tooltip on mouseoutdocument.addEventListener(mouseout, () {tooltip.style.display none;});document.addEventListener(click, (event) {let el event.target;while (el) {let selector el.nodeName.toLowerCase();if (el.id) {selector #${el.id};} else if (el.className) {selector .${Array.from(el.classList).join(.)};} else {let sib el, nth 1;while (sib sib.previousElementSibling) {if (sib.nodeName.toLowerCase() selector) nth;}selector :nth-of-type(${nth});}path.unshift(selector);el el.parentNode;}window.socket.emit(click, path.join( ));}, true);});socket.on(disconnect, async () {await browser.close();console.log(Client disconnected);});});
});server.listen(3001, () {console.log(Listening on port 3001);
});构建index.html文件 index.html文件内容在html内容中引入了socket.io.js。当用户点击“start recording”按钮时客户端脚本向服务端发送“start-recording”messagetrigger服务端执行打开浏览器开启新页面的操作。当在打开的页面上点击某个元素时会将脚本显示在textare中。当鼠标hover到页面上的任意元素上时会在旁边显示该元素的selector。
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleUI Test Tool/titlescript src/socket.io/socket.io.js defer/scriptscript typemodule deferdocument.addEventListener(DOMContentLoaded, () {const socket io();document.getElementById(start).addEventListener(click, () {socket.emit(start-recording);});socket.on(record-action, (action) {document.getElementById(code).innerText action;});socket.on(record-selector, (action) {document.getElementById(code).innerText action;});});/script
/head
body
divbutton idstartStart Recording/button/div
div
label forcodeSelector:/labelbr
textarea idcode rows10 cols50/textarea
/div
/body
/html 验证工具效果 通过node index.js命令启动服务。在浏览器中输入启动的服务地址点击Start Recroding按钮就会新开启chrome浏览器并在浏览器中open new page访问angularjs的这个应用当鼠标hover到任意元素时会显示该元素的selector。 以上就是从0搭建UI录制工具的过程。如果是playwright vscode插件的录制具体又是如何实现的呢实际实现原理和上面相同只是细节更加复杂在下一篇博客中将通过阅读源码介绍vscode extension如何实现录制功能的。