SuperAPI AI 工具集

accelint-react-testing

测试与质量

查看项目

更新于 10-15 15:31

技能介绍

用途

accelint-react-testing 是一个用于指导编写、审查和重构 React 组件测试的技能,基于 Testing Library。其目标产物是可维护、以用户为中心的测试,强调查询选择、无障碍优先(accessibility-first)测试,以及避免测试实现细节。

主要能力(规则要点)

编写 React 测试时的禁止事项:

  • 在尝试无障碍查询之前,禁止使用 test id 查询:test id 会绕过无障碍验证,查询层级为 getByRole > getByLabelText > getByText > getByTestId,层级越低对 UI 可用性的信心越少。
  • 在 userEvent 可用时,禁止使用 fireEvent 模拟用户交互:fireEvent 只派发单个 DOM 事件,遗漏真实用户的完整事件序列(如 focus → mousedown → mouseup → click);userEvent.click() 模拟完整交互序列。
  • 禁止测试实现细节而非用户行为:验证“状态变量 X 等于 Y”或“函数 Z 被调用”会产生虚假失败,惩罚重构且无法提供用户体验层面的信心。应测试用户看到和做了什么(渲染输出、交互结果)。
  • 禁止从 container 查询或在初始渲染后使用解构的查询:解构查询会命中初始 DOM 快照,遗漏更新,应始终使用 screen.getByText() 之类查询当前 DOM 状态。
  • 禁止仅为测试添加 aria-label 或 role 属性:测试应验证组件已经无障碍,而不是为测试而让它“变得”无障碍;额外的测试专用 ARIA 会污染生产代码并掩盖真实的无障碍问题。
  • 禁止在缺少具体断言的情况下快照整个组件树:500 行以上的巨大快照会因任意改动而失败,只应快照关键结构(错误信息、数据表),其余使用针对性断言。
  • 禁止对返回 promise 的动作使用 waitFor:应使用基于 promise 的 findBy 查询(如 await screen.findByText('loaded')),waitFor 保留给无法使用 findBy 的断言(如检查元素消失、等待属性变化)。
  • 禁止在 waitFor 回调内执行副作用:waitFor 会在重试时多次执行回调,导致不可预期行为;动作应在 waitFor 之外执行,waitFor 仅用于断言。
  • 禁止在没有文档说明 Provider 要求的情况下创建自定义渲染函数:应将 Provider 设置集中在测试工具中,并用 TypeScript 类型约束正确用法,或显著记录所需的包装器。
  • 禁止混用来自不同 Testing Library 导入的查询:React 组件应全部从 @testing-library/react 导入查询。

编写测试前应思考的要点:

  • 查询选择策略:哪个查询匹配用户寻找该元素的方式;该元素是否真的需要被查询到;应使用 getBy、queryBy 还是 findBy。
  • 用户测试与实现测试:用户会怎么验证它能工作;该测试能否在行为不变的重构后存活。
  • 异步与时机:查询是否针对异步加载内容;等待的是元素出现还是消失。
  • 测试隔离与设置:组件是否需要 context provider 才能渲染;该用例所需的最小设置是什么。

使用方式

该技能使用渐进式披露以尽量减少上下文占用:

  1. 从概览(AGENTS.md)开始:阅读 AGENTS.md 获取所有规则的一句话摘要式简洁概览。
  2. 按需加载具体规则文件,触发条件包括:
    • 强制加载(加载整个文件):编写任何查询(getBy、findBy、queryBy*)→ query-priority.md;模拟用户交互(点击、输入等)→ user-events.md。
    • 出现以下模式时加载:对 getBy / findBy / queryBy 感到困惑 → query-variants.md;waitFor、异步查询或 “act” 警告 → async-testing.md;组件使用 Context、Redux、Router → custom-render.md;测试无障碍或 ARIA 属性 → accessibility-queries.md;大量使用 container、wrapper 或 rerender → anti-patterns.md;查询失败或找不到合适选择器 → query-variants.md(了解 screen.debug() 用法)。
    • 除非特别需要,否则不要加载:无 Provider 的简单组件不要加载 custom-render.md;同步测试不要加载 async-testing.md;不测试 ARIA 或无障碍问题时不要加载 accessibility-queries.md。
  3. 应用模式:每个参考文件包含 ❌ 错误示例、✅ 正确示例,以及为何该模式重要的解释。
  4. 审计现有测试(可选):使用提供的脚本审计现有测试套件:
    • Check query priority (testId usage, container.querySelector)

      ./scripts/check-query-priority.sh
    • Find fireEvent that should be userEvent

      ./scripts/find-fire-event.sh
    • Detect deprecated wrapper/container patterns

      ./scripts/detect-wrapper-queries.sh
  5. 使用报告模板:当该技能被用于测试代码审查时,使用标准化报告格式:Template: assets/output-report-template.md。报告格式提供执行摘要(含无障碍信心与以用户为中心覆盖率评估)、严重级别(Critical、High、Medium、Low)、影响分析(无障碍信心、用户中心信心、测试可靠性、重构安全性)、分类(查询优先级、查询变体、用户事件、异步测试、自定义渲染、无障碍、反模式)、链接到 references/ 中详细指南的模式引用,以及用于跟踪所有问题的汇总表。

