如何为 Comprehensive Rust 的 tests 目录编写避免状态泄漏与竞态条件的 WebdriverIO 测试 📅 发布时间:2026/9/12 13:10:11 👁 浏览次数: 如何为 Comprehensive Rust 的 tests 目录编写避免状态泄漏与竞态条件的 WebdriverIO 测试【免费下载链接】comprehensive-rustThis is the Rust course used by the Android team at Google. It provides you the material to quickly teach Rust.项目地址: https://gitcode.com/GitHub_Trending/co/comprehensive-rustComprehensive Rust 的课程网站theme/下的book.js、speaker-notes.js等 JS 代码依赖真实浏览器行为来验证功能因此项目的tests/目录用 WebdriverIO 搭配 Mocha 和 WebdriverIO Expect API 编写端到端测试。新写或维护测试时最容易遇到两个问题前一个测试留下的状态如 JavaScript 写入的行内样式、sessionStorage泄漏到下一个测试以及页面元素由 JavaScript 在初始加载后动态生成、测试提前访问导致的偶发失败。这篇文章给出仓库中实际使用的两类写法并说明如何运行和验证。测试环境有两个配置写新测试时默认走前者npm test对应 wdio.conf.ts通过wdio/static-server-service在localhost:8080起临时静态服务器自包含大多数测试开发应使用它。npm run test-mdbook对应 wdio.conf-mdbook.ts面向本地cargo xtask serve起的http://localhost:3000实例只覆盖了baseUrl并清空services仅用于对本地服务快速迭代。准备条件按 GEMINI.md 的项目约定# 1. 安装 Rustrustup克隆仓库后执行 cargo xtask install-toolscargo xtask install-tools会安装项目依赖的工具包括固定的 nightly 工具链nightly-2025-09-01、mdbook 及其 Bazel 构建的预处理器插件。没有这一步后续的构建与测试无法正常工作。wdio.conf.ts中与稳定性相关的默认值写测试时可依赖这些行为baseUrl: http://localhost:8080静态服务器挂载env.TEST_BOOK_DIR || ../book/htmlwaitforTimeout: 10000所有waitFor*命令的默认超时mochaOpts.timeout: 60000单个 Mocha 测试的超时Chrome capabilities 默认只带--headless当CI环境变量存在时会追加--disable-gpu、--no-sandbox、--disable-dev-shm-usage等标志以提升 CI 稳定性。用 beforeEach 中的 browser.refresh() 消除测试间状态泄漏redbox.test.ts中的 测试 展示了本仓库确认有效的做法。直接调用browser.url()并不能保证干净的起点JavaScript 施加的行内样式等残留状态可能从一个测试带到下一个造成难以解释的失败。redbox.test.ts的注释明确写着按 WebdriverIO 文档这“本不应该必要但没有它测试会失败”。完整的beforeEach如下beforeEach(async () { await browser.url(/hello-world.html); await browser.execute(() sessionStorage.clear()); // Clear any lingering state (like inline styles) from previous // tests. Reading https://webdriver.io/docs/api/browser/url, // this should not be necessary, but tests fail without it. await browser.refresh(); });即导航到被测页面后先清掉sessionStorage该功能用showRedBox键持久化状态不清会让“默认隐藏”“URL 参数覆盖”这类断言互相污染再refresh()强制整页重载以清掉行内样式等残留状态。speaker-notes.test.ts 的beforeEach同样是browser.url(...)后紧跟browser.refresh()而它的afterEach还负责关闭测试中打开的新窗口避免句柄泄漏到后续测试afterEach(async () { const handles await browser.getWindowHandles(); if (handles.length 1) { await browser.switchToWindow(handles[1]); await browser.closeWindow(); await browser.switchToWindow(handles[0]); } });用等待与自定义命令消除竞态条件本页面的很多元素由 JavaScript 在初始加载后动态创建。如果测试在导航后立即访问脚本可能还没跑完、元素尚不在 DOM 中。GEMINI.md 给出的规则是在对动态元素交互或断言如toBeDisplayed()之前始终先await element.waitForExist()。另一类竞态出现在模拟键盘等操作之后。wdio.conf.ts 的before钩子里注册了自定义命令toggleRedBox注释说明原因直接的browser.keys()调用“被证明是不稳定的会造成间歇性测试失败”。该命令用waitUntil等待 UI 真正反映状态变化从而消除竞态browser.addCommand(toggleRedBox, async function () { const redBox await $(#aspect-ratio-helper); const initialVisibility await redBox.isDisplayed(); // Perform the toggle action. await browser.keys([Control, Alt, b]); // Wait until the visibility state has changed. await browser.waitUntil( async function () { const currentVisibility await redBox.isDisplayed(); return currentVisibility ! initialVisibility; }, { timeout: 5000, timeoutMsg: Red box display state did not toggle after 5s. Initial state: ${initialVisibility}, }, ); });如果你的被测功能也有“操作后状态异步变化”的形态照这个模式写自定义命令操作 waitUntil轮询目标状态比在断言前硬编码等待更可靠。导航一律使用最终的非重定向 URLbook.toml 在[output.html.redirect]段定义了一张重定向表例如async.html concurrency/welcome-async.html大量旧路径会 301 到新的课程结构。GEMINI.md 的警告是导航到重定向 URL 虽然浏览器会跟随但这个过程会丢掉 URL 查询参数导致依赖参数的功能测试失败。所以写测试时导航目标一律用重定向表右值那侧的最终页面。redbox.test.ts里用/hello-world.html?show-red-boxtrue验证 URL 参数行为就是针对最终 URL 写的而book.toml中确实存在welcome-day-1/what-is-rust.html ../hello-world/what-is-rust.html这类条目若导航到旧路径?show-red-boxtrue之类的参数就会在跳转中丢失。运行测试与验证稳定性在tests/目录下运行# 运行全部 spec静态服务器模式端口 8080 npm test # 只运行文件名匹配 redbox 的 spec npm test -- --spec redbox # 只运行文件内单个用例Mocha grep npm test -- --spec redbox --mochaOpts.grep should be hidden by default # 用重复执行检查偶发性 npm test -- --spec redbox --repeat 100仓库根目录下等价的入口是cargo xtask web-tests可选--dir book_html_directory指定构建产物目录它会同时刷新slide-style-guide.test.ts使用的幻灯片列表本地快速迭代时也可以cargo xtask serve起 3000 端口服务后改用npm run test-mdbook。验证标准npm test全部用例通过用--repeat如 100 次重复跑改动过的 spec确认无偶发失败在设置CI环境变量的条件下跑一遍确认追加的 Chrome 标志下依然通过。区分功能失败与环境故障按 tests/README.md 的说法失败先分两类合理告警Legitimate warnings例如页面过长需要缩短或申请豁免或 mdbook 基础设施的破坏性变更打断了功能。这类问题必须在合并前修复。测试环境损坏Broken test environmentCI 中出现如ERROR webdriver: WebDriverError: tab crashed的报错时可能不是你的改动导致的。此时应提交 bug 报告若其余检查都通过且你确信改动正确可以绕过 web-test 要求合并 pull request 作为临时措施。新测试写完后的落点就是上面三件事beforeEach里带refresh()的状态清理、动态元素先waitForExist()异步状态用waitUntil封装成自定义命令、导航只认最终 URL最后用--repeat证明没有 flakiness 再提交。【免费下载链接】comprehensive-rustThis is the Rust course used by the Android team at Google. It provides you the material to quickly teach Rust.项目地址: https://gitcode.com/GitHub_Trending/co/comprehensive-rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考