mcpField
B
browser-qa

browser-qa

github.com/bhagyamudgal测试与质量2108 次安装5 天前更新
代码仓库

关于 browser-qa

面向 Web 界面和 API 流程测试的浏览器 QA skill,通过真实浏览器执行步骤并收集截图、录屏及可用的网络和控制台证据。它按工具可用性选择 T3、Playwright MCP 或 agent-browser,并要求明确报告缺失证据和失败步骤。

主要功能

  1. 01按优先级选择浏览器驱动
  2. 02每次交互前重新检查页面
  3. 03逐步保存截图并记录测试流程
  4. 04检查 API 请求与控制台错误
  5. 05执行变更预检并生成结构化结果

适用场景

  1. 01验证 Web 界面的用户操作流程
  2. 02用测试矩阵检查 API 端点行为
  3. 03为变更流程收集截图和录屏证据

MCP 相关

可通过 Playwright MCP 的浏览器工具驱动测试;若该工具不可用,则使用 T3 预览工具或 agent-browser CLI。

安装

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

$npx skills add https://github.com/bhagyamudgal/skills --skill browser-qa

安装后在 Claude Code 中输入/browser-qa确认已加载。

详细介绍

我会通过完整流程操作真实浏览器,并且只有在亲眼看到流程正常运行后才会判定完成。每一步都会截取屏幕截图,完整运行过程会录制视频,会对触发 API 的操作进行网络检查,并检查控制台是否出现新错误。

驱动程序优先级

  1. 如果工具列表中有 t3-code_preview_snapshot,我只使用 T3 预览工具。先用 t3-code_preview_open 打开页面,再用 t3-code_preview_navigate 前往 URL,然后循环调用 t3-code_preview_snapshot,再调用 t3-code_preview_click 或 t3-code_preview_type。每次交互前都会重新截取屏幕快照,因为引用可能会过期。我会保持 open=true,让用户看到运行过程。
  2. 否则,如果有 Playwright MCP 的 browser_navigate,我会原样使用 Playwright 流程。
  3. 否则,我会使用 agent-browser CLI(open、snapshot -i、click @eN、fill @eN)。对于 CLI 无法提供的证据,我会报告为缺失,绝不擅自假定。

Playwright 到 T3 的映射:browser_navigate 对应 t3-code_preview_navigate,browser_snapshot 对应 t3-code_preview_snapshot,browser_click 对应 t3-code_preview_click,browser_type 对应 t3-code_preview_type,browser_press 对应 t3-code_preview_press,browser_wait_for 对应 t3-code_preview_wait_for。屏幕截图通过设置 save=true 调用 t3-code_preview_snapshot 获取,该调用会返回一个 screenshotPath,需要将其移入 .qa/。

录制

我会录制每次测试流程运行,而不只是截取屏幕截图。在 T3 上,我会在第一步之前调用 t3-code_preview_recording_start,并在最后一步之后调用 t3-code_preview_recording_stop,以保存本地证据文件。使用 agent-browser CLI 时,我会用 record start .qa/<flow-name>.webm 和 record stop 标记录制的开始和结束。Playwright MCP 没有视频工具,因此此时会以屏幕截图序列作为记录,并报告视频不可用,绝不伪造视频。

录制分辨率至少为 1920x1080;对于可设置帧率的驱动程序,帧率至少设为 30 fps。在 T3 上,我会在开始录制前使用 t3-code_preview_resize 将视口设为不小于该尺寸。CLI 的 record start 会以自己的尺寸打开全新上下文,因此之前设置的视口不会保留:执行 record stop 后,我会检查文件尺寸;如果低于最低要求,我会如实报告,而不会声称符合要求。两种驱动程序都无法设置帧率,因此我会使用录制器的默认值,并在文件生成后报告该值。

