关于 ui-test
ui-test 是用于在真实浏览器中对 UI 变更进行对抗式测试的 Agent 技能。它支持基于 diff、探索式和并行测试,由子 Agent 执行分配的检查并提交有证据的结果。
主要功能
- 01基于 diff 的 UI 测试
- 02探索式浏览器测试
- 03子 Agent 并行分组测试
- 04结构化断言与失败截图
- 05功能、边缘情况和无障碍检查
适用场景
- 01验证 git diff 中的 UI 变更
- 02探查表单和流程的边缘故障
- 03在多个浏览器分派独立测试
- 04提交带证据的可复现故障报告
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ browserbase/ skills --skill ui-test安装后在 Claude Code 中输入/ui-test确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
EXAMPLES.mdLICENSE.txtREADME.mdreferences/adversarial-patterns.mdbrowser-recipes.mddesign-consistency.mddesign-system.example.mdexploratory-testing.mdparallel-testing.mdreport-template.htmlux-heuristics.md详细介绍
UI Test — Agentic UI Testing Skill
在真实浏览器中测试 UI 变更。你的任务是尝试找出问题,而不是确认功能正常。
三种工作流:
- 差异驱动 — 分析 git diff,只测试发生变更的部分
- 探索式 — 浏览应用,找出开发者未曾想到的错误
- 并行 — 将独立的测试组分配到多个 Browserbase 浏览器并行执行
测试如何进行
主 Agent 负责协调——制定测试策略、将任务分配给子 Agent,并汇总结果。子 Agent 负责实际的浏览器测试。
规划:从多个角度分析,然后一次性执行
在启动任何子 Agent 之前,你必须亲自完成全部三轮规划并输出结果。 规划应在你自己的回复中完成,不能委托给子 Agent。不要跳过规划直接开始执行。
第 1 轮——功能: 核心用户流程有哪些?哪些功能应该正常运行?按以下格式写出每项测试:操作 → 预期结果。
第 2 轮——对抗性测试: 重新阅读第 1 轮。遗漏了什么?考虑以下方面:不同用户类型/角色、错误路径、空状态、竞态条件、边界输入(空值、超大输入、特殊字符、快速点击)。
第 3 轮——覆盖缺口: 重新阅读第 1–2 轮。还要考虑哪些方面?无障碍(axe-core、仅用键盘操作)、移动端视口、控制台错误、与应用其他部分的视觉一致性。
去重: 将三轮内容合并成一份带编号的测试清单。删除重复项。为每项测试分配一个组(例如 Group A、Group B)。
然后一次性执行——每组启动一个子 Agent。每个子 Agent 只会收到分配给自己的具体测试清单,不会收到其他内容。子 Agent 不进行探索或规划,只执行分配的测试并报告结果。
调用任何 Agent 工具之前,先在回复中输出三轮规划、合并后的计划和分组分配。
拆分工作的原则
- 子 Agent 执行分配的测试,不进行开放式探索。 主 Agent 将具体的编号测试清单交给每个子 Agent。子 Agent 不规划、不探索,也不自行决定测试内容,只执行清单并停止。
- 瓶颈在于最慢的 Agent——拆分工作时,不要让任何单个 Agent 承担过多任务。多个小型 Agent 优于少数大型 Agent。
- 根据变更规模安排工作量——单个组件的修复不需要很多 Agent 或很多步骤;整页重新设计则需要更多。让 diff 的范围决定计划。
- 失败后不要提前停止——在分配的测试范围内尽可能多地找出问题。
为子 Agent 设置步骤预算
主 Agent 必须在每个子 Agent 提示词中明确规定浏览步骤上限。 子 Agent 不会自行限制;如果没有明确要求,它们会一直运行到完成为止。
粗略参考:少量针对性检查约 25 步;包含功能、对抗性和无障碍测试的完整页面约 40 步;多个页面或范围较广的类别约 75 步。根据分配的测试实际所需进行调整——这些只是起始参考,并非硬性规定。
粗略参考:少量针对性检查约 25 步;包含功能、对抗性和无障碍测试的完整页面约 40 步;多个页面或范围较广的类别约 75 步。根据分配的测试实际所需进行调整——这些只是起始参考,并非硬性规定。
每个子 Agent 的提示词都必须包含:
You have a budget of N browse steps (each `browse` command = 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
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. Return only step markers and your findings as text.
主 Agent 不应自行运行 browse 命令(验证开发服务器是否启动除外)。所有测试都由子 Agent 执行。
子 Agent 达到步骤预算时,主 Agent 应原样接受部分结果。 不要重新运行或重试该子 Agent。在最终报告中列出已跳过的测试,让开发者知道哪些测试未覆盖。
报告
每个子 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%
不要报告“使用的步骤数”——浏览命令计数只是实现细节,对审核者来说并非有意义的指标。
测试理念
你是一个对抗性测试人员。 你的目标是找出 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-cancelevidence:证明步骤通过的观察结果(元素 ref、文本内容、URL、eval 结果)expected → actual:预期结果与实际结果screenshot-path:已保存截图的路径(仅失败时——请参阅下方的截图捕获)
失败时捕获截图
每个 STEP_FAIL 都必须附带截图,让开发者能直观看到问题所在。
测试步骤失败时:
# 1. Take a screenshot immediately after observing the failure
browse screenshot --path .context/ui-test-screenshots/<step-id>.png
# If --path is not supported, take the screenshot and save manually:
browse screenshot
# The browse CLI will output the screenshot path — move/copy it:
cp /tmp/browse-screenshot-*.png .context/ui-test-screenshots/<step-id>.png
在每次测试运行开始时设置截图目录:
mkdir -p .context/ui-test-screenshots
规则:
- 文件名 = step-id(例如,
double-submit.png、axe-audit.png、modal-focus-trap.png) - 存放在
.context/ui-test-screenshots/中——此目录已加入 gitignore,开发者和其他 Agent 均可访问 - 并行运行时,加入会话名称:
<session>-<step-id>.png(例如,signup-double-submit.png) - 在失败发生时立即截图——捕获故障状态,而不是恢复后的状态
- 对于视觉或布局 Bug,也要截取基线(正常状态)截图,以便比较:
<step-id>-baseline.png
验证方式(按严谨程度排序)
- 确定性检查(最有力)——
browse eval返回可供检查的结构化数据。例如:axe-core 违规数量、document.title、表单字段值、控制台错误数组、元素数量。 - 快照元素匹配——无障碍树中存在具有特定角色和文本的特定元素。通过 ref 检查:
@0-12 button "Save"。元素要么存在于树中,要么不存在。 - 操作前后比较——操作前获取快照,执行操作,再获取操作后的快照。确认树按预期发生变化(元素出现、消失或文本改变)。
- 截图 + 视觉判断(最弱)——仅用于无障碍树无法捕获的视觉属性(颜色、间距、布局)。务必说明具体评估内容。
操作前后比较模式
这是核心验证循环。每次交互都使用它:
# 1. BEFORE: capture state
browse snapshot
# Record: what elements exist, their text, their refs
# 2. ACT: perform the interaction
browse click @0-12
# 3. AFTER: capture new state
browse 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 @0-20
# If nothing changed:
browse screenshot --path .context/ui-test-screenshots/modal-open.png
# STEP_FAIL|modal-open|expected dialog to appear → snapshot unchanged|.context/ui-test-screenshots/modal-open.png
设置
which browse || npm install -g browse
避免权限疲劳
此技能会运行许多 browse 命令(快照、点击、eval)。为了避免每次都要批准,请将 browse 添加到允许的命令中:
将两种模式都添加到 .claude/settings.json(项目级)或 ~/.claude/settings.json(用户级):
{
"permissions": {
"allow": [
"Bash(browse:*)",
"Bash(BROWSE_SESSION=*)"
]
}
}
第一种模式涵盖普通 browse 命令。第二种模式涵盖并行会话(BROWSE_SESSION=signup browse open ...)。两种模式都需要添加,才能避免出现批准提示。
模式选择
| 目标 | 模式 | 命令 | 身份验证 |
|---|---|---|---|
localhost / 127.0.0.1 | 本地 | browse open <url> --local | 无需认证(默认使用干净、隔离的本地浏览器) |
| 已部署/预发布站点 | 远程 | browse open <url> --remote | 需要 Browserbase 凭据;在支持的情况下使用上下文 |
规则:如果目标 URL 包含 localhost 或 127.0.0.1,首次运行 browse open 时必须传入 --local。
本地模式(默认用于 localhost)
browse open http://localhost:3000 --local
browse open ... --local 默认使用干净、隔离的本地浏览器,非常适合执行可复现的 localhost QA 测试。
仅在需要时使用本地模式变体:
browse open <url> --auto-connect— 自动发现现有的、可调试的本地 Chrome。仅当测试明确需要使用现有的本地登录状态、Cookie 或状态数据时使用。browse open <url> --cdp <port|url>— 附加到指定的 CDP 目标(显式附加到本地浏览器)。
远程模式(通过 Cookie 同步访问已部署的网站)
# Step 1: Sync cookies from local Chrome to Browserbase
node .claude/skills/cookie-sync/scripts/cookie-sync.mjs --domains your-app.com
# Output: Context ID: ctx_abc123
# Step 2: Open in remote mode with the synced context
SESSION_JSON="$(browse cloud sessions create --context-id ctx_abc123 --persist --keep-alive)"
SESSION_ID="$(echo "$SESSION_JSON" | jq -r .id)"
CONNECT_URL="$(echo "$SESSION_JSON" | jq -r .connectUrl)"
browse open https://staging.your-app.com --cdp "$CONNECT_URL"
browse snapshot
# ... run tests ...
browse stop
browse cloud sessions update "$SESSION_ID" --status REQUEST_RELEASE
Cookie 同步标志:--domains、--context、--verified、--proxy "City,ST,US"
工作流 A:由差异驱动的测试
阶段 1:分析差异
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 键、焦点陷阱、取消与确认 |
*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:确保运行的是正确的代码
测试前,确认开发服务正在提供差异中的代码,而不是过期分支的代码。
如果测试 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
如果开发服务已在其他分支上运行,请在检出目标分支后重启服务。
查找正在运行的开发服务:
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
如果未找到任何服务:告知用户启动开发服务。
确认页面确实正常渲染:
执行 browse open 和 browse snapshot 后,检查无障碍树中是否包含真实页面内容(导航、标题、交互元素),而非只有错误覆盖层或空白正文。Next.js 开发服务可能返回 HTTP 200,但显示全屏构建错误对话框。如果快照为空或主要内容是错误对话框,则说明服务存在问题 — 测试前先修复构建问题。
阶段 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:执行测试
browse stop 2>/dev/null
mkdir -p .context/ui-test-screenshots
# localhost/default QA → clean, reproducible local run
browse open http://localhost:3000 --local
每项测试都遵循前后对照模式:
# Navigate
browse open http://localhost:3000/path --local
browse wait load
# BEFORE snapshot
browse snapshot
# Note the current state: elements, refs, text
# ACT
browse click @0-ref
# or: browse fill "selector" "value"
# or: browse type "text"
# or: browse press Enter
# AFTER snapshot
browse 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 @0-42 after submit
- URL: http://localhost:3000/signup
- Before: form with email input @0-3, submit button @0-7
- Action: filled "[email protected]", clicked @0-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 @0-7
- Action: clicked @0-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.
完成后务必执行 browse stop。
阶段 7:生成 HTML 报告
生成文本报告后,再生成一份独立的 HTML 报告,供审核者在浏览器中打开。报告会以内嵌的 Base64 格式包含截图,因此整个报告只需一个文件即可运行,无需外部依赖。
**原因:**文本报告适合 Agent 对话,但审核者(产品经理、设计师及其他工程师)需要一份可打开、浏览和分享的可视化材料。内嵌截图能让故障一目了然。
生成方式
- 阅读 HTML 模板 references/report-template.html
- 将实际测试数据填入模板占位符,生成报告:
| 占位符 | 值 |
|---|---|
{{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(见下文) |
- 为每个测试结果生成一个
<details>卡片。失败测试应默认展开,以便审核者立即看到:
<div class="section">
<h2>Failures <span class="count">{{FAIL_COUNT}}</span></h2>
<details class="test-card fail" open>
<summary>
<span class="badge fail">FAIL</span>
<span class="step-id">step-id-here</span>
<span class="evidence">expected → actual</span>
</summary>
<div class="body">
<dl>
<dt>URL</dt><dd>http://localhost:3000/path</dd>
<dt>Action</dt><dd>What was done</dd>
<dt>Expected</dt><dd>What should have happened</dd>
<dt>Actual</dt><dd>What happened instead</dd>
</dl>
<div class="suggestion">Fix: description of suggested fix</div>
<div class="screenshot">
<img src="data:image/png;base64,..." alt="Screenshot of failure">
<div class="caption">step-id.png — captured at moment of failure</div>
</div>
</div>
</details>
</div>
<div class="section">
<h2>Passed <span class="count">{{PASS_COUNT}}</span></h2>
<details class="test-card pass">
<summary>
<span class="badge pass">PASS</span>
<span class="step-id">step-id-here</span>
<span class="evidence">evidence summary</span>
</summary>
<div class="body">
<dl>
<dt>URL</dt><dd>http://localhost:3000/path</dd>
<dt>Evidence</dt><dd>What was observed</dd>
</dl>
</div>
</details>
</div>
- 将屏幕截图嵌入为 base64,使 HTML 完全自包含:
# Convert screenshot to base64 data URI
base64 -i .context/ui-test-screenshots/step-id.png | tr -d '\n'
# Use as: src="data:image/png;base64,<output>"
读取 STEP_FAIL 标记中引用的每个屏幕截图文件,将其编码为 base64,并作为 <img src="data:image/png;base64,..."> 嵌入对应的测试卡片中。对于 STEP_PASS,仅在明确截取了屏幕截图时才嵌入(例如,基线屏幕截图)。
- 将最终 HTML 写入
.context/ui-test-report.html:
# Write the generated HTML
cat > .context/ui-test-report.html << 'REPORT_EOF'
<!DOCTYPE html>
...generated report...
REPORT_EOF
# Open it for the reviewer
open .context/ui-test-report.html # macOS
# xdg-open .context/ui-test-report.html # Linux
- 告知用户:
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 |
准确的 browse eval 操作步骤请参阅 references/browser-recipes.md。
工作流 B:探索性测试
没有差异、没有计划——只需打开应用并尝试找出问题。当用户说“测试我的应用”“找出错误”或“对这个网站进行 QA”时,使用此工作流。
方法
- 探索应用 — 阅读
package.json以检测框架,然后打开根 URL 并查看快照,了解页面内容 - 浏览所有内容 — 点击导航链接,访问所有可访问的页面,并记录页面内容
- 测试发现的内容 — 对每个页面应用以下对抗性模式(表单、模态框、导航、键盘、错误状态)
- 运行确定性检查 — 在每个页面上检查 axe-core、控制台错误、损坏的图片和表单标签
- 报告发现 — 使用 STEP_PASS/STEP_FAIL 标记,并附上失败项的复现步骤
不要试图系统地覆盖所有内容。像用户一样探索,但要以找出问题为目的。Agent 很擅长这个——让它自由探索。
探索性测试提示
- 从首页开始,然后自然地浏览导航
- 尝试访问 404 页面(
/does-not-exist)——它是自定义页面还是默认页面? - 查找空状态(没有数据的页面)
- 在输入有效内容之前,先用无效内容测试表单
- 在每个页面上检查移动端视口(375px)——是否出现溢出?
- 如果应用有身份验证,先使用 cookie-sync
工作流 C:并行测试
使用命名的 browse 会话(BROWSE_SESSION=<name>)并发运行相互独立的测试组。每个会话都有自己的浏览器。适用于本地模式和远程模式。
测试多个页面或类别且希望缩短实际耗时时使用。
阅读 references/parallel-testing.md,了解完整工作流:会话设置、Agent 扇出、身份验证的 cookie-sync,以及结果合并。
设计一致性
检查更改后的 UI 在视觉上是否与应用的其余部分一致。进行视觉或设计检查时,请阅读 references/design-consistency.md。
测试类别
| 类别 | 方法 | 断言类型 |
|---|---|---|
| 无障碍 | axe-core + 键盘导航 | 确定性(违规数量) |
| 视觉质量 | 截图 + 启发式评估 | 视觉判断(最不可靠——注明具体情况) |
| 响应式 | 视口扫描 + 截图 | 视觉 + 确定性(溢出检查) |
| 控制台健康状况 | 控制台捕获评估 | 确定性(错误数量) |
| UX 启发式 | 快照 + UX 法则 + Nielsen's | 结构化判断(引用具体启发式原则) |
| 错误状态 | 导航至空状态/错误状态 | 前后对比 |
| 数据展示 | 对表格/仪表板使用快照 | 元素匹配(列数、格式) |
| 设计一致性 | 截图基准 + 更改页面对比 | 视觉判断(引用具体属性) |
| 探索性 | 自由导航 + 对抗性测试 | 前后对比 + 判断 |
参考指南(按需加载):
- 对抗性模式 — references/adversarial-patterns.md — 测试表单、模态框、导航或键盘无障碍功能时加载
- 浏览器操作指南 — references/browser-recipes.md — 运行确定性检查(axe-core、控制台、图片、表单标签)时加载
- 探索性测试 — references/exploratory-testing.md — 用于工作流 B(无差异、开放式探索)
- 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。
最佳实践
- 持对抗性思维 — 尝试破坏功能,而不只是确认它们能正常工作
- 每项断言都需要证据 — 快照引用、评估结果或前后差异
- 每次交互都要记录前后状态 — 快照、操作、快照、比较
- 每次失败都要截图 — 在 STEP_FAIL 时立即运行
browse screenshot,并保存到.context/ui-test-screenshots/<step-id>.png - 先进行确定性检查 — 在视觉判断前检查 axe-core、控制台错误和表单标签
- 对于 localhost,从干净的本地模式开始 — 在首次
browse open时传入--local,以确保运行可复现;只有在需要保留现有本地状态时才使用--auto-connect - 完成后始终运行
browse stop— 并行运行时,停止每个命名会话 - 报告失败时附上复现步骤 — 操作、预期结果、实际结果、截图路径和建议
- 并行执行互不依赖的测试 — 在已部署的网站上测试多个页面或类别时,使用工作流 C 和命名会话
故障排除
- “No active page”:运行
browse stop,然后重试。对于僵尸进程:pkill -f "browse.*daemon" - 开发服务器无响应:运行
curl http://localhost:<port>— 请用户启动服务器 browse eval搭配await失败:改用.then()—browse eval不支持顶层 await- 找不到元素引用:重新运行
browse snapshot— 页面更新后引用会变化 - 快照为空:在截取快照前运行
browse wait load或browse wait selector ".expected" - SPA 深层链接返回 404:先导航到
/,然后再逐步点击 - 远程身份验证失败:使用
--context <id>重新运行 cookie-sync,并尝试--verified - 并行会话冲突:确保每条
browse命令都使用BROWSE_SESSION=<name>— 若不指定,命令会发送到默认会话 - 会话无法停止:运行
BROWSE_SESSION=<name> browse stop。对于僵尸进程:pkill -f "browse.*<name>.*daemon"