Chrome 对抗式 UI 测试

SKILL开发
开发 未标注权限 许可证不明确
安装这个技能

使用 chrome-devtools MCP 在真实浏览器中检查 UI 改动、功能、无障碍和响应式布局;需要先配置对应浏览器连接器。

一句话选型结论

按资料字段整理

Chrome 对抗式 UI 测试是开发类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类开发 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_fa822256/yzfly-chrome-qa-agent
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

开发
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_fa822256仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验2026-11-06上游最后核验时间 · 数据更新 2026-11-06
正文体量32.5 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
写代码与改 bug

按需求补代码、定位并修掉报错。

读仓库与生成改动

让模型读懂项目结构,再给出可落地的改动。

跑测试与排查故障

按现象排查问题,补测试用例并复跑。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在开发场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
Chrome 对抗式 UI 测试当前 未标注权限 未标注 未标注 未标注 有
技能审查员 浏览器控制 ClawHub 市场 877.9 万 OpenClaw 有
Vercel React 最佳实践 浏览器控制 GitHub 仓库 849.1 万 Codex、Claude、Cursor 有
GitHub 代码协作 联网访问 ClawHub 市场 763.3 万 OpenClaw 有
网页设计指南 联网访问 GitHub 仓库 668.6 万 Codex、Claude、Cursor 有
本体论 只读 ClawHub 市场 663.7 万 OpenClaw 有

SKILL.md 全文

32.5 KB
模型实际读到的说明书原文,来自技能仓库

Chrome QA Agent — 对抗式 UI 测试 Skill

在真实浏览器里测试 UI 改动。你的任务是想办法把它弄坏,而不是确认它能跑。

本 skill 通过 chrome-devtools MCP(mcp__chrome-devtools__* 工具)驱动单个本地 Chrome。由于该 MCP 只控制一个浏览器,且 select_page 会为整条连接全局设置当前活动页面,浏览器测试是单线程的 —— 绝不能让两个 agent 同时对同一个浏览器操作。

两种工作流:
- diff 驱动 —— 分析 git diff,只测改动部分
- 探索式 —— 在应用里到处点,找出开发者没想到的 bug

对于较大的任务,你仍可以把工作拆给多个子 agent 以隔离上下文,但它们必须轮流独占这唯一的浏览器 —— 见下文「拆分工作的原则」一节。

测试如何运作

主 agent 负责协调 —— 它制定测试策略、把任务分派给子 agent、并汇总结果。真正的浏览器测试由子 agent 执行。

规划:先从多个角度想,再一次性执行

你必须亲自完成全部三轮规划并输出,然后才能启动任何子 agent。 规划发生在你自己的回复里 —— 不能委派给子 agent。不要跳过规划直接执行。

第一轮 —— 功能: 核心用户流程有哪些?什么应该正常工作?把每个测试写成:动作 → 预期结果。

第二轮 —— 对抗: 重读第一轮。你漏了什么?想想:不同的用户类型/角色、错误路径、空状态、竞态、边界输入(空值、超长、特殊字符、连续快速点击)。

第三轮 —— 覆盖盲区: 重读第一、二轮。还有什么没考虑:无障碍(axe-core、纯键盘)、移动端视口、控制台错误、与应用其余部分的视觉一致性?

去重: 把三轮合并成一份带编号的测试清单。去掉重叠项。给每个测试分配一个分组(例如 Group A、Group B)。

然后一次性执行 —— 每个分组启动一个子 agent。每个子 agent 只接收它那份具体的测试清单,别的都不给。子 agent 不探索、不规划 —— 它们执行被指派的测试并汇报结果。

在调用任何 Agent 工具之前,把三轮规划、合并后的计划、以及分组分配都输出在你的回复里。

