上一篇博客从源码层面分析了playwright vscode插件实现原理,在上一篇博客中提到,backend服务是一个websocket服务。这遍博客将介绍如何封装一个websocket服务,通过发送消息来执行playwright测试。
初始化项目
第一步是初始化项目和安装必要的依赖,这里需要安装playwright, @playwright/test和ws两个依赖包。后面启动执行测试的cli.js文件就是来源于@plawright/test这个包。
mkdir playwright-ws-server
cd playwright-ws-server
npm init -y
npm install ws playwright @playwright/test
实现websocket服务
下面的代码中,通过new WebSocket.Server启动一个websocket服务,监听在8085端口。当监听到message.command==“runtest”时,通过spawn启动node进程,执行playwright的测试文件。并把测试结果通过消息发送出去。
const WebSocket = require('ws');
const { spawn } = require('child_process');
const path = require('path');
// WebSocket server setup
const wss = new WebSocket.Server({ port: 8085 });
// Event listener for new connections
wss.on('connection', ws => {
console.log('Client connected');
// Event listener for incoming messages
ws.on('message', message => {
console.log(`Received message: ${message}`);
// Parse the received message
let command;
try {
command = JSON.parse(message);
} catch (e) {
console.error('Invalid JSON:', e);
ws.send(JSON.stringify({ error: 'Invalid JSON' }));
return;
}
// Check if the command is "runtest"
if (command.action === 'runtest') {
const testFilePath = command.testFilePath;
const options = command.options;
// Construct the Playwright test command
const nodePath = '/opt/homebrew/bin/node';
const cliPath = path.resolve('./node_modules/@playwright/test/cli.js');
const configPath = 'playwright.config.js';
const args = [
cliPath,
'test',
'-c', configPath,
testFilePath,
`--headed`,
`--project=${options.project}`,
`--repeat-each=${options.repeatEach}`,
`--retries=${options.retries}`,
`--timeout=${options.timeout}`,
`--workers=${options.workers}`
];
console.log('Executing command:', `${nodePath} ${args.join(' ')}`);
// Spawn the Playwright test process
const testProcess = spawn(nodePath, args, { stdio: 'pipe' });
// Capture stdout and stderr
testProcess.stdout.on('data', data => {
console.log(`stdout: ${data}`);
ws.send(JSON.stringify({ output: data.toString() }));
});
testProcess.stderr.on('data', data => {
console.error(`stderr: ${data}`);
ws.send(JSON.stringify({ error: data.toString() }));
});
// Handle process exit
testProcess.on('close', code => {
console.log(`Child process exited with code ${code}`);
ws.send(JSON.stringify({ exitCode: code }));
});
} else {
ws.send(JSON.stringify({ error: 'Unknown action' }));
}
});
// Event listener for connection close
ws.on('close', () => {
console.log('Client disconnected');
});
});
console.log('WebSocket server is running on ws://localhost:8085');
node server.js命令启动上面的websocket服务,再安装wscat工具,通过wscat工具给服务发送消息,发送后即可看到测试脚本执行结果。
//安装wscat
npm install -g wscat
//连接ws的命令
wscat -c ws://localhost:8080
//发送的message
{
"action": "runtest",
"testFilePath": "/Users/taoli/study/playwrightDemo/tests/test-1.spec.ts:3",
"options": {
"headed": true,
"project": "chromium",
"repeatEach": 1,
"retries": 0,
"timeout": 0,
"workers": 1
}
}
也可以编写client.js文件来发送消息执行测试。下面是client.js的代码。
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:8085');
ws.on('open', () => {
const message = {
action: 'runtest',
testFilePath: '/Users/taoli/study/playwrightDemo/tests/test-1.spec.ts:3',
configPath: 'playwright.config.js',
options: { "project": "chromium", "repeatEach": 1, "retries": 0, "timeout": 0, "workers": 1 }
};
ws.send(JSON.stringify(message));
});
ws.on('message', data => {
console.log('Received:', data);
});
启动server,在另外一个terminal中执行client.js文件,可以看到websocket接受到的message,实际执行的命令如下图红框所示。stdout部分打印了测试执行结果。在执行测试过程中,因为设置--headed模式,所以可以看到开启了浏览器,在浏览器中打开被测应用进行测试。
spawn提供哪些功能
在前面的介绍中,多次提到了spawn,那么spawn有哪些功能呢?spawn 是 Node.js 的 child_process 模块提供的一个方法,用于创建一个新的进程来执行给定的命令。它与 exec 类似,但 spawn 更适合处理长时间运行的进程,并且可以与子进程进行流式交互。
spawn可以启动任何可执行文件,包括 Node.js 程序。这是因为 spawn 本质上是在操作系统中运行一个新进程,将命令和参数传递给这个新进程,即可完成执行操作。
除了执行 Node.js 程序,spawn 可以用来执行几乎任何可执行文件或命令,包括但不限于:
Shell 命令:执行操作系统的命令,如 ls, grep, ping 等。
其他脚本语言:执行 Python, Ruby, Perl 等脚本语言编写的脚本。
系统服务:启动、停止或重启系统服务。
编译工具:运行编译器如 gcc, javac 等。
应用程序:启动其他应用程序或工具,如 git, docker, npm 等。
可以看到spawn功能非常强大,例如python编写的程序,也可以通过spawn来运行,当然,这个运行也可以封装到一个websocket服务中,通过发送和监听消息来执行。