输入

  • 自然语言流程,例如“创建一个包含 3 种食材的食谱,并验证营养数据是否计算正确”。
  • URL 加操作说明,例如 http://localhost:3000/orders 加上“点击 New Order,填写供应商并提交”。
  • API 端点加测试矩阵,例如 GET /v1/shop/:clientId/patients-order-overview 加上“验证标签筛选、日期筛选、分页、错误处理和数量一致性”。此时,我会直接测试端点,使用 curl 或在已认证会话中发起页面内请求,逐项汇总测试用例,然后生成下方的 QA 测试结果报告。

未提供 URL 时,我默认使用 http://localhost:3000。

UI 更改刚完成但未指定流程时,我会询问要测试哪个流程,例如“测试 localhost:3000/orders 中的订单创建”。

步骤 1:准备

mkdir -p .qa
[ -s .gitignore ] && [ -n "$(tail -c1 .gitignore)" ] && printf '\n' >> .gitignore
grep -qxF '.qa/' .gitignore 2>/dev/null || printf '.qa/\n' >> .gitignore

我会使用 curl -s -o /dev/null -w "%{http_code}" <url> 检查开发服务器是否正在运行。如果无法访问,我会请用户启动服务器。

第 2 步:身份验证检查

  1. 我使用上述优先级中选定的驱动程序打开 URL,并对页面进行快照。
  2. 我会查找登录表单指示,例如 input[type=password]、URL 中的 /login,或与身份验证相关的文本。
  3. 找到这些指示时,说明当前会话尚未登录。我会让用户在浏览器中手动登录,然后说“完成”。之后我会再次检查。
  4. 没找到任何指示并不能证明什么。未登录的页面也可能在没有可见表单的情况下呈现。我会先确认登录后的标记,例如账户名称、注销或个人资料控件,或用户专属内容。只有确认存在标记后,我才会继续执行测试。若没有标记,我会将会话视为未知,并请用户登录并确认。

第 3 步:执行测试流程

我会将用户的流程解析为编号步骤,并启动一个子 Agent。子 Agent 使用我在第 2 步中选定的驱动程序,并遵循上述驱动程序优先级。

在 T3 中,每次调用 Playwright 时都会按上述映射进行转换,然后运行下方的提示词模板。T3 的网络和控制台证据来自子 Agent 安装的收集器:在第一步之前安装,并在每次导航后重新安装;在安装后建立基线,然后在每次触发 API 的操作后读取数据。如果页面阻止安装收集器,则报告该证据类型不可用,绝不伪造。在 Playwright MCP 上,模板保持不变。在 agent-browser CLI 回退方案中,browser_navigate 转换为 open,browser_snapshot 转换为 snapshot -i,交互操作转换为 click @eN 和 fill @eN "text",截图、网络和控制台证据则使用 agent-browser --help 中最接近的 agent-browser 对应功能。证据标准不会降低。每个步骤仍然都需要截图;CLI 无法生成的证据必须报告为缺失,绝不能擅自假定其存在。

变更预检(主 Agent,在派发之前)

我会在子 Agent 创建之前完成此步骤。派发的子 Agent 无法与用户沟通,因此,如果在子 Agent 内部得出 confirmation-required 结论,流程就会卡住:浏览器仍开着,却没人能回应。

当 URL 看起来像生产环境,或任何已解析步骤会修改共享数据时,我会在此处调用 preflight-mutations。我会提供准确的环境 URL、已通过身份验证的账户和工作区、操作和记录 ID、所有权、测试前的记录快照、还原或补偿步骤,以及用户授权。我会在主 Agent 中应用其结果契约。若结果为 confirmation-required,我会向用户展示确认卡片,并在派发之前取得用户决定。若结果为 blocked,我会报告其 后续操作,且不派发任何内容。只有 ready 卡片才会作为 {ready card} 插入下方的提示词中。

仅涉及一次性数据的本地流程无需使用此门控。我会将 not-applicable, local flow, disposable data only 作为 {ready card} 传入。

子 Agent 提示词模板

