news 2026/4/14 23:20:59

【获取WebSocket】使用 Playwright 监听 Selenium 自动化测试中的 WebSocket 消息(一)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【获取WebSocket】使用 Playwright 监听 Selenium 自动化测试中的 WebSocket 消息(一)

使用 Playwright 监听 Selenium 自动化测试中的 WebSocket 消息(一)

文章目录

  • 使用 Playwright 监听 Selenium 自动化测试中的 WebSocket 消息(一)
    • 一、前言:为什么 Selenium 自动化里“看不到” WebSocket?
    • 二、整体技术方案:Selenium 驱动,Playwright 监听
      • 2.1 方案结构概览
      • 2.2 为什么选择 Playwright?
    • 三、环境与前提条件说明
      • 3.1 技术栈前提
      • 3.2 重要约束条件
    • 四、第一步:让 Selenium 启动一个“可被监听”的浏览器
      • 4.1 为什么需要 remote-debugging-port?
      • 4.2 注入 ChromeOptions 的关键时机
      • 4.3 在 TestBase 中注入 remote-debugging-port
    • 五、代码实战:实现 PlaywrightWsCollector(专职监听 WebSocket)
      • 5.1 设计一个可复用的消息模型 WsMessage
      • 5.2 端口“桥接”对象(让 TestBase 能拿到端口)
      • 5.3 PlaywrightWsCollector:核心类骨架
        • 5.3.1 生成空闲端口(多机/多进程安全)
      • 5.4 完整实现:PlaywrightWsCollector.cs
      • 5.5 如何在测试类里“正确初始化” Collector(时序写法)
        • 5.5.1 ClassInitialize:生成端口 + 初始化 Collector,但不连接
        • 5.5.2 TestInitialize:先 base,再 EnsureConnected
      • 5.6 本节小结
      • 下一篇预告

一、前言:为什么 Selenium 自动化里“看不到” WebSocket?

在现代前端应用中,越来越多的核心逻辑通过WebSocket完成,例如:

  • 多人协同编辑(SelectionChange、EditRecord 等实时广播)
  • 实时状态同步
  • 前端操作与后端推送解耦

在浏览器中,这些信息可以通过
DevTools → Network → WebSocket → Messages直观查看。

但在 Selenium 自动化测试中,会遇到一个现实问题:

  • Selenium 3.x没有 DevTools API
  • Selenium 4.x 以上,如果使用了 DevTools API,需要持续更新WebDirver版本以匹配不断更新的浏览器

这在以下场景中会成为瓶颈:

  • 需要验证某个操作是否真的向后端发送了Action:"EditRecord"
  • 需要校验某一步操作触发了几次SelectionChange
  • 仅靠 UI 状态不足以判断功能是否正确

本文将介绍一种借助Playwright辅助Selenium 框架的解决方案:
👉使用 Playwright 作为“旁路监听器”,专门监听 WebSocket。


二、整体技术方案:Selenium 驱动,Playwright 监听

本方案的核心思想是:

Selenium 继续负责“操作页面”,Playwright 只负责“监听浏览器的 WebSocket”。

两者并不是互相替代,而是各司其职。

2.1 方案结构概览

整体结构可以概括为:

  • Selenium

    • 创建并管理 Chrome WebDriver
    • 执行页面操作(点击、输入、拖拽等)
  • Chrome

    • 启动时开启--remote-debugging-port
  • Playwright

    • 通过 Chrome DevTools Protocol(CDP)连接到同一个浏览器实例
    • 监听 WebSocket 帧(FrameSent / FrameReceived)
  • 测试代码

    • 对捕获到的 WebSocket 消息进行解析和断言

2.2 为什么选择 Playwright?

Playwright 在这里的价值主要体现在:

  • 原生支持CDP(Chrome DevTools Protocol)
  • 可以附着到已经存在的浏览器进程
  • 提供page.WebSocket事件,直接获取 WS 帧数据
  • 不影响 Selenium 的 UI 操作

这意味着:
我们不需要重写现有 Selenium 用例,只需额外“接一根线”。


三、环境与前提条件说明

在继续之前,需要明确本文适用的技术前提。

3.1 技术栈前提

