WebdriverIO 自动化协议体系深度解析:WebDriver、Bidi、Appium 与厂商扩展协议
2026/9/16 14:26:20 网站建设 项目流程

WebdriverIO 自动化协议体系深度解析:WebDriver、Bidi、Appium 与厂商扩展协议

【免费下载链接】webdriverioNext-gen browser and mobile automation test framework for Node.js项目地址: https://gitcode.com/GitHub_Trending/we/webdriverio

本指南以 WebdriverIO 官方文档 Protocols.md 为核心,系统讲解 WebdriverIO 如何依赖多种自动化协议与远程设备(浏览器、移动设备、电视等)通信:协议命令如何被装载到 Browser 与 Element 对象上、每种协议的技术定位与适用场景,以及底层源码是如何按会话环境选择协议的。读完本文,你将理解 WebDriver、WebDriver Bidi、Appium、Chromium、Firefox、Sauce Labs、Selenium Standalone 与已废弃的 JSON Wire 协议之间的区别,并能结合源码确认协议命令的分发机制。

协议体系概览:WebdriverIO 如何与远程设备通信

WebdriverIO 是一个自动化框架,它自身并不直接操作浏览器内核,而是通过一系列自动化协议来驱动远程代理(remote agent),这些远程代理既可能是浏览器,也可能是移动设备或智能电视。不同的远程设备对应不同的协议:例如浏览器通常走 WebDriver 协议,移动端测试走 Appium 协议,Chromium 内核浏览器还可以获得 Chromium 协议的额外命令。

WebdriverIO 会把协议命令分配到 Browser 或 Element 对象上,具体分配到哪个对象,取决于远程服务器(如浏览器驱动)返回的会话信息。内部几乎所有与远程代理的交互,最终都会落到协议命令上。

不过,协议命令是偏底层的“原始命令”,直接使用并不友好。以获取元素文本为例,若完全使用协议命令,代码是这样的:

const searchInput = await browser.findElement('css selector', '#lst-ib') await client.getElementText(searchInput['element-6066-11e4-a52e-4f735466cecf'])

其中element-6066-11e4-a52e-4f735466cecf是 WebDriver 规范定义的元素引用键(Element Reference Key),协议要求先通过findElement拿到元素引用,再把它当作参数传给getElementText。而使用 Browser / Element 提供的便捷命令,同样的需求可以简化为一行:

$('#lst-ib').getText()

$定位元素后返回的 Element 对象内部已经封装了元素引用,getText()则由 WebdriverIO 高层命令在内部替我们完成协议调用。这也是整个 WebdriverIO 使用体验的核心:底层协议保持标准与稳定,上层命令保持简洁与可读

协议的源码组织与装载机制

要理解这套协议体系,先看仓库中的两个关键位置:协议定义与协议装载。

协议定义:packages/wdio-protocols

WebdriverIO 把所有协议命令的“元数据”集中放在packages/wdio-protocols包中,其src/protocols目录下有 8 个协议定义文件,正好对应文档中介绍的协议:

文件对应协议
webdriver.tsWebDriver 协议
webdriverBidi.tsWebDriver Bidi 协议
appium.tsAppium 协议
chromium.tsChromium 协议
gecko.tsFirefox(Geckodriver)协议
saucelabs.tsSauce Labs 协议
selenium.tsSelenium Standalone 协议
mjsonwp.tsMobile JSON Wire 协议

在 index.ts 中,这 8 个协议被统一导入并导出,同时通过ProtocolCommands接口把各协议命令合并为一个总类型。值得留意的是其中Omit<MJSONWPCommands, keyof AppiumCommands | keyof ChromiumCommands>的写法——由于 Mobile JSON Wire 的很多命令与 Appium、Chromium 命令重叠,合并类型时先剔除重复项。

协议定义的数据结构在 types.ts 中说明:每个协议是一个Protocol,即“端点路径 → HTTP 方法 → 命令端点”的映射。CommandEndpoint描述了命令名、描述、规范参考链接(ref)、参数、路径变量、支持的移动环境、返回类型等;HTTP 方法支持POST/GET/DELETE,Bidi 命令则使用socket。这也解释了为什么上层能自动生成参数校验——因为每个命令的parameters都声明了类型与是否必填。

协议装载:packages/webdriver/src/utils.ts