使用 {driver: T3 preview tools | Playwright MCP tools | agent-browser CLI},在 {URL} 执行以下 QA 测试流程。认证检查已在浏览器会话中打开 {URL}。

测试步骤。{用户流程描述中的编号步骤}。

变更授权。{ready card}。

该卡片已获授权。不要自行调用 preflight-mutations,因为你无法回答它可能提出的问题。对于每次共享状态交互,在写入前立即重新读取并比较目标当前的 guards。只要它们匹配,就按该卡片继续操作。若 guard 发生变化,请停止待执行的交互,并将尚未执行的剩余操作交还主 Agent 重新预检,而不是写入。写入后,执行卡片规定的权威回读,根据观察到的状态更新 guards,并将该项记录为 landed、failed 或 reconcile-required。结果不明确时,记录为 reconcile-required。停止该项操作,并报告以便根据权威状态解决。绝不要自行重试。

对于每一步,先获取快照(T3 使用 t3-code_preview_snapshot,Playwright 使用 browser_snapshot,CLI 使用 snapshot -i)。页面一旦变化,Refs 就会立即失效,因此每次交互前都要重新获取快照。使用同一驱动执行交互。将证据保存为截图文件 .qa/<NN>-<step-name>.png:在 T3 上调用 t3-code_preview_snapshot 并设置 save=true,然后将返回的 screenshotPath 移至该路径;在 Playwright 上调用 browser_take_screenshot 并使用该文件名;在 CLI 上使用 screenshot。任何会触发 API 的操作之后,都要检查网络,并检查是否有新错误:在 T3 上通过 t3-code_preview_evaluate 读取预装的收集器;在 Playwright 上使用 browser_network_requests 和 browser_console_messages;在 CLI 上使用 network requests 和 console。如果驱动无法生成某种证据,请报告该证据不可用,不要伪造。没有证据的步骤判定为 FAIL。

证据收集器(仅限 T3)。在第一个测试步骤之前,通过 t3-code_preview_evaluate 安装网络和控制台收集器:包装 fetch 和 XMLHttpRequest,监听 error 和 unhandledrejection 事件,并将日志写入页面全局数组,然后记录流程开始前的基线。每次导航后都要重新安装收集器,因为导航会销毁页面全局变量。之后每次检查网络和控制台时,都要读取这些数组;读取时若数组不存在,请报告该步骤的证据不可用,而不是报告无异常。

录制。在第一个测试步骤之前开始录制,并在最后一个测试步骤之后停止录制,遵循上文的 Recording 部分。报告结果时,使用 Recording: <path>;若驱动无法录制,则使用 Recording: unavailable。

按照下文第 4 步的格式报告每一步。每个编号步骤都必须标注 PASS 或 FAIL。无法执行的步骤也必须标注 FAIL,不得省略。

清理。若录制仍在进行,先停止录制。在 Playwright MCP 上,调用 browser_close。在 T3 上,保持预览标签页打开,以便用户保留观看内容。在 agent-browser CLI 上,运行 record stop 后再运行 agent-browser close。

第 4 步:报告

QA: <flow description>

Step 1: <description>
  PASS: <observation>

Step 2: <description>
  PASS: <observation>
  API: POST /api/endpoint -> 201

Step 3: <description>
  FAIL: Expected X, got Y
  Screenshot: .qa/03-step-name.png

Console errors: <list or "none">
Screenshots: .qa/ (<N> files)
Recording: <path or "unavailable">

VERDICT: <ALL PASS | PARTIAL | FAIL> (N/M steps)

失败时,我会提供预期结果与实际结果的准确对比,并引用截图。

上方的录制路径是交接给 file-pr 的路径;它会在创建 PR 时附上录制文件。我会报告该路径,然后停止;CLAUDE.md 中的延迟附加规则涵盖了 PR 创建后才生成的录制文件。

QA 测试结果报告(端点和 API QA)

