做浏览器扩展的日常循环大概是这样:改一行代码 → chrome://extensions 点刷新 → 点开弹窗 → 再点进选项页 → 同时盯三个 DevTools 窗口看有没有报错。我自己维护几个扩展,这套流程走了几年,一直没写自动化测试——不是懒,是常规工具够不着扩展真正会坏的地方。
Playwright / Puppeteer 驱动的是「页面」,而扩展大部分不是页面:
- 点图标弹出来的那个弹窗属于浏览器 UI ,不在自动化能寻址的页面树里,选择器写得再巧也点不到;
- MV3 的后台是 Service Worker ,没有 tab 、没有 DOM 、没有 window ,
page.evaluate() 没有附着点,而且它空闲就被回收;
- 内容脚本和页面共享 DOM 但 JS 上下文隔离,在页面里读它设的变量拿到的是
undefined。
以前的办法是 --load-extension 启动浏览器再驱动。Chrome 137 把这个开关从 Chrome 品牌版本里删了(理由也算合理,这参数长期被拿来静默装恶意扩展)。但公告里关键的一句是:该变更只作用于 Chrome 品牌版本,Chromium 、Chrome for Testing 照常工作。 所以门没焊死,只是官方 Chrome 关了。
顺带说两个实测结论,省得有人踩:
- 网上说加
--disable-features=DisableLoadExtensionCommandLineSwitch 能强行恢复的,别信。Chrome 150.0.7871.187 上加不加都装不上,--enable-unsafe-extension-debugging 也不管用。
- Edge 可以,它是微软品牌的 Chromium ,没继承这条限制,
--browser-channel msedge,CI 里 Linux/Windows 都跑通了。
于是有了 pikabo
一句话:manifest.json 里其实已经写好半套测试了。弹窗、选项页、内容脚本的匹配规则、有没有 Service Worker——这些都是声明好的,足够推导出一套真能跑的冒烟测试。
npx pikabo explore --ext ./my-extension
它读 manifest ,在真实 Chromium 里把每个声明的界面打开,检查弹窗是不是渲染出了实际内容(而不是一个空壳),按内容脚本的匹配规则访问对应网址确认注入成功,再断言 Worker 干净启动。生成的 YAML 套件落盘,你可以接着改,不是黑盒。
my-extension smoke tests
✓ service worker starts without errors 12ms
✓ popup renders 431ms
✓ options page renders 318ms
✓ content script injects on github.com 772ms
4 passed · 3.8s
一行手写测试都没有。
我自己最受用的一个功能
MV3 Service Worker 的控制台,只在你打开它的 Inspector 期间才存在,Chrome 不替你缓冲。所以后台脚本第一行就抛异常(拼错变量名、少 import 、用了没声明权限的 API ),你看到的是一个空白弹窗,页面控制台干干净净,完全意识不到出过事——Worker 在你开始看之前就已经死了。
pikabo 的做法是在 Worker 启动之前通过 DevTools 协议挂上去,等它抛的时候缓冲区已经在收:
✗ service worker starts without errors
assertNoConsoleErrors: 2 console error(s):
[worker] ReferenceError: initialise is not defined
at chrome-extension://abc…/background.js:4:1
文件行号都在,而这个脚本根本没活到能给你打印一次堆栈。
其他
- 按名字寻址每个界面。
in: worker 在 Service Worker 里执行(chrome.storage、chrome.runtime 都在那),in: popup 把弹窗当真实文档,还有 sidepanel、devtools、offscreen、MV2 的 background。
- 权限审计。 对比代码实际碰过的
chrome.* 命名空间和 manifest 声明。声明了没用到的容易卡商店审核;反过来「用了没声明」更糟,正式安装里那个命名空间就是 undefined,只对用户报错不对你报错。报告写的是 not observed 而不是 unused——只开过弹窗的套件证明不了什么,这个区别我在文档里专门说了。
- 导出文件校验。
assertPdf 直接读文件:页数、页面尺寸、体积、生成器。Worker 里调 chrome.downloads.download() 产生的下载也抓得到,这种全程没有页面事件。
- 已有 Playwright 套件不用重写,给自己的
test 加几个 fixture 就行,locator/断言/重试/reporter 全保留。
- 还有
record 录制、HTML 报告(截图内联,可以直接丢进 issue )、MCP server 和 agent skill 。
做不到的也说清楚
只支持未打包目录,不支持商店装的 .crx。浏览器自身 UI (工具栏图标菜单、拼图溢出菜单、原生权限弹窗)点不了,不过这些界面能触发的功能都能从弹窗文档、选项页或 Worker 走到。manifest.commands 里的快捷键没法作为真实按键发送,得通过 Worker 派发处理函数。需要 Node 22+( 20/21 没有全局 WebSocket,Worker 控制台捕获依赖它)。
MIT ,0.1.0 ,刚发出来不久,能用但肯定还有坑。
https://github.com/sonic0002/pikabo
npm 上包名就是 pikabo。如果你也在维护扩展、一直因为没趁手工具把测试往后拖,这个补的正好是那块;有跑不通的场景欢迎来提 issue 。