使用报告模板的时机:通过 /accelint-react-testing <path> 直接调用技能;用户要求“审查测试代码”或跨文件“审计测试”而隐式调用技能。

不使用报告模板的时机:用户要求“为这个函数写个测试”(直接实现);用户问“这个测试哪里有问题”(直接回答问题);用户要求具体的测试修复(直接应用修复,不生成正式报告)。

覆盖范围

  • 查询优先级:从 getByRole 到 getByTestId 的无障碍查询层级。
  • 查询变体:在不同场景下何时使用 getBy、findBy、queryBy。
  • 用户事件:userEvent 与 fireEvent 在真实交互测试中的对比。
  • 异步测试:处理 promise、waitFor、findBy 查询,避免 act 警告。
  • 自定义渲染:为复杂组件(Context、Redux、Router)设置 Provider。
  • 无障碍查询:使用角色、标签和 ARIA 属性进行测试。
  • 反模式:避免实现细节、container 使用、过量快照。
  • 审计脚本:自动检测现有测试中的次优模式。

查询选择决策树

选择查询时按从上到下尝试:

  1. getByRole ← 首选:无障碍,反映用户与辅助技术的交互方式
  2. getByLabelText ← 表单字段:匹配用户阅读表单的方式
  3. getByPlaceholderText ← 输入框:无障碍性弱于 label
  4. getByText ← 非交互内容:标题、段落
  5. getByDisplayValue ← 表单输入:当前值
  6. getByAltText ← 图片:alt 属性
  7. getByTitle ← title 属性:无障碍性较弱
  8. getByTestId ← 最后手段:没有无障碍验证

关键原则:越靠上的查询意味着对无障碍的信心越高;如果无法按 role/label 查询,应先修复组件的无障碍;getByTestId 意味着“我已确认此处无法验证无障碍”。

重要说明

  • screen 导出并非魔法,它只是 getQueriesForElement(document.body)。screen.getByRole() 与从 render 解构的 getByRole() 等价,但 screen 在重新渲染后不会过期。
  • Testing Library 通过让无障碍元素最易查询来鼓励无障碍:如果查询很难,说明 UI 很难用,查询难度是 UX 的坏味道。
  • 查询失败时使用 screen.debug() 或 screen.logTestingPlaygroundURL():不要猜测选择器,让 Testing Library 展示可用的查询。
  • queryBy 会静默返回 null,应使用 getBy 获得更好的错误信息;queryBy 仅用于配合 .not.toBeInTheDocument() 断言不存在。
  • Act 警告意味着 React 状态更新发生在 Testing Library 感知之外,通常由测试完成后 promise 才 resolve 或异步查询缺少 await 引起,并非正确使用 findBy 或 waitFor 所致。
  • userEvent 方法为异步(返回 promise),fireEvent 方法为同步;忘记 await userEvent.click() 会导致 “act” 警告和脆弱测试。

报告模板结构(供代码审查)

模板文件:assets/output-report-template.md,包含执行摘要、严重级别、影响分析、分类、模式引用(链接到 references/ 详细指南)、汇总表。

限制

关于该技能是否收费、价格、支持的具体版本或平台范围,资料中暂未提供。