当测试针对的是 API 或端点,而不只是点击路径时,我会构建测试矩阵,并在下方报告结构化结果,与第 4 步的浏览器报告一起提供,或以此替代浏览器报告。我会按类别、筛选条件、错误处理、分页和一致性对用例分组,然后逐一直接执行,并记录实际响应与预期响应的对照结果。若已发出请求但没有捕获到响应,该用例就判定为 FAIL,绝不会假定通过。

端点执行与身份验证。第 2 步和第 3 步只通过浏览器进行身份验证和操作,因此仅测试端点的运行需要独立的执行器和经过身份验证的上下文。

运行任何端点用例之前,我都会记录会话来源,即第 2 步进行身份验证时使用的协议、主机和端口。每个目标都会与该值核对,而“测试环境”会将其报告为“会话来源”,而不是定义它。我会计算这三项,而不是从 URL 中读取。我只接受 http 和 https 目标,并在任何审批或发送请求之前拒绝其他所有协议,包括 file、ftp 和 gopher;无论用例是否携带凭据,都一律如此,这样运行器就不会在未经我同意的情况下读取本地文件或建立非 HTTP 连接。我会拒绝 authority 中包含用户信息、百分号转义或反斜杠的任何 URL,然后将协议和主机转换为小写,将主机转换为 ASCII Punycode,去掉一个尾随点,并填入默认端口:HTTPS 为 443,HTTP 为 80。其他任何来源都需要单独审批,包括与浏览器应用不在同一主机上的 API。提及或粘贴端点不等于审批。我会向用户展示规范化后的来源,并说明将发送哪些凭据,只按名称标出会话 Cookie 和防 CSRF 令牌,绝不显示其值;我会在同一轮中等待答复,并将获批的来源记录在“测试环境”中。若未获审批,该用例就会被标记为 BLOCKED,我不会发送任何请求,无论是否携带凭据;这样,拼写错误或粘贴的链接都无法获取有效会话或预置记录 ID。

在任一执行路径中,携带凭据的请求都必须使用 HTTPS,除非主机是环回字面量、127.0.0.0/8 内的地址、::1、::ffff:127.0.0.0/104,或裸名称 localhost。我会直接从 URL 中读取该字面量,绝不接受自行解析出的名称,因为 curl 和浏览器在连接前都会再次解析;因此,即使我的检查已通过,重绑定或混合的 A 与 AAAA 响应仍可能将请求导向公网地址。对于不属于这些字面量的纯 HTTP 主机,任一执行路径都不会携带凭据,因此相关用例会被标记为 BLOCKED,而不会在明文传输下进行测试。

我会通过以下两种方式之一获取该上下文,并且两种方式都会先运行这些检查:

  • 将第 2 步的会话导出到其中的 curl,包括其 Cookie 和 anti-CSRF 令牌。我从不传递 -L,无论是否携带凭据,因此每个请求都只会发往我检查过的源站。3xx 是此案例中观察到的结果:我记录状态码和 Location,根据预期响应对它们进行评分,绝不发起下一跳请求。我通过 -b jar.txt 使用限定主机的 Cookie jar 携带会话;当 jar 中 Cookie 的域不覆盖已批准的端点源站时,我会仅针对该源站设置显式的 Cookie 标头。只有端点不需要会话时,才仅需使用未经身份验证的普通 curl。
  • 通过驱动程序的 evaluate 钩子发起页面内请求。运行钩子的页面也必须通过源站检查,因为 fetch 会与当前打开页面的源站相同,而浏览器会自行附加会话 Cookie。同源 fetch 不会添加 anti-CSRF 标头,因此我会调用应用自身的请求辅助函数(即它已用于 API 调用的客户端,由其附加令牌),或者从 Cookie 或 meta 标签中读取 anti-CSRF 令牌,并将其设置在 RequestInit.headers 中。跨源请求还需要 credentials: "include" 和匹配的 CORS。fetch 会自行跟随重定向,并将 anti-CSRF 标头和 Cookie 带到下一跳,因此我会在每个 evaluate 钩子请求中设置 redirect: "error"。仅有拒绝并不能证明发生了重定向或请求已发出:我会记录观察到的错误,并利用可用的网络证据区分已证实未发出(BLOCKED)和已发出但没有响应(FAIL)。如果仍无法确定是否已发出,我会将其报告为 FAIL 并说明这一不确定性,绝不假定发生了重定向或测试通过,也不会改用 curl 重试,因为服务器可能已经处理了该请求。需要重定向状态码或 Location 的案例,从一开始就通过 curl 流程执行。

