深度解析 Cypress 浏览器自动化扩展 @packages/extension:MV2/MV3 双版本架构与构建调试指南

深度解析 Cypress 浏览器自动化扩展 @packages/extension:MV2/MV3 双版本架构与构建调试指南 深度解析 Cypress 浏览器自动化扩展 packages/extensionMV2/MV3 双版本架构与构建调试指南【免费下载链接】cypressFast, easy and reliable testing for anything that runs in a browser.项目地址: https://gitcode.com/GitHub_Trending/cy/cypress本文聚焦 Cypress monorepo 中的packages/extension包——一个在 Cypress 测试运行时被 Chrome 与 Firefox 加载的 WebExtension。它从扩展层而非调试协议层自动化浏览器补足 CDP 与 WebDriver BiDi 覆盖不到的 API如 Firefox 的 Cookie/下载事件与浏览器状态清理、Chrome 主标签页跟踪与激活。读完本文你将理解 MV2/MV3 两套扩展为什么存在且分工不同、各自的源码工作流、构建产物与测试体系并掌握在真实浏览器里加载与调试该扩展的完整步骤。为什么 Cypress 需要自己的浏览器扩展Cypress 通过packages/server启动浏览器并驱动测试大多数自动化能力来自底层调试协议但协议并非万能。packages/extension/AGENTS.md明确给出了这个包的存在理由The WebExtension loaded by Chrome and Firefox during Cypress test runs. It automates the browser at the extension level, reaching APIs that CDP and BiDi dont cover.即扩展以浏览器扩展 APIWebExtension API为杠杆触及 CDPChrome DevTools Protocol和 BiDiWebDriver BiDi覆盖不到的领域——例如 Firefox 环境下基于browser.cookies/browser.downloads的 Cookie 与下载事件推送、调用browser.browsingData.remove清理浏览器状态Chrome 环境下跟踪主 Cypress 标签页并把用户拉回该标签页。扩展与packages/server、packages/socket、packages/icons三个包产生依赖详见下文集成点。核心架构不是一套代码的两个构建而是两种截然不同的职责该文档特别强调了一个容易误解的架构事实——AGENTS.md 写道The two bundles are not two builds of the same thing — each is loaded by exactly one browser and does a different job.app/v2/与app/v3/不是同一功能的 V2/V3 双版本Chrome MV2 迁移到 MV3 那样而是各自只被一个浏览器加载、各做各的工作维度app/v2/Manifest V2app/v3/Manifest V3目标浏览器仅 Firefox仅 Chrome加载方packages/server的 Firefox 启动逻辑经utils.writeExtension写入packages/server的 Chrome 启动逻辑经getPathToV3Extension取得路径后端通信经socket.io实际是packages/socket的浏览器端 client回连 Cypress 服务端无 socket 连接仅通过扩展内部消息content script ↔ service worker核心职责推送 Cookie 变更事件、下载创建/完成/取消事件处理reset:browser:stateBiDi 刻意将此职责委托给扩展记录主 Cypress 标签页 URL并在需要时把该标签页重新激活到前台供cypress/puppeteer使用运行时载体MV2 background pagebackground.jsMV3 service workerservice-worker.js content scriptV2Firefox 专用的事件推送 状态重置扩展V2 扩展在 Firefox 里承担两类自动化任务源码可见于 app/v2/background.ts。连接与服务端通信。client.ts 从packages/socket/browser/client引入client并以transports: [websocket]建立连接background.ts 建立ws后监听两类服务端消息automation:request按消息名分发其中唯一已注册的处理是reset:browser:state→ 调用扩展侧的resetBrowserState未注册消息则回传错误结构__error/__stack/__name。automation:config触发checkIfFirefox判定依赖browser.runtime.getBrowserInfo随后注册事件监听。Cookie 事件推送。listenToCookieChanges使用browser.cookies.onChanged.addListener当 Cookie 变化的cause不是overwrite时通过automation:push:request向服务端推送change:cookie事件background.ts。下载事件推送。listenToDownloads只在 Firefox 下启用注释明确非 Firefox 浏览器走 CDP分别监听browser.downloads.onCreated→ 推送create:download携带 id、filePath、mime、urlbrowser.downloads.onChanged→ 根据下载状态推送complete:download或canceled:downloadbackground.ts。浏览器状态重置。resetBrowserState调用browser.browsingData.remove({}, {...})一次性清理cache、cookies、downloads、formData、history、indexedDB、localStorage、passwords、pluginData、serviceWorkers共十类数据background.ts源码注释指出 Chrome 走 CDP automation且 Firefox 不支持fileSystems/serverBoundCertificates这两类数据清理。对应地v2/manifest.json 为 MV2 清单声明了cookies、browsingData、downloads权限与all_urls主机权限通过applications.gecko.id automation-extensioncypress.io固定 Firefox 扩展 IDbackground.scripts指定background.jschrome_url_overrides.newtab指向newtab.html。init.ts负责在扩展页面加载时把 background page 连接到 Cypress 服务端。V3Chrome 专用的标签页跟踪 激活扩展V3 扩展解决的是另一类问题让 Cypress 主标签页在测试过程中保持/恢复前台。它不建立 socket 连接而是采用 MV3 标准的content script ↔ service worker 消息协作。Manifest 骨架。v3/manifest.json 为 MV3 清单权限仅tabs与storagebackground.service_worker指向service-worker.jscontent_scripts匹配http://*/*、https://*/*、all_urls并注入content.js。相比 V2它刻意不申请 cookies/downloads 等敏感权限职责更轻。Service worker 逻辑。service-worker.ts 顶部注释点明了其运行约束service worker 拥有扩展 API但无法直接访问网页内容。核心实现为两段消息处理service-worker.tsurl:changed把最新的主标签页 URL 写入chrome.storage.localmostRecentUrl完成标签页跟踪activate:main:tab从 storage 读取mostRecentUrl在chrome.tabs.query({})结果中匹配包含该 URL 的标签页调用chrome.tabs.update(tab.id, { active: true })将其置前并通过main:tab:activated回执确认。一个值得注意的实现细节是激活标签页时特意不抢系统焦点——源码注释明确写道 this brings the main Cypress tab to the front of any other tabs without Chrome stealing focus from other running appsservice-worker.ts并且把失败日志通过console.log输出仅在开发者检查 service worker 时可见避免污染用户控制台。Content script 桥接。content.ts 运行在网页上下文它通过扩展端口port.onMessage参见 content.ts与 service worker 通信把网页侧需要激活主标签页的请求转交给拥有tabsAPI 的 service worker。扩展 UI 与主题资产除自动化逻辑外该包还包含少量扩展界面资源newtab.html/newtab.css覆盖新建标签页、popup.html/popup.css工具栏弹窗以及theme/目录浏览器主题清单与theme_frame.png等资源。V2/V3 的 manifest 都将browser_action/action的default_popup指向popup.html图标则由packages/icons提供的各尺寸 PNG16/19/38/48/128构成。工程化gulp 编排的三种产物与双工具链packages/extension/package.json与 README.md 展示了清晰的构建拓扑——扩展包并非单一构建流程而是app lib三种产物全部由 gulpfile.ts 编排产物内容工具链输出appv2MV2 扩展Firefoxwebpack-cliwebpack.config.mjs打包app/v2输出background.jsappv3MV3 扩展Chrometsc -p tsconfig.app.v3.json直接编译ESM 产物可在浏览器原生运行无外部依赖libpackages/extension的main入口查找/加载扩展的 Node 侧工具方法tsc -p tsconfig.lib.json转译CommonJS在 Node 上下文消费各脚本在 package.json 中均有对应build委托给gulp buildbuild:v2走 webpack-clibuild:v3与build:lib各走各自的 tsc projectclean走gulp clean。编译后的app-dist、lib-dist目录与theme一并列入包的files发布清单。常用命令速查以下命令均在 monorepo 根目录执行# 构建 V2 V3 两个扩展 bundle 与 lib yarn workspace packages/extension build # 监听模式构建后由 chokidar 监听 app 目录变动并自动重构建 yarn workspace packages/extension watch # 单元测试vitest run yarn workspace packages/extension test # 监听运行测试 yarn workspace packages/extension test-watch # 调试模式运行测试inspect-brk、不并行、无超时 yarn workspace packages/extension test-debug # 运行单个测试文件 yarn workspace packages/extension test -- path-to-spec # 按 glob 匹配运行测试 yarn workspace packages/extension test -- glob-pattern # 类型检查 yarn workspace packages/extension check-ts一个常见的坑该包与packages/electron一样安装后必须显式执行yarn buildpostinstall脚本只打印提醒packages/extension needs: yarn build而不会真正构建。测试体系测试由 Vitest 驱动vitest.config.ts分为单元测试与集成测试两层单元测试test/unit/extension.spec.ts覆盖lib层查找/加载扩展的工具方法V2 集成测试test/integration/v2/background.spec.ts验证 Firefox background page 的消息分发、Cookie/下载事件推送与reset:browser:stateV3 集成测试test/integration/v3/service-worker.spec.ts 与 content.spec.ts验证 service worker 的标签页跟踪/激活协议以及 content script 桥接共享辅助代码位于 test/helpers/background.js。在真实浏览器中加载与调试扩展在 Chrome 中调试 V3service workerV3 扩展的 background 逻辑运行在 service worker 中需要打开 service worker 的控制台才能看到日志与断点。步骤如下整理自 README.md打开 Chrome进入chrome://extensions勾选右上角Developer Mode开发者模式点击左上角Load unpacked extension...加载已解压的扩展程序选择packages/extension/app-dist/v3目录在扩展卡片中点击service workerInspect views 下的 service worker以调试service-worker.js每次改动manifest.json后点击Reload⌘R使其生效。service-worker.ts 源码注释补充了另一种调试入口在新标签页打开chrome://inspect→ 左侧选择 Service Workers → 点击 inspect。若 reload 不生效可能需要重启 Chrome 后再次在chrome://extensions重载扩展。这是 MV3 service worker 生命周期带来的已知调试体验。在 Firefox 中调试 V2background pageFirefox 的 V2 扩展通过 Cypress 测试运行加载调试步骤同样来自 README.md通过cypress open启动并让 Cypress 拉起 Firefox在 Firefox 中打开新标签页导航到about:debugging点击左侧导航的This Firefox在Temporary Extensions临时扩展下找到名为Cypress的扩展点击inspect会弹出独立的调试窗口关闭about:debugging标签页在弹出的调试窗口中切到Debugger标签页即可看到background.js按需设置断点并观察变量。集成点与依赖关系文档在Integration Points一节明确了该包在 monorepo 中的位置运行时依赖packages/socket承担浏览器端 ↔ Cypress 服务端的通信V2 经 socket 传输自动化事件依赖packages/icons提供扩展图标资源被packages/server消费server 在浏览器启动参数中注入构建好的扩展——Firefox 经utils.writeExtension写入扩展、Chrome 经getPathToV3Extension取扩展路径详见 packages/extension/AGENTS.md。与此对应package.json 的nx.implicitDependencies声明了packages/server与packages/socket意味着这两个包任一发生变化都会在 CI 中触发 extension 的重构lib产物以 CommonJS 形态被 Node 侧消费也解释了为什么它使用独立于浏览器 bundle 的编译管线。附开发中的注意事项Gotchas从 AGENTS.md 与 README.md 可提炼出几条对贡献者影响实际的约束安装依赖后必须执行yarn workspace packages/extension build或整仓yarn buildpostinstall仅打印提醒V2 与 V3 的构建工具链不同webpack vs 直接tsc需要修改app构建逻辑时分别查看 webpack.config.mjs、tsconfig.app.v2.json/tsconfig.app.v3.json与 gulp 任务两条扩展各对应一个浏览器修改行为前先确认修改目标属于 Firefox 的协议补足V2还是 Chrome 的标签页管理V3避免在错误的 bundle 中实现功能。【免费下载链接】cypressFast, easy and reliable testing for anything that runs in a browser.项目地址: https://gitcode.com/GitHub_Trending/cy/cypress创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考