协议命令真正被“挂”到浏览器实例上,发生在packages/webdriver/src/utils.ts的 getPrototype 函数中。它根据会话环境标志(isW3CisMobileisChromiumisFirefoxisSauceisSeleniumStandalone)用deepmerge合并出最终的协议集合:

  • 移动端会话同时合并AppiumProtocolWebDriverProtocol(因为 Appium 中仍在使用部分旧 JSONWire 命令,如地理位置读取);
  • W3C 会话启用WebDriverBidiProtocol
  • 移动端还会再合并MJsonWProtocol
  • Chromium、Firefox、Sauce Labs、Selenium Grid 会话分别追加各自协议的“超集命令”。

合并完成后,遍历所有端点为每个命令生成一个command(method, endpoint, commandData, ...)包装函数,写入 prototype。最终在 packages/webdriver/src/index.ts 的WebDriver.newSession中,通过webdriverMonad把“基础协议命令 + 环境标志 + 用户自定义命令 + Bidi 处理器”组合成可用的客户端实例。

会话环境标志本身由sessionEnvironmentDetector(来自@wdio/utils)根据新建会话返回的capabilities推导,并在 getEnvironmentVars 中作为isW3CisMobileisIOSisAndroidisFirefoxisSauceisSeleniumStandaloneisChromiumisBidi等属性挂到实例上,方便用户代码判断当前运行环境。

WebDriver 协议:基于真实浏览器的自动化标准

WebDriver 协议是用于浏览器自动化的 Web 标准(W3C 规范)。与其他 E2E 工具不同,它保证自动化发生在用户真实使用的浏览器上——Firefox、Safari、Chrome,以及 Chromium 内核的 Edge 等,而不是只在 WebKit 这类与真实浏览器差异很大的浏览器引擎上运行。

WebDriver 协议相比 Chrome DevTools 这类调试协议的优势在于:

  • 提供一组跨浏览器一致的命令,无论驱动哪款浏览器,交互方式完全相同,从而显著降低脚本在不同浏览器间的 flakiness(不稳定)概率;
  • 天然支持大规模并行——借助 Sauce Labs、BrowserStack 等云厂商,把测试分发到海量真实浏览器环境。

在协议定义文件 webdriver.ts 中可以找到 WebDriver 规范的全部命令,例如:

  • POST /sessionnewSession:创建新的 WebDriver 会话,失败则返回 session not created 错误;
  • DELETE /session/:sessionIddeleteSession:关闭与当前会话关联的所有顶级浏览上下文、终止连接并结束会话;
  • GET /statusstatus:查询远程端是否可以创建新会话;
  • GET/POST /session/:sessionId/timeoutsgetTimeouts/setTimeouts:读写会话的scriptpageLoadimplicit三类超时;
  • GET/POST /session/:sessionId/urlgetUrl/navigateTo:读取或跳转当前顶级浏览上下文的 URL。

这些命令全部带ref指向 W3C 规范的具体章节,属于协议层面对标准的一一映射。

WebDriver Bidi 协议:双向通信的第二代协议

WebDriver Bidi 协议是 WebDriver 的第二代协议,目前仍在由各大浏览器厂商共同推进中。相比前代协议,它的核心变化是:

  • 双向通信(即 “Bidi”):框架与远程设备之间既能发送命令,也能持续接收事件,不再只是“一问一答”的 HTTP 请求;
  • 更强的浏览器内省(introspection)能力:引入 browsing context、network、script、storage 等新原语,更适合自动化现代 Web 应用。

从 types.ts 的SupportedMethods可以看出现有 Bidi 命令的覆盖范围:会话方法(session.statussession.newsession.endsession.subscribe)、浏览器方法(如browser.getClientWindowsbrowser.createUserContext)、浏览上下文方法(如browsingContext.navigatebrowsingContext.captureScreenshotbrowsingContext.print)、网络方法(如network.addInterceptnetwork.failRequestnetwork.continueWithAuth)、脚本方法(如script.evaluatescript.callFunctionscript.addPreloadScript)、存储方法、日志方法(log.entryAdded)以及输入方法(input.performActionsinput.setFiles)。这些命令定义在自动生成的 webdriverBidi.ts 中,文件头部注明该文件由规范生成,可通过项目根目录的npm run generate:bidi重新生成。

自动开启 Bidi

文档强调:由于该协议仍在演进,浏览器会逐步增加新特性,而使用 WebdriverIO 便捷命令的用户无需任何改动,框架会在浏览器可用时自动利用新协议能力。这一点在源码中有直接体现:startWebDriverSession 会自动为会话开启 Bidi——除非用户显式设置wdio:enforceWebDriverClassic: true,或请求的是不支持 Bidi 的 Safari 会话,否则它会把capabilities.alwaysMatch.webSocketUrl置为true,同时将unhandledPromptBehavior设为'ignore'让框架自己处理弹窗。