本文基于以下环境设计:

  • Selenium WebDriver3.10.x

  • 测试框架:MSTest

  • 浏览器:Chrome

  • Playwright:.NET 官方版本

  • 已存在的自动化框架中:

    • 有统一的TestBase
    • 有 Browser 封装(支持SetChromeOptions

3.2 重要约束条件

这是本文方案成立的关键前提:

  1. 不能修改 Selenium Browser 核心实现

    • CreateWebDriver()是私有方法
    • Browser 类可能来自 DLL
  2. 但可以:

    • 修改TestBase
    • 在测试类中增加辅助逻辑
  3. 测试用例可能在:

    • 多台机器
    • 多进程
    • 并发执行

因此,本方案必须满足:

  • 对现有框架侵入极小
  • 不引入端口冲突
  • 不影响非 WebSocket 用例

四、第一步:让 Selenium 启动一个“可被监听”的浏览器

Playwright 想要监听 WebSocket,有一个前提条件:

浏览器必须开启 remote-debugging-port。

4.1 为什么需要 remote-debugging-port?

Playwright 并不是“魔法监听”,它的本质是:

  • 通过 CDP(Chrome DevTools Protocol)
  • 连接到浏览器调试端口
  • 订阅 Network / WebSocket 事件

如果 Chrome 启动时没有开启该端口,Playwright 无从连接。

4.2 注入 ChromeOptions 的关键时机

在很多 Selenium 框架中:

  • WebDriver 是懒加载的
  • Browser 在第一次访问WebDriver时才真正启动浏览器

幸运的是,大多数成熟框架都会提供一个生命周期钩子,例如:

protectedvirtualvoidAfterInitializeTestDriver()

这个方法的特点是:

  • Browser 已创建
  • WebDriver 尚未创建
  • 正是注入 ChromeOptions 的最佳时机

4.3 在 TestBase 中注入 remote-debugging-port

示例代码如下:

protectedoverridevoidAfterInitializeTestDriver(){base.AfterInitializeTestDriver();if(PlaywrightWsCollectorBridge.DebugPort==0)return;varbrowser=this.ActiveBrowser;if(browser.BrowserType==BrowserType.Chrome){varoptions=newChromeOptions();options.AddArgument($"--remote-debugging-port={PlaywrightWsCollectorBridge.DebugPort}");browser.SetChromeOptions(options);}}

这里做了三件关键的事:

  1. 仅在需要 WebSocket 的测试中生效(通过 DebugPort 判断)
  2. 使用 Chrome 原生支持的--remote-debugging-port
  3. 不修改 Browser 内部实现,只调用公开扩展点

到这里,Selenium 启动的 Chrome 已经具备了“被 Playwright 监听”的能力。


五、代码实战:实现 PlaywrightWsCollector(专职监听 WebSocket)

这一节的目标很明确:把“DevTools 里 WS → Messages 面板看到的东西”,变成测试代码里可读取、可切片、可断言的数据结构。
同时要满足几个工程要求:

  • Playwright不接管 UI,只监听;
  • 连接必须通过CDP 端口,而端口是 Selenium 启动 Chrome 时注入的;
  • 避免常见坑:.NET 没有 IBrowser.ContextCreatedECONNREFUSED等;
  • 能做到“只取某一步操作产生的 WS 消息”,而不是全程污染。

5.1 设计一个可复用的消息模型 WsMessage

我们不仅要拿到文本,还要知道它属于:

  • 上箭头 / 下箭头(Sent / Received)
  • 以及消息发生顺序(用于“操作切片”)
publicclassWsMessage{publiclongSeq{get;set;}// 递增序号:用于切片publicstringMessageType{get;set;}// "Sent" / "Received"publicstringText{get;set;}// WebSocket 帧内容(一般是 JSON)}

5.2 端口“桥接”对象(让 TestBase 能拿到端口)

在第 4 节里已经在TestBase.AfterInitializeTestDriver()注入了:

--remote-debugging-port=xxx

TestBase自己并不知道端口是什么,因此我们用一个小桥接类存放端口值即可:

publicstaticclassPlaywrightWsCollectorBridge{publicstaticintDebugPort{get;set;}=0;}

约定:

  • DebugPort == 0:表示当前用例不需要 WS 监听;
  • 非 0:TestBase 注入该端口,Playwright 用同一个端口连接。

5.3 PlaywrightWsCollector:核心类骨架

这个类负责:

  1. 生成一个可用端口(供 Selenium 启动 Chrome)
  2. 在浏览器启动后,通过 CDP 连接
  3. hook page 的 WebSocket 事件
  4. 收集消息、切片、分类、清理

关键点:不要在构造函数里 Connect,否则浏览器还没启动就连,会直接ECONNREFUSED

5.3.1 生成空闲端口(多机/多进程安全)
usingSystem.Net;usingSystem.Net.Sockets;publicstaticintGenerateFreePort(){varlistener=newTcpListener(IPAddress.Loopback,0);listener.Start();intport=((IPEndPoint)listener.LocalEndpoint).Port;listener.Stop();returnport;}

5.4 完整实现:PlaywrightWsCollector.cs

说明:这里使用127.0.0.1,避免某些机器localhost解析到 IPv6::1导致连接异常。

usingMicrosoft.Playwright;usingSystem.Collections.Concurrent;usingSystem.Threading;usingSystem.Linq;publicclassPlaywrightWsCollector:IDisposable{privateIPlaywright_playwright;privateIBrowser_browser;privatereadonlyConcurrentBag<WsMessage>_messages=newConcurrentBag<WsMessage>();privatelong_seq=0;privatebool_connected=false;privatebool_pageHooked=false;publicintDebugPort{get;}publicPlaywrightWsCollector(intdebugPort){DebugPort=debugPort;// 仅保存端口,不做连接}/// <summary>/// 在 Selenium 浏览器启动(带 remote-debugging-port)后调用。/// </summary>publicvoidEnsureConnected(){if(_connected)return;_playwright=Playwright.CreateAsync().GetAwaiter().GetResult();varurl=$"http://127.0.0.1:{DebugPort}";_browser=_playwright.Chromium.ConnectOverCDPAsync(url).GetAwaiter().GetResult();HookExistingContexts(_browser);_connected=true;}privatevoidHookExistingContexts(IBrowserbrowser){// .NET 里没有 IBrowser.ContextCreated,所以只能:// 1) 先 hook 现有 contextsforeach(varctxinbrowser.Contexts){HookContext(ctx);}}privatevoidHookContext(IBrowserContextctx){// hook 已有 pageforeach(varpageinctx.Pages){HookPage(page);}// hook 新打开的 page(例如 Selenium 新开 tab/window)ctx.Page+=(_,page)=>HookPage(page);}privatevoidHookPage(IPagepage){// 避免重复 hook:同一个测试通常只关心当前页面的 WSif(_pageHooked)return;page.WebSocket+=(sender,ws)=>{ws.FrameSent+=(s2,frame)=>{AddWs("Sent",frame.Text);};ws.FrameReceived+=(s3,frame)=>{AddWs("Received",frame.Text);};};_pageHooked=true;}privatevoidAddWs(stringtype,stringtext){varid=Interlocked.Increment(ref_seq);_messages.Add(newWsMessage{Seq=id,MessageType=type,Text=text});}publicvoidClear(){while(_messages.TryTake(out_)){}Interlocked.Exchange(ref_seq,0);}// 核心切片:只取某一步操作发生后的 WSprivateList<WsMessage>CaptureCore(ActionuiAction,intwaitMs){varstart=Interlocked.Read(ref_seq);uiAction();Thread.Sleep(waitMs);return_messages.Where(m=>m.Seq>start).OrderBy(m=>m.Seq).ToList();}publicList<string>CaptureTexts(ActionuiAction,intwaitMs=1000)=>CaptureCore(uiAction,waitMs).Select(m=>m.Text).ToList();publicList<WsMessage>CaptureRaw(ActionuiAction,intwaitMs=1000)=>CaptureCore(uiAction,waitMs);// 方向过滤(可选:带是否包含空消息参数)publicIEnumerable<string>OnlyReceived(IEnumerable<WsMessage>list,boolcontainEmpty=false){varq=list.Where(m=>m.MessageType=="Received");if(!containEmpty){q=q.Where(m=>!string.IsNullOrWhiteSpace(m.Text)&&m.Text!="{}");}returnq.Select(m=>m.Text);}publicIEnumerable<string>OnlySent(IEnumerable<WsMessage>list,boolcontainEmpty=false){varq=list.Where(m=>m.MessageType=="Sent");if(!containEmpty){q=q.Where(m=>!string.IsNullOrWhiteSpace(m.Text)&&m.Text!="{}");}returnq.Select(m=>m.Text);}publicvoidDispose(){_browser?.CloseAsync().GetAwaiter().GetResult();_playwright?.Dispose();}}

5.5 如何在测试类里“正确初始化” Collector(时序写法)

这一段非常重要:端口必须先确定,TestBase 必须用这个端口启动 Chrome,Chrome 启动后 Collector 才能连接。

5.5.1 ClassInitialize:生成端口 + 初始化 Collector,但不连接
staticPlaywrightWsCollector_collector;[ClassInitialize]publicstaticvoidClassInit(TestContextctx){intport=PlaywrightWsCollector.GenerateFreePort();PlaywrightWsCollectorBridge.DebugPort=port;// 让 TestBase 注入该端口_collector=newPlaywrightWsCollector(port);}
5.5.2 TestInitialize:先 base,再 EnsureConnected
[TestInitialize]publicoverridevoidTestInitialize(){base.TestInitialize();// 触发 Selenium 启动浏览器(带 remote-debugging-port)_collector.EnsureConnected();// 浏览器已启动,此时才连_collector.Clear();// 每个 case 清空,避免污染}

这段顺序颠倒就会出现错误:

  • ECONNREFUSED:浏览器还没启动就连接
  • 或端口不一致:Selenium 用 A 端口,Playwright 连 B 端口

5.6 本节小结

到这一节为止,框架已经具备了完整的监听能力:

  • Selenium 按原方式执行 UI 操作;
  • Playwright 通过 CDP 附着到同一个浏览器;
  • CaptureTexts(() => 某一步操作)只截取当前操作的 WS;
  • OnlySent/OnlyReceived可进一步对应 DevTools 的上下箭头;

到这里,我们已经完成了本篇的核心目标:

  • 不改动既有 Selenium 框架的前提下

  • 通过remote-debugging-port + Playwright CDP 连接

  • 成功监听到了 Selenium 驱动页面产生的WebSocket 消息

  • 并实现了:

    • 消息方向区分(Sent / Received)
    • 按“单一步操作”切片捕获
    • 为后续断言打下基础

这一步,解决了**“拿到 WebSocket”**的问题。


下一篇预告

《使用 Playwright 监听 Selenium 自动化测试中的 WebSocket(二)》

将重点介绍:

  • WebSocket 消息中Action的解析与统计
  • SelectionChange / EditRecord 次数断言的实现方式
  • PlaywrightWsCollector 在多用例场景下的复用设计
  • 常见坑点总结与工程化建议
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 5:47:32

手把手带你过MCP Azure量子认证实验:5大关键操作步骤不容错过

第一章&#xff1a;MCP Azure量子认证实验概述Azure量子认证实验是面向现代云安全与量子计算交叉领域的一项关键技术实践&#xff0c;旨在验证在量子威胁模型下身份认证机制的可靠性与前向安全性。该实验结合了微软Azure平台提供的量子开发工具包&#xff08;QDK&#xff09;与…

作者头像 李华
网站建设 2026/4/14 22:23:42

HoRNDIS完全指南:在macOS上实现Android USB网络共享的专业方案

HoRNDIS完全指南&#xff1a;在macOS上实现Android USB网络共享的专业方案 【免费下载链接】HoRNDIS Android USB tethering driver for Mac OS X 项目地址: https://gitcode.com/gh_mirrors/ho/HoRNDIS 在现代移动办公环境中&#xff0c;如何快速稳定地将Android设备的…

作者头像 李华
网站建设 2026/4/14 0:47:47

VSCode远程调试时文件不一致?教你4步快速定位并修复同步漏洞

第一章&#xff1a;VSCode远程调试的文件同步问题概述在使用 VSCode 进行远程开发时&#xff0c;开发者常通过 Remote-SSH、Remote-Containers 或 Remote-WSL 扩展连接到远程主机进行代码编辑与调试。尽管这种模式极大提升了跨平台开发效率&#xff0c;但随之而来的文件同步问题…

作者头像 李华
网站建设 2026/4/11 13:58:55

Q#量子计算开发实战(VSCode测试报告深度指南)

第一章&#xff1a;Q# 程序的 VSCode 测试报告在量子计算开发中&#xff0c;测试是确保 Q# 程序正确性的关键环节。Visual Studio Code&#xff08;VSCode&#xff09;结合 Microsoft Quantum Development Kit 提供了完整的测试支持&#xff0c;开发者可直接在编辑器中运行单元…

作者头像 李华