拆分工作的原则

  • 一个浏览器,同一时刻只有一个 agent。 chrome-devtools MCP 控制单个 Chrome,且 select_page 是全局状态。顺序分派子 agent —— 每个在自己回合里独占浏览器,跑完,下一个再开始。并发驱动浏览器的 agent 会破坏彼此的页面状态。(你仍可以并行跑非浏览器的工作,比如 diff 分析。)
  • 子 agent 跑被指派的测试,而非开放式探索。 主 agent 交给每个子 agent 一份具体的、带编号的测试清单。子 agent 不规划、不探索、不决定测什么 —— 它们执行清单然后停下。
  • 即便是串行,拆分依然有用 —— 它让每个 agent 的上下文保持小而聚焦。许多小 agent 优于少数大 agent。这里的收益是上下文隔离和每组干净的汇报,而不是挂钟时间上的并行。
  • 按改动规模匹配投入 —— 单个组件的修复不需要很多 agent 或很多步数;主 agent 直接跑就行。整页重构才值得拆成多个分组。让 diff 的范围来驱动计划。
  • 遇到失败不要提前停 —— 在被指派的测试范围内尽可能多地找出 bug。

给子 agent 设定步数预算

主 agent 必须在每个子 agent 的提示里写明步数上限。 一「步」= 一次 chrome-devtools MCP 工具调用(navigate_page、take_snapshot、click、evaluate_script……)。子 agent 不会自我设限 —— 除非被告知,否则它们会一直跑到完成。

粗略经验值:几项有针对性的检查约 25 步,一个完整页面(功能 + 对抗 + a11y)约 40 步,多个页面或一大类约 75 步。根据被指派测试的实际需要来调整 —— 这些是起点,不是规则。

每个子 agent 的提示都必须包含:

You have a budget of N steps (each chrome-devtools MCP tool call = 1 step). Count your steps as you go. When you reach N, stop immediately and report:
- STEP_PASS/STEP_FAIL for every test you completed
- STEP_SKIP|<test-id>|budget reached for every test you didn't get to