底层连接与命令路由

Bidi 通信基于 WebSocket。在 packages/webdriver/src/index.ts 的newSession中,当检测到会话 capabilities 包含webSocketUrl时,会调用initiateBidi建立连接并注册BidiHandler,之后把所有收到的 Bidi 消息通过parseBidiMessage解析并派发给浏览器实例。连接相关的实现位于packages/webdriver/src/bidi目录:socket.ts(WebSocket 封装)、handler.ts(消息处理)、core.tslocalTypes.tsremoteTypes.ts(类型定义)。

在 command.ts 中还有一个重要细节:如果用户在未建立 Bidi 会话时调用了 Bidi 命令,会抛出明确错误,提示“需要设置webSocketUrl: true并确保浏览器支持”。这保证了错误信息对使用者友好且可定位。

Appium:一套协议,覆盖移动/桌面/IoT 设备

Appium 项目致力于自动化移动设备、桌面设备以及各类 IoT 设备。WebDriver 聚焦浏览器与 Web,而 Appium 的愿景是把同一套思路推广到任意设备。除了 WebDriver 定义的标准命令外,Appium 还提供了大量设备特定命令。对移动测试而言,这意味着可以用同一份测试代码同时覆盖 Android 与 iOS 应用。

根据 Appium 官方文档,Appium 的设计遵循四条哲学原则(即 four tenets):

  • 自动化时不应要求重新编译或修改被测应用
  • 不应被锁定在某种特定语言或框架上;
  • 移动自动化框架在自动化 API 上不应重复造轮子
  • 移动自动化框架应当开源,无论是精神、实践还是名义上。

Appium 命令与移动会话

在 appium.ts 中可以看到大量移动相关命令,例如:

  • GET /session/:sessionId/contextgetAppiumContextPOST ...switchAppiumContextGET /session/:sessionId/contextsgetAppiumContexts:用于原生 App(NATIVE_APP)与 WebView 上下文之间的切换与枚举,这是混合应用测试的关键能力;
  • 各类设备设置、截图、录屏、剪贴板、传感器模拟等命令。

从源码看,Appium 协议还并入了 Chromium 的日志命令(/session/:sessionId/se/log/types/session/:sessionId/se/log),并标记getSession命令为 deprecated(建议改用getAppiumSessionCapabilities)。

直连配置:appium:directConnect

Appium 新会话响应中可能带有appium:directConnectProtocolappium:directConnectHostappium:directConnectPathappium:directConnectPort信息,用于绕过负载均衡直连实际 Appium host。只有当用户在配置中启用enableDirectConnect时,WebdriverIO 才会执行 setupDirectConnect,把客户端连接参数替换为直连地址,从而降低代理带来的开销与不稳定因素。

Chromium:Chromedriver/Edgedriver 的命令超集

Chromium 协议在 WebDriver 协议之上提供了超集命令,仅在通过Chromedriver(用于 Chrome)或Edgedriver(用于 Microsoft Edge)运行自动化会话时可用。在 chromium.ts 中定义了 28 个命令,包含 CDP(Chrome DevTools Protocol)相关的命令,例如发送 CDP 命令(sendCommand)、启动/停止性能数据收集、获取网络状态等。会话装载时,只有当isChromium标志为真(即浏览器是 Chrome/Edge)才会合并该协议。

Firefox:Geckodriver 的命令超集

Firefox 协议同样是在 WebDriver 协议之上的超集命令,仅在通过Geckodriver运行 Firefox 自动化会话时可用。gecko.ts 中的典型命令包括:

  • GET /session/:sessionId/moz/screenshot/fullfullPageScreenshot:捕获整页截图;
  • GET/POST /session/:sessionId/moz/contextgetMozContext/setMozContext:在CHROMECONTENT两种上下文间切换。CONTENT上下文拥有普通 Web 文档权限(如同在页面中执行任意 JavaScript),而CHROME上下文拥有提升的权限,可以直接操纵浏览器 chrome(XUL 工具集),适合扩展开发类测试。

同样的,只有isFirefox标志为真时该协议才会被装载。

Sauce Labs:云厂商的命令超集

Sauce Labs 协议在 WebDriver 之上提供超集命令,仅在使用 Sauce Labs 云运行自动化会话时可用。saucelabs.ts 中定义了 Sauce 特有的命令,例如获取/设置网络条件(throttleNetwork)、获取/设置模拟设备内存、配置 JS 执行器等云端能力。会话装载时通过isSauce标志决定是否合并该协议。

