mcpField
U
ui-data-testid

ui-data-testid

github.com/dtyq测试与质量5.1k38 次安装4 天前更新
代码仓库

关于 ui-data-testid

这是一个指导 UI 实现者为界面元素添加稳定 data-testid 的技能,帮助测试选择器不受文案翻译和视觉调整影响。它提供命名、覆盖范围、重复列表定位及测试查询的规则。

主要功能

  1. 01为根容器和交互元素添加标识
  2. 02使用语义化 kebab-case 命名
  3. 03为重复列表设置行级标识
  4. 04优先使用稳定选择器编写测试
  5. 05保留已有标识并覆盖异步状态

适用场景

  1. 01为新表单添加可测试的稳定选择器
  2. 02改造菜单和弹窗而保留既有标识
  3. 03测试重复列表中的指定行及其操作

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dtyq/magic --skill ui-data-testid

安装后在 Claude Code 中输入/ui-data-testid确认已加载。

附带文件agents/openai.yaml

详细介绍

UI data-testid

概览

在实现过程中为 UI 代码添加可预测的 data-testid 属性,而不是事后补充。 确保选择器不会因 i18n 文本变化或视觉重构而变动。 遵循 .cursor/rules 中的项目测试规则:

  • 重构或迁移时保留现有的 data-testid
  • 在项目测试中采用 data-testid-first 查询策略

工作流

  1. 根据功能或模块上下文确定作用域前缀(例如:user-menus、organization-switch、settings-profile)。
  2. 为组件根容器添加 data-testid。
  3. 为所有主要交互节点添加 data-testid:
    • 按钮或链接触发器
    • 输入框、选择框、复选框和单选框控件
    • 标签页、菜单项和子菜单触发器
    • 模态框或抽屉的打开和确认操作
  4. 对于配置驱动的 UI(例如 menu.items),在配置中添加 "data-testid",并在渲染器或包装组件中将其传递给实际可点击的 DOM 节点。
  5. 对于重复列表行或列表项,首先将稳定的 data-testid 放在行或列表项容器上。默认情况下,不要为每个子元素添加单独的唯一 ID。
  6. 在列表行或列表项中,在测试里复用行作用域:通过共享的行 ID 以及文本或业务数据定位行,然后使用 within(row) 或角色/标签选择器查询子控件。
  7. 只有在无法通过行作用域可靠地选择子元素时,才在重复行中添加子级 data-testid;如有需要,让子级 ID 在各行之间共用,而不是追加行 ID。
  8. 除非用户明确要求重命名,否则保持现有 ID 不变;迁移任务中绝不能移除现有 ID。
  9. 对于交互变更,在可行的情况下,于同级的 __tests__ 中添加或更新 Vitest/RTL 测试。

命名规则

  • 仅使用小写 kebab-case。
  • 使用语义格式:<scope>-<entity>-<action>。
  • ID 不依赖文本内容(不得依赖 i18n 标签)。
  • 避免使用动态或随机值(Date.now、UUID、翻译文本)。
  • 不要嵌入密钥、电子邮件地址、电话号码或令牌。
  • 适用时使用稳定的后缀:trigger、content、button、input、option、item、row、loading、empty、error。

最低覆盖检查清单

对于每个新建的 UI 组件,至少包含:

  • 一个根容器 test id
  • 一个主要 CTA test id
  • 每个次要操作按钮的 test id
  • 每个表单字段组或控件的 test id
  • 存在菜单时,为每个菜单项触发器添加 test id
  • 对于重复列表或表格,一个列表容器 ID 和一个行或列表项容器 ID;除非行作用域选择器不够用,否则避免为每个单元格或操作添加动态 ID
  • 保留已修改文件中的历史 data-testid
  • 为异步 UI 添加 loading、empty 和 error test id

查询优先级

编写或更新测试时:

  • 在本项目中优先使用 getByTestId 作为稳定选择器
  • 使用 getByRole、getByLabelText、getByText 作为补充断言
  • 面向用户行为的测试中,避免使用 container.querySelector(...) 选择器

这样可以确保与 .cursor/rules/testing-guide.mdc 保持一致。

场景指南

应用以下模式,以稳定、准确地定位元素:

  1. 表单
    • 为表单容器、输入框、提交/取消按钮和验证错误添加 id
  2. 列表和表格
    • 添加列表容器 id 和行容器 id
    • 优先使用共享行 id,再根据文本/业务数据选择目标行
    • 仅在确实需要直接查找特定行时,才使用稳定的业务键作为行 id 后缀
    • 不要为行内的每个字段/操作单独添加动态 id;使用 within(row) 作用域查询子操作
    • 如果子操作需要 data-testid,请使用一个共享 id,例如 collaborator-remove-button,并在行作用域内查找
  3. 菜单和下拉菜单
    • 为触发器、弹出内容和每个可操作菜单项添加 id
    • 如果菜单由配置驱动,请将各项级别的 data-testid 传递到渲染后的节点
  4. 模态框和抽屉
    • 为打开触发器、模态框内容、主要操作和关闭/取消操作添加 id
  5. 异步状态
    • 为加载、空状态和错误状态添加 id

稳定性规则

  • 如果数组顺序可能变化,绝不要根据数组索引生成 id。
  • 绝不要根据随机值或时间戳生成 id。
  • 确保单例 id 在页面上唯一。
  • 对于重复组件,保留共享的子级 id,并使用 within(...) 限定作用域。
  • 在重复行中,优先保证行级唯一性,而不是子级唯一性;除非没有可用于限定作用域的行容器,否则子级 id 不应包含行 id。

模式

组件标记
<div data-testid="user-menus-organization-info">
  <button type="button" data-testid="user-menus-upgrade-button" />
  <button type="button" data-testid="user-menus-recharge-button" />
</div>
重复列表行
<div data-testid="collaborator-list-content">
  {collaborators.map((collaborator) => (
    <div
      key={collaborator.id}
      data-testid="collaborator-item"
      data-collaborator-id={collaborator.id}
    >
      <span>{collaborator.name}</span>
      <button type="button" data-testid="collaborator-remove-button" />
    </div>
  ))}
</div>

const row = page
  .getByTestId("collaborator-list-content")
  .locator('[data-testid="collaborator-item"]')
  .filter({ hasText: receiverName })

await row.getByTestId("collaborator-remove-button").click()
配置 + 渲染器转发
const items = [
  { key: "logout", label: t("logout"), "data-testid": "user-menus-logout" },
]

<ItemComponent data-testid={menuItem["data-testid"]}>{menuItem.label}</ItemComponent>

完成标准

只有在已触及的 UI 文件中,所有新增的单例交互节点都具有稳定的 data-testid 值,且重复列表/表格行都具有行级选择器,可用于在行作用域内查找子控件时,才算完成。 确认迁移/重构差异中没有意外移除任何现有的 data-testid。

评论

支持 Markdown