ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Brave browser-laptop 测试体系实战指南:基于 Mocha、Spectron 与 WebdriverIO 的 UI 与单元测试

Brave browser-laptop 测试体系实战指南:基于 Mocha、Spectron 与 WebdriverIO 的 UI 与单元测试 桌面应用【免费下载链接】browser-laptop[DEPRECATED] Please see https://github.com/brave/brave-browser for the current version of Brave项目地址https://gitcode.com/gh_mirrors/br/browser-laptop点击查看免费下载本文是 Bravebrowser-laptop即早期基于 Electron/Muon 的桌面浏览器官方测试文档docs/tests.md的完整深度解读。它面向需要在当前仓库中编写、运行与调试测试的开发者你将掌握测试框架选型Mocha Spectron WebdriverIO、测试的启动与筛选命令、自定义辅助方法IPC、标签页、窗口、状态、站点、偏好设置、以及 UI 测试的防竞态最佳实践。文章以仓库中的 package.json、test/mocha.opts、test/lib/brave.js 等源码为依据补充了文档之外的实现细节与可运行命令。测试体系概览一套覆盖单元与端到端的双层测试架构Brave browser-laptop 的测试体系分为两大块单元测试unit tests针对纯逻辑模块如状态管理、工具函数、reducer的隔离测试不启动浏览器实例速度快、稳定性高。UI / 端到端测试webdriver tests通过 Spectron 拉起真实浏览器进程用 webdriver.io 的 API 驱动界面交互覆盖标签页、书签、导航栏、Bravery 面板等完整用户流程。官方文档明确指出绝大多数测试基于webdriver.io框架经 Spectron 与 Electron 集成且测试 API 全部遵循 webdriver.io 官方 API 文档 中列出的命令集合。测试代码统一放在仓库顶层的test目录下文件名必须以Test.js作为后缀例如 test/navbar-components/urlBarTest.js、test/bravery-components/braveryPanelTest.js。这一命名约定与package.json中的 mocha 通配符test/**/*Test.js严格对应。环境准备安装 Mocha 与构建测试包全局安装 Mocha测试框架选用 mocha。官方推荐先全局安装npm install --global mochaMocha 的全局安装是为了方便在命令行直接调用 mocha而package.json的devDependencies中同样声明了mocha: ^5.2.0参见 package.json以保证本地开发与 CI 环境的版本一致。保持 webpack 测试包最新为了贴近生产环境测试不使用 webpack dev server即npm run watch启动的webpack-dev-server不服务于测试。因此开发时修改源码后需要手动让测试用的 webpack bundle 持续重建npm run watch-test该脚本在package.json中定义为cross-env NODE_ENVtest webpack --watch即监听源码变化以NODE_ENVtest环境重新打包package.json。若需要同时跑开发与测试两套构建可使用npm run watch-allnpm run watch npm run watch-test。底层 mocha 配置所有测试通过 test/mocha.opts 统一配置其内容决定了测试的执行方式--ui tdd --timeout 600s --reporter spec --check-leaks --require babel-register --require babel-polyfill --recursive要点解读--ui tdd使用 TDD 风格的接口suite/test但测试代码中同样可以使用 BDD 风格的describe/it--timeout 600s单条测试超时高达 10 分钟——因为每条 webdriver 测试要经历启动浏览器 → 初始化 Spectron → 执行断言的完整过程--check-leaks检测全局变量泄漏--require babel-register/babel-polyfill让 mocha 直接运行 ES6/generator 语法的测试源码测试中大量使用function * ()generator 与yield配合co-mocha支持。运行测试全部、仅单元、还是按关键字筛选运行全部测试npm run test该脚本等价于cross-env NODE_ENVtest mocha test/**/*Test.jspackage.json会递归执行test目录下所有*Test.js——包括 UI 测试与单元测试。仅运行单元测试npm run unittest单元测试要快得多。unittest脚本为python tools/test cross-env NODE_ENVtest mocha test/unit/**/*Test.js --globals chrome,DOMParser,XMLSerializerpackage.json其中--globals声明了浏览器全局对象以避免--check-leaks误报。仓库的 test/unit 目录按about/、app/、common/、js/、lib/、state/等子目录组织如 test/unit/app 下就包含 100 个单元测试文件。运行子集测试--grep 筛选可以通过 mocha 的--grep按测试的description或it描述筛选npm run test -- --grepexpression例如--grep^tabs会匹配所有以单词tabs开头的测试描述。该用法对test、unittest等所有测试模式均生效。其他相关入口按目录运行工具脚本tools/test.js 支持TEST_DIR环境变量lint、tools、performance、unit等默认执行mocha test/${TEST_DIR}/**/*Test.js --globals chrome,DOMParser,XMLSerializer集成测试npm run inttest仅运行 test/integration 下的测试覆盖率npm run unittest-cov基于 istanbul 收集单元测试覆盖率。编写测试前须知新标签页背景图默认关闭为了给测试提速新标签页New Tab Page的背景图片在测试环境中默认禁用。如果某个 webdriver 测试需要验证背景图可见必须先在测试内重新打开该设置官方给出了 generator 风格的示例it(shows new tab page background, function * () { yield this.app.client // enable setting again: .changeSetting(tabs.show-dashboard-images, true) // keep testing... })这里的changeSetting是 Brave 自定义的 webdriver 命令见下文偏好设置小节它会派发changeSettingaction 并等待设置值真正反映到应用状态中对应源码 test/lib/brave.js 中changeSetting→waitForSettingValue的调用链。这种命令 等待结果的写法正是避免竞态的核心手段。编写测试的最佳实践来自官方文档的七条军规文档总结了多条实战中踩坑得出的经验逐条展开如下。1. 打开新标签后必须先验证标签已存在任何会打开新标签页的操作都必须先验证标签已经打开再切换标签/窗口——这是测试中最常见的竞态race condition来源。原因在于 webdriver 会自动把上下文切换到任何新建的window而 chromedriver 在 Brave 中无法区分标签页和窗口因此必须使用仓库自定义的辅助方法来处理。特别提醒如果存在多个相同 URL 的标签不能用waitForUrl因为它会命中已存在的那个标签/窗口而不会等待新标签此时getTabCount是更好的选择因为它不依赖特定窗口上下文即可执行。2. 与 DOM 元素交互前必须确认元素存在不要尝试对一个尚未确认存在的元素执行click、moveTo等操作。仅验证页面或某个父元素存在是不够的需要验证目标元素本身。3. 除非绝对必要避免使用外部站点例如 HTTPS Everywhere 与 SSL 相关测试之所以必须访问外部站点是因为本地测试服务器test/lib/server.js当前不具备 SSL 能力。除此之外引入外部依赖会带来三个问题测试变慢需要发出外部请求断网时测试完全无法运行外部站点内容一旦变更测试随之挂掉。4. 绝不假设测试的执行顺序每条测试运行前都应自行完成所需的 setup 或 cleanup而不能依赖前一条测试留下的现场。5. 优先使用 before() 而非 beforeEach()webdriver 初始化拉起 Electron 应用、注册命令耗时较长因此用before()只初始化一次、让多个测试复用能显著提速。但需要注意限制条件如果测试会改变环境导致后续测试需要重新 setup则应改回beforeEach()或者把该测试挪进独立的describe()/before()块中。6. 状态变化不会立刻反映——用等待型命令永远不要假设加载了 URL应用状态里的sites条目就已写入。应使用waitForSiteEntry之类的等待型命令来轮询应用状态。这与第 1、2 条共同构成显式等待三原则。7. 主动添加带日志、会等待结果的 webdriver 命令优先以 Webdriver IO 命令的形式封装常用操作尤其是等待操作并为其添加日志输出命令应尽量等待动作完成例如修改设置同时等待新值反映到状态而不是发出指令就返回。实用辅助方法仓库自带的 webdriver 命令全家桶文档列出了一批 Brave 自有的、可与 webdriver.io 原生方法混用的辅助方法。这些方法的注册入口在 test/lib/brave.js 的addCommands()test/lib/brave.js新方法用this.app.client.addCommand(name, fn)即可追加非常容易扩展。按功能分组如下IPC进程间通信方法用途ipcSend向当前窗口的 webContents 发送 IPC 消息test/lib/brave.jsipcSendRenderer从 renderer 进程发送 IPC 消息test/lib/brave.js文档提示想了解可发送的完整消息类型可查看 js/components/main.js 中各组件的componentDidMount对 IPC 的监听。标签页管理tabHandles枚举当前所有标签页句柄会过滤掉chrome-extension与chrome://brave等内部 URL见 test/lib/brave.jstabByIndex(index)按索引切换到指定标签test/lib/brave.jsgetTabCount()返回当前标签页数量不依赖窗口上下文test/lib/brave.jstabByUrl(url)按 URL 定位标签test/lib/brave.jswaitForTabCount(count)等待标签数达到期望值test/lib/brave.jspinTabByIndex(index, isPinned)固定/取消固定标签页test/lib/brave.js。窗口管理waitForBrowserWindow等待浏览器主窗口出现test/lib/brave.jssetContextMenuDetail隐藏当前正在显示的上下文菜单test/lib/brave.jsshowFindbar(show)显示/隐藏查找栏test/lib/brave.jsgetDefaultWindowHeight/getDefaultWindowWidth读取主显示器工作区尺寸test/lib/brave.jsresizeWindow(width, height)调整窗口大小test/lib/brave.jswindowParentByUrl(url)/windowByUrl(url)按 URL 定位父窗口/窗口test/lib/brave.js。状态管理getAppState()读取应用级状态appStore返回 Immutable 状态序列化后的 JS 对象test/lib/brave.jsgetWindowState()读取窗口级状态windowStoretest/lib/brave.js。两个方法都通过devTools(electron).testData注入的测试钩子读取 store因此必须由 Spectron 拉起应用后才可用。站点管理书签 / 历史 / 文件夹addSite添加一条书签、文件夹或历史记录条目addSiteList批量添加站点列表removeSite移除站点。当前源码中以更具体的命令呈现了同类能力addBookmark(siteDetail)等待书签条目写入后返回test/lib/brave.js、addHistorySite(siteDetail)test/lib/brave.js、addBookmarkFolder(siteDetail)test/lib/brave.js、removeBookmark/removeBookmarkFoldertest/lib/brave.js等。偏好设置changeSetting(key, value)修改应用设置并在返回前等待新值写入状态test/lib/brave.jschangeSiteSetting(hostPattern, key, value)修改针对某主机模式的站点级设置test/lib/brave.js。文档特别强调这些辅助方法中有很多并不会等待动作完成。在辅助方法被统一改造之前测试必须自行确保异步操作已完成——例如等待标签数量增加以证明 IPC 消息已被接收并处理。文档引用了一个曾因有时动作已完成、有时未完成而间歇性失败的案例其修复方式正是等待getTabCount变化后再继续。此外brave.js还注册了大量文档未列全的等待型命令例如waitForUrl、waitForTab、waitForElementCount、waitForDataFile、waitForInputText、waitForBookmarkEntry、waitForHistoryEntry、loadUrl、openBraveMenu、activateTabByIndex等详见 test/lib/brave.js。不确定用法时最直接的方式是在现有测试中搜索对应方法的调用示例。调试测试从命令行日志到浏览器内断点开启命令级 verbose 日志设置环境变量BRAVE_TEST_COMMAND_LOGS1即可让部分命令输出额外信息用于定位失败原因BRAVE_TEST_COMMAND_LOGS1 npm run test日志开关的实现在 test/lib/brave.jslogVerboseEnabled同时受BRAVE_TEST_ALL_LOGS与BRAVE_TEST_COMMAND_LOGS控制所有logVerbose(...)调用点几乎每个自定义命令都带日志都会在开关开启时打印。官方文档给出了运行test/components/braveryPanelTest.js中 blocks custom adblock resources in private tab 测试时的真实输出片段已截取关键行waitForUrl(chrome-extension://mnojpmjdmbbfmejpflffifhffcmidifd/about-newtab.html) waitForBrowserWindow() waitForDataFile(adblock) undefined waitForDataFile(adblock) {etag:\215b010f2f5ff8b102896957564862d7\,lastCheckDate:1477083465282,lastCheckVersion:2} tabByIndex(0) tabHandles() handles.length 1; handles[0] CDwindow-e532c598-ab85-4114-9bef-8cfbfc14035e; loadUrl(chrome-extension://mnojpmjdmbbfmejpflffifhffcmidifd/about-adblock.html) waitForTabCount(2) getTabCount() 1 getTabCount() 2 waitForUrl(http://localhost:23188/adblock.html) openBraveMenu() ✓ blocks custom adblock resources in private tab (4569ms)可以看到日志中每个命令都会打印发起 → 结果waitForDataFile的轮询过程、getTabCount从 1 到 2 的等待过程都一目了然这正是排查竞态问题的利器。使用 debug() 暂停浏览器在测试中调用 webdriver 的debug()命令可暂停浏览器执行yield this.app.client.debug()通常更省事的方式是把它追加到一串命令的末尾例如.waitForUrl(url).debug()。暂停后可以打开浏览器的 dev tools或页面内容 dev tools检查日志、console 与其他状态。注意要尽快操作否则超时会导致测试失败必要时可调大--timeout。获取浏览器 / renderer 进程日志BRAVE_TEST_BROWSER_LOGS1测试结束停止应用时输出主进程日志BRAVE_TEST_RENDERER_LOGS1测试结束停止应用时输出 renderer 进程日志。对应的实现在 test/lib/brave.js 的stopApp中分别调用 Spectron 的getMainProcessLogs()与getRenderProcessLogs()并逐行打印。应对 UI 测试的间歇性失败官方策略清单UI 测试极易写错并引入间歇性失败intermittent failures。正因如此UI 测试运行更慢、更脆弱单元测试始终是优先选择。若要降低 UI 测试的间歇性失败概率文档给出的策略包括永远显式不要依赖隐式行为或时机巧合绝不假设状态立即反映例如加载 URL 后不要假设sites状态已新增条目改用waitForSiteEntry等待开启 verbose 模式BRAVE_TEST_COMMAND_LOGS1获取更丰富的失败信息优先新增 Webdriver IO 命令尤其是等待型命令并为它们添加日志让自建命令尽量等待结果例如修改设置同时等待新值反映到状态changeSetting→waitForSettingValue即为此模式警惕临时禁用的元素点击可能发生在元素仍处于 disabled 状态时需用等待类命令规避。深入源码测试基础设施是如何运转的结合 test/lib/brave.js 可以还原一次 webdriver 测试的完整生命周期启动startApptest/lib/brave.js设置环境变量NODE_ENVtest、CHROME_USER_DATA_DIR临时目录、SPECTRONtrue以./node_modules/.bin/electronWindows 下为node_modules/electron-prebuilt/dist/brave.exe启动应用并传入--enable-logging --v1命令注册beforeAll/beforeEach钩子调用addCommands()为this.app.client注册全部自定义命令并通过chaiAsPromised.transferPromiseness让 chai 断言与 webdriverio 的 promise 链无缝衔接test/lib/brave.js本地测试服务器beforeAllServerSetup用 test/lib/server.js 在测试前起一个静态文件服务器指向 test/fixtures 目录包含adblock.html、autoplay.html、login1.html等大量测试页面执行与清理stopApp在必要时输出进程日志并按KEEP_BRAVE_USER_DATA_DIR决定是否删除临时用户数据目录test/lib/brave.js。这套基础设施解释了文档中的诸多约定测试必须等待浏览器启动慢、必须显式状态更新异步、必须自带服务器避免外部依赖。测试目录结构速查test/unit单元测试约 100 个文件覆盖状态、工具函数、常量、组件逻辑test/lib测试基础设施——brave.jsSpectron 封装与自定义命令、server.js本地测试服务器、selectors.jsDOM 选择器、coMocha.jsgenerator 支持、userProfiles.js 等test/fixtures本地测试页面与资源HTML、图片、视频、PDF组件/功能测试目录navbar-components/、tab-components/、bookmark-components/、bravery-components/、misc-components/、contents/、about/、integration/、performance/、muon-native/测试配置test/mocha.opts。整体来看Brave browser-laptop 的测试体系遵循单元测试优先、UI 测试显式等待、基础设施复用、日志驱动调试的设计思路。对维护者而言掌握本文的命令集与等待型辅助方法即可在新增功能时快速写出稳定、可复现的测试。赞分享桌面应用【免费下载链接】browser-laptop[DEPRECATED] Please see https://github.com/brave/brave-browser for the current version of Brave项目地址https://gitcode.com/gh_mirrors/br/browser-laptop点击查看免费下载相关推荐一套系统管理多个网站怎么做PublicCMS多站点管理3步上手指南一套系统管理多个网站怎么做PublicCMS多站点管理3步上手指南 同时维护好几个网站最磨人的往往不是写稿而是同一篇文章要在几个后台各发一遍、同一套改版要electron-vue 测试指南基于 Karma Mocha 的单元测试与 Spectron 端到端测试实战electron vue 测试指南基于 Karma Mocha 的单元测试与 Spectron 端到端测试实战 electron vue 为 render桌面应用前端开发工具electron-vue 测试体系全解析基于 Karma、Mocha 与 Spectron 的单元测试与端到端测试实践electron vue 测试体系全解析基于 Karma、Mocha 与 Spectron 的单元测试与端到端测试实践 electron vue 是一个以 E桌面应用前端开发工具上一篇Oh My Emacs包管理终极指南使用el-get轻松管理Emacs插件下一篇性能调优revanced-patches优化补丁的执行效率创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表