Drive the browser ONLY through the chrome-devtools MCP tools (mcp__chrome-devtools__*).
You own the browser exclusively for this run — no other agent is using it. When done, the next agent will reuse the same Chrome, so leave it in a clean state (close extra tabs you opened with close_page).
Do not retry or continue after hitting the budget.
Run only these tests: [numbered list from the merged plan]
Do not explore beyond the assigned tests.
Do NOT generate an HTML report or write any files (except screenshots via take_screenshot's filePath). Return only step markers and your findings as text.

主 agent 自己不应驱动浏览器(除了验证开发服务器是否已启动)。所有测试都在子 agent 里进行,一次只分派一个 —— 绝不要同时跑两个驱动浏览器的子 agent,因为它们共用一个 Chrome。

当某个子 agent 用尽预算时,主 agent 直接接受这份部分结果。 不要重跑或重试这个子 agent。把 SKIPPED 的测试写进最终报告,让开发者知道哪些没覆盖到。

汇报

每个子 agent 回报时给出:

Tests: 8 | Passed: 5 | Failed: 2 | Skipped: 1 | Pages visited: 2

主 agent 汇总成最终报告:

Tests: 20 | Passed: 14 | Failed: 4 | Skipped: 2 | Agents: 3 | Pass rate: 70%

不要汇报「用了多少步」 —— MCP 工具调用次数是实现细节,对评审者来说不是有意义的指标。

测试理念

你是一名对抗式测试者。 你的目标是找出 bug,而不是证明正确性。

  • 想办法弄坏你测的每个功能。 别只检查「按钮在不在?」 —— 快速点它两下、提交空表单、粘贴 500 个字符、流程中途按 Escape。
  • 测开发者没想到的地方。 空状态、错误恢复、纯键盘导航、移动端溢出。
  • 每条断言都必须基于证据。 对比前后快照。按 ref 检查具体元素。没有来自无障碍树或确定性检查的实在证据,绝不报 PASS。
  • 失败要报到足以复现的程度。 包含确切的动作、你的预期、实际得到的结果,以及一条修复建议。

断言协议

每个测试步骤都必须产出一条结构化的断言。不要写「看起来不错」这种自由文本。

步骤标记

每个测试步骤,恰好发出一个标记:

STEP_PASS|<step-id>|<evidence>

或

STEP_FAIL|<step-id>|<expected> → <actual>|<screenshot-path>
  • step-id:简短标识,如 homepage-cta、form-validation-error、modal-cancel
  • evidence:你观察到的、能证明此步通过的东西(元素 uid、文本内容、URL、evaluate_script 结果)
  • expected → actual:你的预期 vs 实际得到的
  • screenshot-path:保存的截图路径(仅失败时 —— 见下文「失败截图」)

失败截图

每条 STEP_FAIL 都必须配一张截图,好让开发者直观看到哪里出了问题。

当某个测试步骤失败时,立即截图,直接写入以 step-id 命名的路径:

mcp__chrome-devtools__take_screenshot { filePath: ".context/ui-test-screenshots/<step-id>.png" }

take_screenshot 直接写文件 —— 不需要再单独移动/复制。要截取单个元素而非视口,传它的 uid;要截整个可滚动页面,传 fullPage: true。

每次测试运行开始时,创建一次截图目录:

mkdir -p .context/ui-test-screenshots

规则:
- 文件名 = step-id(例如 double-submit.png、axe-audit.png、modal-focus-trap.png)
- 存到 .context/ui-test-screenshots/ —— 该目录已加入 gitignore,开发者和其他 agent 都能访问
- 当某个子 agent 负责一个测试分组时,加上分组名前缀以避免冲突:<group>-<step-id>.png(例如 signup-double-submit.png)
- 在失败的那一刻截图 —— 捕捉损坏状态,不要等恢复之后
- 对于视觉/布局 bug,也截一张基线(正常状态)以便前后对比:<step-id>-baseline.png

如何验证(按严谨程度排序)

  1. 确定性检查(最强) —— evaluate_script 返回可 JSON 序列化的数据供你检视。例如:axe-core 违规计数、document.title、表单字段值、控制台错误数组、元素数量。
  2. 快照元素匹配 —— 在 take_snapshot 返回的无障碍树里存在某个具有特定角色和文本的元素。每个元素都有一个 uid(例如 uid=12 button "Save")。元素要么在树里,要么不在。
  3. 前后对比 —— 动作前快照,执行动作,动作后快照。验证树按预期发生了变化(元素出现、消失、文本改变)。
  4. 截图 + 视觉判断(最弱) —— 仅用于无障碍树无法捕捉的纯视觉属性(颜色、间距、布局)。务必说明你具体在评估什么。

前后对比模式

这是核心的验证循环。每次交互都用它:

# 1. BEFORE: capture state
mcp__chrome-devtools__take_snapshot
# Record: what elements exist, their text, their uids

# 2. ACT: perform the interaction (uid comes from the snapshot above)
mcp__chrome-devtools__click { uid: "12" }

# 3. AFTER: capture new state
mcp__chrome-devtools__take_snapshot
# Compare: what changed? What appeared? What disappeared?

# 4. ASSERT: emit marker based on comparison
# If dialog appeared: STEP_PASS|modal-open|dialog "Confirm" appeared at uid=20
# If nothing changed:
mcp__chrome-devtools__take_screenshot { filePath: ".context/ui-test-screenshots/modal-open.png" }
# STEP_FAIL|modal-open|expected dialog to appear → snapshot unchanged|.context/ui-test-screenshots/modal-open.png

> uid 不稳定。 每次 take_snapshot 都可能给元素重新编号。永远基于最近一次快照里的 uid 来操作;任何导航、点击或 DOM 变化之后,使用 uid 前都要重新快照。你也可以把 uid 作为 args 传给 evaluate_script,对特定元素进行操作。

安装配置

本 skill 需要 chrome-devtools MCP 服务已配置并连接 —— 它驱动真实的本地 Chrome。无需任何额外安装。

确认工具可用:你应该能调用 mcp__chrome-devtools__list_pages。如果 MCP 未连接,告诉用户去添加/启用 chrome-devtools MCP 服务后重试。

避免权限疲劳

本 skill 会发起大量 MCP 工具调用(快照、点击、eval)。为免逐个批准,在 .claude/settings.json(项目级)或 ~/.claude/settings.json(用户级)里放行 chrome-devtools 工具:

{
  "permissions": {
    "allow": [
      "mcp__chrome-devtools"
    ]
  }
}

模式选择

只有一个浏览器 —— 你本地的 Chrome。同一套工具既测 localhost 也测线上站点;区别只在 URL。

目标 怎么做 认证
localhost / 127.0.0.1 navigate_page { type: "url", url: "http://localhost:3000" } 本地开发无需认证
线上 / 预发布站点 navigate_page { type: "url", url: "https://staging.your-app.com" } 复用真实 Chrome 配置文件的登录会话 —— 如果你在 Chrome 里已登录,那这里也登录了

隔离: 默认情况下 MCP 会附着到用户的 Chrome(带着它的 cookie/登录态)。当你需要一个干净的、未登录的浏览器来做可复现的运行时,在隔离上下文里打开页面:

mcp__chrome-devtools__new_page { url: "http://localhost:3000", isolatedContext: "ui-test" }

同一个 isolatedContext 里的页面共享 cookie/存储;换一个上下文名 = 一个全新会话。当测试需要已有的登录/状态时,用用户的默认上下文;要做无干扰的可复现性测试时,用隔离上下文。

工作流 A:diff 驱动测试

阶段 1:分析 diff

git diff --name-only HEAD~1          # or: git diff --name-only / git diff --name-only main...HEAD
git diff HEAD~1 -- <file>            # read actual changes

给改动的文件分类:

文件模式 UI 影响 测什么
*.tsx, *.jsx, *.vue, *.svelte 组件 渲染、交互、状态、边界情况
pages/**, app/**, src/routes/** 路由/页面 导航、页面加载、内容、404 处理
*.css, *.scss, *.module.css 样式 视觉外观(截图)、响应式
*form*, *input*, *field* 表单 校验、提交、空输入、超长输入、特殊字符
*modal*, *dialog*, *dropdown* 交互 打开/关闭、escape、焦点陷阱、取消 vs 确认
*nav*, *menu*, *header* 导航 链接、激活态、路由、键盘导航
仅非 UI 文件 无 跳过 —— 报告「无需 UI 测试」

阶段 2:把文件映射到 URL

检测框架:cat package.json | grep -E '"(next|react|vue|nuxt|svelte|@sveltejs|angular|vite)"'

框架 默认端口 文件 → URL 模式
Next.js App Router 3000 app/dashboard/page.tsx → /dashboard
Next.js Pages Router 3000 pages/about.tsx → /about
Vite 5173 查路由配置
Nuxt 3000 pages/index.vue → /
SvelteKit 5173 src/routes/+page.svelte → /
Angular 4200 查路由模块

阶段 3:确保跑的是对的代码

测试前,确认开发服务器提供的是 diff 里的代码 —— 而不是某个过时的分支。

如果测的是某个 PR 或特定分支:

# Check what branch is currently checked out
git branch --show-current

# If it's not the PR branch, switch to it
git fetch origin <branch> && git checkout <branch>

# Install deps — the lockfile may differ between branches
yarn install  # or npm install / pnpm install

如果开发服务器之前是在另一个分支上跑的,checkout 之后要重启它。

找出正在运行的开发服务器:

for port in 3000 3001 5173 4200 8080 8000 5000; do
  s=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$port" 2>/dev/null)
  if [ "$s" != "000" ]; then echo "Dev server on port $port (HTTP $s)"; fi
done

如果什么都没找到:让用户启动他们的开发服务器。

验证它确实能渲染:
执行 navigate_page + take_snapshot 后,检查无障碍树里是否含有真实的页面内容(导航、标题、可交互元素) —— 而不只是一个错误浮层或空 body。Next.js 开发服务器可能返回 HTTP 200,却展示一个全屏的构建错误对话框。如果快照为空或被错误对话框占满,说明服务器坏了 —— 先修构建再测试。同时尽早调用 list_console_messages { types: ["error"] } —— 一个能渲染却往控制台狂刷错误的页面,本身就已经在失败了。

阶段 4:生成测试计划

对每个改动区域,正常路径与对抗测试都要规划:

Test Plan (based on git diff)
=============================
Changed: src/components/SignupForm.tsx (added email validation)

1. [happy] Valid email submits successfully
   URL: http://localhost:3000/signup
   Steps: fill valid email → submit → verify success message appears

2. [adversarial] Invalid email shows error
   Steps: fill "not-an-email" → submit → verify error message appears

3. [adversarial] Empty form submission
   Steps: click submit without filling anything → verify error, no crash

4. [adversarial] XSS in email field
   Steps: fill "<script>alert(1)</script>" → submit → verify sanitized/rejected

5. [adversarial] Rapid double-submit
   Steps: click submit twice quickly → verify no duplicate submission

6. [adversarial] Keyboard-only flow
   Steps: Tab to email → type → Tab to submit → Enter → verify success

阶段 5:执行测试

mkdir -p .context/ui-test-screenshots
# Open the app (localhost or deployed). Use an isolated context for a clean run.
mcp__chrome-devtools__new_page { url: "http://localhost:3000", isolatedContext: "ui-test" }

每个测试都遵循前后对比模式:

# Navigate
mcp__chrome-devtools__navigate_page { type: "url", url: "http://localhost:3000/path" }
mcp__chrome-devtools__wait_for { text: "<text that proves the page is ready>" }   # optional

# BEFORE snapshot
mcp__chrome-devtools__take_snapshot
# Note the current state: elements, uids, text

# ACT (uids come from the snapshot above)
mcp__chrome-devtools__click { uid: "<uid>" }
# or: mcp__chrome-devtools__fill { uid: "<uid>", value: "..." }
# or: mcp__chrome-devtools__fill_form { ... }      # several fields at once
# or: mcp__chrome-devtools__type_text { text: "..." }
# or: mcp__chrome-devtools__press_key { key: "Enter" }

# AFTER snapshot
mcp__chrome-devtools__take_snapshot
# Compare against BEFORE: what changed?

# ASSERT with marker
# STEP_PASS|step-id|evidence  OR  STEP_FAIL|step-id|expected → actual

阶段 6:汇报结果

## UI Test Results

### STEP_PASS|valid-email-submit|status "Thanks!" appeared at uid=42 after submit
- URL: http://localhost:3000/signup
- Before: form with email input uid=3, submit button uid=7
- Action: filled "user@test.com", clicked uid=7
- After: form replaced by status element with "Thanks! We'll be in touch."

### STEP_FAIL|double-submit|expected single submission → form submitted twice|.context/ui-test-screenshots/double-submit.png
- URL: http://localhost:3000/signup
- Before: form with submit button uid=7
- Action: clicked uid=7 twice rapidly
- After: two success toasts appeared, suggesting duplicate submission
- Screenshot: .context/ui-test-screenshots/double-submit.png
- Suggestion: disable submit button after first click, or debounce the handler

---
**Summary: 4/6 passed, 2 failed**
Failed: double-submit, xss-sanitization

Screenshots saved to `.context/ui-test-screenshots/` — open any failed step's screenshot to see the broken state.

测试完成后,用 mcp__chrome-devtools__close_page 关掉你打开的额外标签页,让下一个 agent 接手一个干净的浏览器。不要关掉用户自己的其他标签页。

阶段 7:生成 HTML 报告

产出文本报告之后,生成一份独立的 HTML 报告,让评审者可以在浏览器里打开。报告把截图内联嵌入(base64),因此作为单文件即可工作 —— 无外部依赖。

为什么: 文本报告适合 agent 对话,但评审者(PM、设计师、其他工程师)想要一个可打开、可浏览、可分享的视觉产物。内联截图让失败一目了然。

怎么生成

  1. 读取 HTML 模板 references/report-template.html
  2. 用真实测试数据替换模板里的占位符来构建报告:
占位符 取值
{{TITLE}} <title> 标签的报告标题(例如 "UI Test: PR #1234 — OAuth Settings")
{{TITLE_HTML}} 可见 <h1> 的报告标题。若有 PR URL,把 PR 引用用 <a> 标签包起来使其可点击(例如 UI Test: <a href="https://github.com/org/repo/pull/1234">PR #1234</a> — OAuth Settings)。若无 URL,则用与 {{TITLE}} 相同的纯文本。
{{META}} 一行上下文:日期、应用 URL、用户、分支
{{TOTAL_TESTS}} STEP_PASS + STEP_FAIL 总数
{{AGENT_COUNT}} 参与运行的子 agent 数量
{{PASS_COUNT}} STEP_PASS 数量
{{FAIL_COUNT}} STEP_FAIL 数量
{{PASS_RATE}} 整数百分比(例如 "92")
{{RATE_CLASS}} good(≥90%)、warn(70–89%)、bad(<70%)
{{FAILURES_SECTION}} 失败测试卡片的 HTML(见下文)
{{PASSES_SECTION}} 通过测试卡片的 HTML(见下文)
  1. 为每条测试结果生成一个 &lt;details&gt; 卡片。失败的测试应默认展开,让评审者立刻看到:
&lt;!-- Failed test card (open by default) --&gt;
&lt;div class=&quot;section&quot;&gt;
  &lt;h2&gt;Failures &lt;span class=&quot;count&quot;&gt;{{FAIL_COUNT}}&lt;/span&gt;&lt;/h2&gt;
  &lt;details class=&quot;test-card fail&quot; open&gt;
    &lt;summary&gt;
      &lt;span class=&quot;badge fail&quot;&gt;FAIL&lt;/span&gt;
      &lt;span class=&quot;step-id&quot;&gt;step-id-here&lt;/span&gt;
      &lt;span class=&quot;evidence&quot;&gt;expected → actual&lt;/span&gt;
    &lt;/summary&gt;
    &lt;div class=&quot;body&quot;&gt;
      &lt;dl&gt;
        &lt;dt&gt;URL&lt;/dt&gt;&lt;dd&gt;http://localhost:3000/path&lt;/dd&gt;
        &lt;dt&gt;Action&lt;/dt&gt;&lt;dd&gt;What was done&lt;/dd&gt;
        &lt;dt&gt;Expected&lt;/dt&gt;&lt;dd&gt;What should have happened&lt;/dd&gt;
        &lt;dt&gt;Actual&lt;/dt&gt;&lt;dd&gt;What happened instead&lt;/dd&gt;
      &lt;/dl&gt;
      &lt;div class=&quot;suggestion&quot;&gt;Fix: description of suggested fix&lt;/div&gt;
      &lt;div class=&quot;screenshot&quot;&gt;
        &lt;img src=&quot;data:image/png;base64,...&quot; alt=&quot;Screenshot of failure&quot;&gt;
        &lt;div class=&quot;caption&quot;&gt;step-id.png — captured at moment of failure&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/details&gt;
&lt;/div&gt;

&lt;!-- Passed test card (collapsed by default) --&gt;
&lt;div class=&quot;section&quot;&gt;
  &lt;h2&gt;Passed &lt;span class=&quot;count&quot;&gt;{{PASS_COUNT}}&lt;/span&gt;&lt;/h2&gt;
  &lt;details class=&quot;test-card pass&quot;&gt;
    &lt;summary&gt;
      &lt;span class=&quot;badge pass&quot;&gt;PASS&lt;/span&gt;
      &lt;span class=&quot;step-id&quot;&gt;step-id-here&lt;/span&gt;
      &lt;span class=&quot;evidence&quot;&gt;evidence summary&lt;/span&gt;
    &lt;/summary&gt;
    &lt;div class=&quot;body&quot;&gt;
      &lt;dl&gt;
        &lt;dt&gt;URL&lt;/dt&gt;&lt;dd&gt;http://localhost:3000/path&lt;/dd&gt;
        &lt;dt&gt;Evidence&lt;/dt&gt;&lt;dd&gt;What was observed&lt;/dd&gt;
      &lt;/dl&gt;
    &lt;/div&gt;
  &lt;/details&gt;
&lt;/div&gt;
  1. 把截图以 base64 嵌入,使 HTML 完全自包含:
# Convert screenshot to base64 data URI
base64 -i .context/ui-test-screenshots/step-id.png | tr -d &#x27;\n&#x27;
# Use as: src=&quot;data:image/png;base64,&lt;output&gt;&quot;

读取每个在 STEP_FAIL 标记里引用的截图文件,做 base64 编码,并作为 &lt;img src=&quot;data:image/png;base64,...&quot;&gt; 嵌入对应的测试卡片。对于 STEP_PASS,仅当显式截过图时才嵌入(例如基线截图)。

  1. 把最终 HTML 写到 .context/ui-test-report.html:
# Write the generated HTML
cat &gt; .context/ui-test-report.html &lt;&lt; &#x27;REPORT_EOF&#x27;
&lt;!DOCTYPE html&gt;
...generated report...
REPORT_EOF

# Open it for the reviewer
open .context/ui-test-report.html  # macOS
# xdg-open .context/ui-test-report.html  # Linux
  1. 告诉用户:Report saved to .context/ui-test-report.html,并主动提出帮他打开。

规则:
- 失败区放在通过区之前 —— 评审者最先关心的是哪里坏了
- 失败卡片默认 open;通过卡片默认折叠
- 每个 STEP_FAIL 卡片都必须嵌入一张截图 —— 如果截图文件缺失,在卡片里注明
- 如果提供了修复建议,在每个失败卡片里包含该建议/修复
- 报告必须能离线工作 —— 无 CDN 链接、无外部资源
- 把 HTML 控制在 5MB 以内 —— 如果截图把它撑超了,降低图片质量,或对通过项跳过基线截图

对抗式测试模式

把这些应用到你测的每个可交互元素上。完整的模式库(表单、模态框、导航、错误状态、键盘无障碍)见 references/adversarial-patterns.md。

确定性检查

这些产出结构化数据,而非主观判断。把它们当作最强形式的断言来用。

检查 能抓到什么 断言
axe-core WCAG 违规 violations.length === 0
控制台错误 运行时异常、失败的请求 空的错误数组
损坏图片 缺失/加载失败的图片 没有 naturalWidth === 0 的图片
表单标签 没有可访问标签的输入框 每个输入都 hasLabel: true

确切的 evaluate_script 配方见 references/browser-recipes.md。

工作流 B:探索式测试

没有 diff,没有计划 —— 就打开应用,想办法把它弄坏。当用户说「测我的应用」「找 bug」「QA 一下这个站点」时用它。

方法

  1. 摸清应用 —— 读 package.json 检测框架,然后打开根 URL 并快照,看看里面有什么
  2. 遍历一切 —— 点遍导航链接,访问每个能到达的页面,记下存在什么
  3. 测你发现的东西 —— 对每个页面,应用下面的对抗式模式(表单、模态框、导航、键盘、错误状态)
  4. 跑确定性检查 —— 对每个页面跑 axe-core、控制台错误、损坏图片、表单标签
  5. 汇报发现 —— 用 STEP_PASS/STEP_FAIL 标记,失败项附上复现步骤

不必追求系统化的覆盖。就像一个用户那样探索,但带着把东西弄坏的意图。agent 擅长这个 —— 放手让它去逛。

探索式运行的技巧

  • 从首页开始,然后自然地顺着导航走
  • 试试 404 页(/does-not-exist) —— 是自定义的还是默认的?
  • 找空状态(没有数据的页面)
  • 先用垃圾输入再用有效输入测表单
  • 在每个页面检查移动端视口(375px) —— 会溢出吗?用 resize_page { width: 375, height: 812 } 或 emulate 套用设备预设
  • 如果应用有认证,在真实 Chrome(默认上下文)里登录一次,会话就会延续 —— 无需 cookie-sync

工作流 C:分组顺序测试

chrome-devtools MCP 驱动一个 Chrome,所以测试分组不能并发跑 —— select_page 是全局的,并行 agent 会破坏彼此的状态。取而代之,把一个大任务拆成多个分组以隔离上下文,并接连运行:分派一个子 agent,让它跑完并汇报,再分派下一个。每个分组可以独占自己的标签页(new_page),主 agent 在最后汇总结果。

当你要测很多页面或类别、又想要每组干净的汇报且不撑爆单个 agent 的上下文时,用它。

完整工作流见 references/parallel-testing.md:分组拆分、顺序分派 agent、标签页/页面管理、以及结果汇总。

设计一致性

检查改动后的 UI 在视觉上是否与应用其余部分相符。做视觉或设计检查时,读 references/design-consistency.md。

测试类别

类别 怎么做 断言类型
无障碍 axe-core + 键盘导航 确定性(违规计数)
视觉质量 截图 + 启发式评估 视觉判断(最弱 —— 注明具体细节)
响应式 视口扫描 + 截图 视觉 + 确定性(溢出检查)
控制台健康 控制台捕获 eval 确定性(错误计数)
UX 启发式 快照 + Laws of UX + Nielsen 原则 结构化判断(引用具体启发式)
错误状态 导航到空状态/错误状态 前后对比
数据展示 对表格/仪表盘做快照 元素匹配(列数、格式化)
设计一致性 截基线图 + 改动页对比 视觉判断(引用具体属性)
探索式 自由导航 + 对抗式测试 前后对比 + 判断

参考指南(按需加载):
- 对抗式模式 —— references/adversarial-patterns.md —— 测试表单、模态框、导航或键盘 a11y 时加载
- 浏览器配方 —— references/browser-recipes.md —— 跑确定性检查(axe-core、控制台、图片、表单标签)时加载
- 探索式测试 —— references/exploratory-testing.md —— 用于工作流 B(无 diff,开放探索)
- UX 启发式 —— references/ux-heuristics.md —— 评估 UX 质量或引用具体启发式时加载
- 设计系统 —— references/design-system.example.md —— 供用户自行定制的模板
- 设计一致性 —— references/design-consistency.md —— 做视觉一致性检查时加载
- 分组顺序测试 —— references/parallel-testing.md —— 用于工作流 C(在一个浏览器上接连跑分组)
- 报告模板 —— references/report-template.html —— 阶段 7 生成报告用的 HTML 模板

带确切命令的实战示例见 EXAMPLES.md,如果你想看断言协议的实际运行效果。

最佳实践

  1. 保持对抗 —— 想办法弄坏,别只确认它能跑
  2. 每条断言都要有证据 —— 快照 uid、evaluate_script 结果,或前后 diff
  3. 每次交互都做前后对比 —— 快照、动作、快照、对比
  4. 使用 uid 前先重新快照 —— uid 每次快照都会变;永远基于最新的那次操作
  5. 每个失败都截图 —— STEP_FAIL 时立即 take_screenshot { filePath: ... },保存到 .context/ui-test-screenshots/&lt;step-id&gt;.png
  6. 先做确定性检查 —— axe-core、控制台错误、表单标签先于视觉判断
  7. 可复现的运行用隔离上下文 —— new_page { isolatedContext: &quot;ui-test&quot; };仅当需要已有登录/状态时才用默认上下文
  8. 一个浏览器,同一时刻一个 agent —— 顺序分派测试分组子 agent,完成后关掉额外标签页(close_page)
  9. 失败要带复现步骤汇报 —— 动作、预期、实际、截图路径、建议

故障排查

  • 没有页面 / 工具不可用:调用 list_pages;如果它报错,说明 chrome-devtools MCP 未连接 —— 让用户启用它。如果没有页面,用 new_page { url }。
  • 开发服务器无响应:curl http://localhost:&lt;port&gt; —— 让用户启动它
  • evaluate_script 与 await:传一个 async () =&gt; { ... } 函数 —— evaluate_script 会 await 返回的 promise。结果必须可 JSON 序列化。
  • 元素 uid 找不到 / 已失效:重新 take_snapshot —— uid 在每次快照及任何 DOM 变化后都会重新编号
  • 空白快照:快照前先 wait_for { text: &quot;...&quot; }(或重新导航);页面可能还没渲染完
  • SPA 深链接 404:先导航到 /,再点进去
  • 认证失败:在真实 Chrome(默认上下文)里手动登录 —— MCP 会复用那个会话。如果你打开了 isolatedContext,它按设计是未登录状态;去掉隔离上下文即可继承登录态。
  • 焦点在错误的标签页:list_pages 然后 select_page { pageId } —— 记住这是全局的,所以同一时刻只应有一个 agent 驱动浏览器
  • 对话框阻塞:用 handle_dialog 处理原生对话框,或给 evaluate_script 传 dialogAction / 给 navigate_page 传 handleBeforeUnload

常见问题

5 问
答案由本站依据条目字段整理
Chrome 对抗式 UI 测试怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_fa822256/yzfly-chrome-qa-agent。安装方式为未标注。装完刷新技能列表或重开客户端。

Chrome 对抗式 UI 测试支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

Chrome 对抗式 UI 测试权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

Chrome 对抗式 UI 测试收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

Chrome 对抗式 UI 测试用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 2026-11-06。