关于 writing-webdriverio-code
Writing WebdriverIO Code 是将测试脚手架转为可执行 WebdriverIO 测试,并扩展或修复现有测试文件的技能。它遵循项目约定,强调确定性设置、稳健选择器和清晰断言。
主要功能
- 01实现脚手架中的测试场景
- 02扩展或修复现有测试文件
- 03遵循项目约定与上下文
- 04使用稳健选择器和显式等待
- 05设置隔离且确定的测试数据
- 06从根因排查不稳定测试
适用场景
- 01将伪代码注释转为可执行测试
- 02为现有 WebdriverIO 测试添加场景
- 03诊断并稳定不可靠的浏览器测试
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ klamping/ webdriverio-skills --skill writing-webdriverio-code安装后在 Claude Code 中输入/writing-webdriverio-code确认已加载。
详细介绍
编写 WebdriverIO 代码
将脚手架注释转换为可用于生产环境的测试代码。
此技能可以处理以下任一情况:
- 由
creating-test-structure创建的脚手架,或 - 需要新增测试、重构或修复错误的现有 WebdriverIO 规范文件。
在这两种情况下,它都会生成具体的 WebdriverIO 实现,使其稳定、易读且便于调试。
适用场景
- 已有脚手架,需要将伪代码转换为 WDIO 命令和断言。
- 需要为现有测试文件添加其他场景。
- 现有测试不稳定、脆弱或不正确,需要修复。
不适用场景
- 需要根据 Markdown 测试计划为完整测试套件搭建脚手架(请使用
creating-test-structure)。 - 仅需重新组织 describe/it 层级,不涉及代码实现。
- 需要制定广泛的测试策略(测试金字塔/范围),而不是编写文件级别的 WDIO 代码。
输入约定
- 带有伪代码注释的脚手架规范文件(可选)。
- 或需要扩展/修复的现有已实现规范文件。
- 项目中的现有页面对象、测试夹具和辅助工具。
- 项目约定(代码检查、命名、断言风格)。
项目上下文文件
实现前,请在可用时读取项目缓存文件:
.webdriverio-skills/project-context.md.webdriverio-skills/project-context.json.webdriverio-skills/custom-rules.md.webdriverio-skills/health-recommendations.mdreferences/website-analysis/<target>/website-analysis.mdreferences/website-analysis/<target>/website-analysis.json
将这些文件作为项目约定、脚本、环境用法和团队覆盖规则的默认依据。
使用网站分析参考资料了解路由/组件上下文、预期状态以及需要身份验证的流程。
<target> 应解析为小写的网站主机名(优先使用用户提供的 URL 或项目 baseUrl 主机名)。
如果无法获取,请使用 unknown-target,并继续使用其他上下文来源。
如果文件缺失或已过时,请先运行 managing-project-customizations。
转换工作流
- 确定目标是脚手架转换,还是直接增强/修复测试。
- 加载项目上下文和自定义规则,并将其作为硬性约束应用。
- 如果存在伪代码,按执行顺序实现注释内容。
- 优先使用现有页面对象方法,而不是创建新方法。
- 使用可靠的选择器和明确的预期。
- 行为明确后,移除伪代码注释。
- 仅保留用于解释非显而易见意图的注释。
套件启动状态卫生
- 在套件启动时重置可能在测试间泄漏的状态(Cookie、本地存储、会话/身份验证状态)。
- 确保启动前置条件具有幂等性,以便重复运行时得到相同的基准状态。
- 优先在钩子中进行显式设置,避免依赖隐藏的跨测试状态。
- 清理是必需的,但不要仅依赖可能因崩溃而无法运行的
after钩子。
确定性测试数据的设置与清理
- 尽可能通过 API/测试夹具创建确定性测试数据。
- 为测试夹具/数据命名,使其用途一目了然。
- 将设置逻辑放在需要它的测试范围附近(严格隔离时使用
beforeEach,共享稳定状态时使用before)。 - 始终为创建的数据提供清理路径。
- 执行操作前,先在代码中验证测试数据的前提条件。
测试结构规则
- 将每项测试划分为清晰的阶段:设置、验证、清理。
- 共享设置逻辑应放在钩子中(
before、beforeEach),不要复制粘贴到每项测试中。 - 让每个
it(...)专注于一种用户可观察到的行为。 - 确保测试彼此独立,可单独运行,也可并行运行。
框架规则(Mocha/Jasmine)
- 遵循项目中现有的
describe、it和钩子风格。 - 使用嵌套的
describe块表示用户上下文,而非实现层级。 - 如果扁平结构更易读,就避免过深的套件嵌套。
.only/.skip仅用于本地调试,并在最终提交前移除。
页面对象规则
- 将选择器和特定页面的操作放在页面对象/组件中。
- 让测试规格专注于行为和断言。
- 添加新抽象前,先复用现有页面对象方法。
- 添加小型、用途明确的页面对象方法;避免使用包揽一切的通用辅助方法。
高效查询元素
- 先将查询范围限定在有意义的容器中,再选择子元素。
- 在一个测试步骤中复用已定位的元素,而不是反复查询同一选择器。
- 优先使用唯一的语义化选择器,而非基于索引的查找。
- 仅当 UI 约定明确规定位置顺序时,才使用基于索引的选择。
选择器规则
- 优先使用面向用户的选择器:
button=...、aria/...。 - 当文本/ARIA 不稳定时,使用
data-testid。 - 避免脆弱的类名链和与布局耦合的选择器。
- 限定元素查询范围,以减少冲突。
等待规则
- 尽可能依赖交互操作(
click、setValue)的自动等待。 - 对有意义的 UI 状态转换使用显式等待(
waitForDisplayed、waitForClickable、waitUntil)。 - 优先等待用户可见的结果,而非内部实现细节。
- 不要将
browser.pause用作同步策略。 - 只有在受已知 UI 限制约束时(例如无法避免的动画时长),才允许使用短暂的硬等待;应少用并记录原因。
- 除非有记录在案的理由,否则将隐式超时保持为默认值。
等待决策指南
| 情况 | 首选方法 | 避免 |
|---|---|---|
| 元素交互 | WDIO 自动等待 + 交互 | 预先调用 pause |
| 操作后的异步 UI 更新 | 断言重试或 waitFor... | 固定休眠 |
| 非元素条件 | 使用明确条件调用 browser.waitUntil(...) | 使用手动循环轮询 |
| 已知动画延迟 | 仅在没有稳定信号时使用极短且有记录的 pause | 大范围使用长时间暂停 |
避免断言第三方依赖
- 测试由应用自身负责的行为,而非外部提供商的内部机制。
- 尽可能替身/模拟第三方集成,以避免外部不稳定因素。
- 通过请求/响应处理来验证与外部服务之间的契约,而非验证供应商的正常运行时间或 UI。
- 仅在必要时,为外部集成路径保留极少量的冒烟检查。
断言规则
- 断言用户可见的结果和关键状态。
- 使用
expect-webdriverio匹配器(toHaveText、toBeDisplayed、toHaveUrlContaining)。 - 选择明确的断言目标,以便提供有意义的失败信息。
- 当行为依赖顺序时,明确断言列表的数量/顺序。
- 仅验证与场景相关的行为;避免过多且冗余的断言。
测试命名规则
- 测试名称应清楚描述行为。
- 使用用户和开发者熟悉的领域术语。
- 避免含糊的名称(
should work、happy path test)。 - 根据预期结果命名测试,而非实现步骤。
安全规则
- 切勿硬编码机密信息。
- 输入凭据时屏蔽敏感值(在支持的情况下使用
setValue(..., { mask: true }))。 - 避免在日志中泄露令牌或凭据。
编写便于快速调试的测试
- 按执行顺序编写清晰易读的测试步骤。
- 使用能清楚指出失败原因的断言目标,无需额外排查。
- 对复杂流程添加简洁的步骤级日志。
- 让测试规格中的抽象保持浅层,以便快速将失败对应到测试意图。
不稳定测试排查手册
- 稳定复现失败(先运行单个测试,再重复运行)。
- 隔离不稳定的步骤(选择器、等待、数据、环境或共享状态)。
- 对根本原因进行分类(时机、状态泄漏、脆弱的定位器、测试数据漂移、外部依赖)。
- 修复根本原因(不要用休眠/重试来掩盖问题)。
- 关闭问题前多次重新运行,以验证稳定性。
快速参考
| 测试意图 | 典型 WDIO 实现 |
|---|---|
| 导航到页面 | await browser.url('/path') |
| 与控件交互 | await el.click() / await el.setValue(...) |
| 验证可见结果 | await expect(el).toBeDisplayed() |
| 验证内容/状态 | await expect(el).toHaveText(...) / toHaveValue(...) |
| 等待异步状态变化 | await el.waitForDisplayed() 或 browser.waitUntil(...) |
常见错误
- 认为始终需要脚手架。
- 留下未实现的伪代码注释。
- 将注释转换为脆弱的选择器。
- 使用
browser.pause,而不是等待某个条件。 - 过度使用会掩盖测试意图的辅助抽象。
- 将测试与执行顺序耦合。
- 将重试视为根因修复的替代方案。
示例
it('should default to showing the global feed', async function () {
const activeTabs = await $$('.feed-toggle .nav-link.active');
await expect(activeTabs).toBeElementsArrayOfSize(1);
await expect(activeTabs[0]).toHaveText('Global Feed');
});
完成的标准是:所有伪代码注释都已转换为易于维护的 WDIO 代码,或仅为说明不明显的上下文而有意保留。
评论
支持 Markdown