我绝不接受未经身份验证的响应作为案例结果;如果无法获取已验证身份的上下文,我会将这些案例记录为 BLOCKED,而不是测试错误的对象。会修改共享数据的端点案例,在发出请求前也会执行与第 3 步相同的变更预检。如果没有操作 UI,则截图和录制不适用,因此每个案例都以捕获的请求和响应作为证据。

我会一次性捕获环境,以确保运行可复现;每行案例都会记录完整的请求输入,包括路径、查询、请求体和所有非机密标头,而不只是查询参数。重放时会使用新配置的第 2 步会话进行身份验证,因此表格中不会携带该会话:写入任何请求或响应值之前,我都会删去凭据、会话令牌、身份验证标头、Cookie 和个人数据,只保留案例所需的功能性证据、计数、ID、状态码和错误消息。我会在 Result 列中使用 PASS、FAIL 或 BLOCKED 文本,绝不使用勾选表情符号。

报告模板
## QA Test Results - <feature or endpoint>

### Test Environment
- Date: <YYYY-MM-DD>
- Session origin: <normalized origin Step 2 authenticated against>
- Approved endpoint origin: <normalized origin and the date approved, when it differs from the session origin>
- Backend: <url> (<database>)
- Test data: <seeded records and their IDs>
- Auth: <account, role, IDs>

### API Endpoint: `<METHOD /path>`

#### <Category> Tests

| # | Test | Request | Expected | Result |
|---|------|---------|----------|--------|
| 1 | <case> | `<path, query, body, safe headers; secrets redacted>` | <expected> | PASS/FAIL/BLOCKED: <actual observed, or the blocker> |

#### Error Handling Tests

| # | Test | Request | Expected | Result |
|---|------|---------|----------|--------|
| N | <bad input> | `<path, query, body, safe headers; secrets redacted>` | <status and message> | PASS/FAIL/BLOCKED: <observed status and message, or the blocker> |

### Browser UI Testing
- <what rendered, with screenshot paths under .qa/>
- <blockers hit, stated plainly, never hidden>

### Findings
- <what passed, what failed, and any behavior that is by design>

VERDICT: <ALL PASS | PARTIAL | FAIL | BLOCKED> (<passed>/<executed> cases, <blocked> blocked)

我会为每个类别保留一张表,并且只添加端点实际具有的类别。请求从未发出的案例为 BLOCKED,绝不标为 PASS 或 FAIL;上述未经身份验证响应规则所阻止的案例也是如此。请求的字节一旦离开客户端,就视为已发出,因此连接被拒绝或 DNS 查询失败都不算已发出。如果 fetch 被拒绝后仍无法确定请求是否已发出,我会将该案例计为已执行并标记为 FAIL,同时说明是否发出尚不确定;我绝不会声称请求已发出或重试。我会列出被阻止的案例及其阻止原因,不将其计入已执行数量;如果其他案例已执行,结论最高只能为 PARTIAL;如果没有案例执行,则为 BLOCKED。Browser UI Testing 部分会沿用上述浏览器流程中的截图和录制,因此混合运行会在同一处报告点击路径及其背后的端点。发现项会明确说明失败和按设计运行的行为;不加说明地省略内容,会让人误以为案例通过,而它并未通过。

评论

支持 Markdown