Selenium Standalone:Selenium Grid 的命令超集

Selenium Standalone 协议在 WebDriver 之上提供超集命令,仅在使用 Selenium Grid(或 Selenium Standalone Server)运行自动化会话时可用。selenium.ts 中的命令主要面向 Grid 运维场景,例如:

  • GET /se/grid/hub/configgetHubConfig:获取 Hub 配置;
  • POST /se/grid/testsessiongridTestSession:获取或分配测试会话;
  • GET /se/grid/proxy/:idgridProxyDetails:查询某个节点代理详情;
  • 文件上传/下载相关命令(filegetDownloadableFilesdownloaddeleteDownloadableFiles)。

CommandEndpoint类型中的isHubCommand字段即是为这类命令设计的——标记为 Hub 命令的端点(例如 Grid 治理类命令)只能发给 Selenium Hub 节点,WebdriverIO 在生成请求时会据此区分请求目标。

已废弃协议:JSON Wire Protocol 与 Mobile JSON Wire Protocol

JSON Wire Protocol(JWP)是 WebDriver 的前代协议,如今已deprecated。虽然某些环境下仍可能支持部分命令,但官方明确不推荐使用其中的任何命令。

Mobile JSON Wire Protocol(MJSONWP)是在 JSON Wire Protocol 之上扩展的移动命令超集。由于 JWP 已废弃,MJSONWP 同样进入deprecated状态。Appium 可能仍支持其中的部分命令(如获取/设置地理位置等历史遗留接口),但同样不推荐使用。

在协议装载逻辑(getPrototype)中可以看到 WebdriverIO 的兼容策略:移动端会话仍会合并MJsonWProtocol,仅仅是为了兼容 Appium 中仍在使用的少量旧命令,属于为生态兼容而保留,并非推荐在新代码中使用。对于确有历史包袱需要调用已废弃命令的场景,WebdriverIO 在 command.ts 中会输出 deprecation 警告,并支持通过环境变量DISABLE_WEBDRIVERIO_DEPRECATION_WARNINGS抑制提示(某些内部流程需要用到已废弃命令时会设置该变量)。

协议命令的运行时校验与请求链路

理解每种协议之后,再看协议命令被调用时发生的完整链路(实现在 packages/webdriver/src/command.ts):

  1. Bidi 命令检查:若目标是 Bidi 命令但未建立 Bidi 会话,直接抛出带指引的错误;
  2. 参数数量与类型校验:根据CommandEndpoint.parameters中声明的必填项与类型,逐参数校验;路径变量(如:sessionId)会先被 URL 编码并替换进端点;
  3. 请求发送:通过Request类发起 HTTP 请求(浏览器环境使用FetchRequest,见 browser.ts),同时发出commandrequest.startrequest.endresult等事件,便于日志、reporter 与中间件监听;
  4. 会话删除处理deleteSession会关闭 Bidi 连接、按shutdownDriver选项决定是否终止驱动进程;已删除会话的实例再执行命令会被manageSessionAbortions拦截,避免无意义请求。

这套机制保证了“协议命令 + 参数声明”这一份元数据同时驱动了类型提示、参数校验、文档生成与运行时调用,是理解 WebdriverIO 体系的关键。

结语

WebdriverIO 之所以能同时覆盖浏览器、移动端、云厂商与 Selenium Grid 等众多场景,正是得益于这套清晰的协议分层:

  • **WebDriver(W3C 标准)**是浏览器自动化的基石,保证真实浏览器、跨浏览器一致性与大规模并行能力;
  • WebDriver Bidi用双向通信与内省原语推进下一代浏览器自动化,并已由 WebdriverIO 默认自动开启;
  • Appium把同一套理念延伸到移动、桌面与 IoT 设备;
  • Chromium / Firefox / Sauce Labs / Selenium Standalone则是面向特定驱动或平台的命令超集,仅在对应会话中按需装载;
  • JSON Wire 与 Mobile JSON Wire属于历史遗留,官方已标记废弃。

所有这些协议都以数据文件形式定义在 packages/wdio-protocols/src/protocols 下,并由 packages/webdriver/src/utils.ts 依据会话环境动态装配。日常使用中,开发者几乎不会直接调用协议命令,而是通过 Browser 与 Element 的便捷 API 享受底层协议带来的标准化与稳定性——这正是 WebdriverIO 协议设计的最终目的。

【免费下载链接】webdriverioNext-gen browser and mobile automation test framework for Node.js项目地址: https://gitcode.com/GitHub_Trending/we/webdriverio

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询