在我们 之前的博客文章 中,我们介绍了 Web 测试生态系统中,通过基于 HTTP 的 WebDriver 标准自动执行浏览器与 DevTools 协议(例如 Chrome DevTools Protocol (CDP))之间权衡。虽然 WebDriver 的基于 HTTP 的方法有很多好处,但我们知道许多开发者发现基于 CDP 的测试工具的额外功能和人体工程学非常吸引人。
很明显,WebDriver 需要发展以满足基于 DevTools 的自动化的能力。然而,这个过程需要时间,我们希望更多的开发者能够在今天使用 Firefox 运行他们的自动化测试。
为此,我们在 Firefox Nightly 中发布了 CDP 部分内容的实验性实现,专门针对使用 Google 的 Puppeteer 进行端到端测试以及 Selenium 4 的基于 CDP 的功能。
对于希望在 Firefox 的稳定版本中使用 CDP 工具的用户,我们目前正在进行一项过程,以在发布通道上启用该功能,我们希望尽快使其可用。
本帖的其余部分将介绍如何使用 Firefox 与基于 CDP 的工具。
Puppeteer 自动化
Puppeteer 是一个 Node.js 库,它在 CDP 之上提供了一个直观的异步浏览器自动化 API。
Puppeteer 本身现在基于我们的 CDP 实现,提供对 Firefox 的实验性支持。这项变更是在与 Puppeteer 维护人员合作中进行的,允许许多现有的 Puppeteer 测试在 Firefox 中运行,只需最小的配置更改。
要将 Puppeteer 与 Firefox 一起使用,请安装 puppeteer 包并将它的 产品选项 设置为“firefox”。从 3.0 版开始,Puppeteer 的 npm install 脚本可以自动为您获取相应的 Firefox Nightly 二进制文件,使您更容易上手。
PUPPETEER_PRODUCT=firefox npm install puppeteer
以下示例演示了如何使用 Puppeteer 在无头模式下启动 Firefox
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
product: 'firefox',
});
});
就是这样!添加一个启动选项是针对 Firefox 运行 Puppeteer 脚本所需的一切。
您可以在 Puppeteer 存储库中找到一个 更长的示例脚本,它还演示了故障排除提示,例如打印内部浏览器日志。
扩展上面的脚本,让我们导航到一个页面并测试一个元素属性。您可以在本系列的第一篇博客文章中看到使用 WebDriver 的类似示例。
const page = await browser.newPage();
await page.goto('http://localhost:8000');
const element = await page.$('.test');
expect(await element.evaluate(node => node.tagName)).toBe('DIV');
虽然这与第一篇文章中的 WebDriver 脚本具有相同的功能,但幕后发生了更多事情。对于 WebDriver,这种类型的脚本与协议直接映射,每行一个远程调用。对于 Puppeteer,仅浏览器初始化就依赖于 15 种不同的 CDP 方法和三种类型的事件。
对 page.goto 的调用检查多个 CDP 事件以确保导航成功,而对 page.$ 和 element.evaluate 的调用都是对远程脚本评估的高级抽象。
这种额外的复杂性带来了实现挑战;即使是一个简单的脚本也要工作,都需要浏览器实现许多命令和事件,即使与 Blink 行为存在微小的偏差,也会打破客户端做出的假设。
这种脆弱性不仅仅是 CDP 提供的低级别控制比 WebDriver 更多的结果,而是实现专有协议的结果,该协议并非旨在跨浏览器支持。
Firefox Nightly 中提供的 CDP 支持 今天 使核心 Puppeteer 功能(如导航、脚本评估、元素交互和屏幕截图)成为可能。我们了解许多用户将依赖我们尚未支持的 API。例如,我们知道网络请求拦截是一个引人注目的功能,但 Firefox CDP 实现目前尚不支持它。
尽管如此,我们对 Puppeteer 脚本在 Firefox 中无法按预期工作时得到的反馈感兴趣;请参阅本文末尾了解如何与我们联系。
Selenium 4
除了像 Puppeteer 这样的完全基于 CDP 的客户端,基于 WebDriver 的客户端也开始添加基于 CDP 的额外功能。例如,Selenium 4 将使用 CDP 为日志记录、网络请求拦截和响应 DOM 突变提供新的 API。Firefox Nightly 已经支持支持访问控制台日志消息所需的 CDP 功能。
这代表着测试作者提出的一个长期以来的功能请求,他们希望断言他们的测试在没有意外错误消息的情况下完成,并收集所有记录的消息以帮助在发生故障时进行调试。
例如,给定一个记录消息的页面,例如
<title>Test page</title>
<script>
console.log('A log message')
</script>
以及使用最新 trunk Selenium Python 绑定的以下脚本
import trio
from selenium import webdriver
from selenium.webdriver.common.bidi.console import Console
async def get_console_errors():
driver = webdriver.Firefox()
async with driver.add_listener(Console.ALL) as messages:
driver.get("http://localhost:8000/test.html")
print(messages['message'])
driver.quit()
trio.run(get_console_errors)
该脚本将输出“A log message
”。
我们正在努力为 Firefox 用户启用更多 Selenium 4 功能,并与 Selenium 作者合作,确保它们在所有提供的语言绑定中得到支持。
直接访问 CDP 连接
对于希望在不依赖现有客户端的情况下,直接在 Firefox 中使用底层 CDP 协议进行实验的用户,启用 CDP 支持的机制与 Chrome 的非常相似。要启动 CDP 服务器,请使用 --remote-debugging-port
命令行选项启动 Firefox Nightly。默认情况下,这会在端口 9222 上启动一个服务器。浏览器进程将向 stderr 打印类似以下的消息
DevTools listening on ws://localhost:9222/devtools/browser/9fa78d94-9133-4460-a4f2-f8ffa149b354
这提供了用于与 CDP 交互的 WebSocket URL。该服务器还公开了一些有用的 HTTP 端点。例如,您可以从 http://localhost:9222/json/list
获取所有可用 WebSocket 目标的列表。
为所有浏览器带来高级自动化
我们在 Firefox 中对 CDP 的实验是开发一个名为 WebDriver BiDi 的新版 WebDriver 协议的早期步骤。虽然我们参与了标准化过程,但我们的团队对跨浏览器端到端测试工作流程的反馈感兴趣。我们邀请开发者尝试在 Firefox Nightly 上运行他们的 Puppeteer 或其他基于 CDP 的测试。
如果您遇到意外行为或缺少功能,您可以通过多种方式与我们联系
- 我们正在关注 Puppeteer 的问题追踪器 上的 Firefox 特定报告。
- 如果您直接访问 Firefox 的 CDP 连接,而不使用客户端库,那么报告问题的最佳位置是 Mozilla 的 Bugzilla
- 随时在我们的 Matrix 频道 #remote-protocol 上提问
无论您在哪里发送反馈,我们都喜欢收到 协议级日志
基于专有协议的自动化解决方案始终会限制其可以支持的浏览器范围。Web 的成功建立在多供应商标准的基础上。重要的是,测试工具也建立在标准之上,以便测试可以在所有浏览器和设备上运行,而 Web 在这些浏览器和设备上可以运行。
将来,我们可能会发布更多文章来介绍我们与其他供应商一起探索 WebDriver-BiDi 的工作,这是一个标准化项目,旨在为未来指定一个双向的、面向自动化的协议。
致谢
感谢 Tantek Çelik、Karl Dubost、Jan Odvarko、Devin Reams 和 Maire Reavy 的宝贵反馈和建议。
关于 Maja Frydrychowicz
关于 James Graham
专注于维护健康的开放 Web 的软件工程师。Web 平台测试核心团队成员。
一条评论