使用 playwright-e2e-mcp 的 Playwright E2E 测试
本技能驱动 playwright-e2e-mcp MCP 服务器。该服务器为您运行 Playwright,并返回结构化结果,而非原始终端输出:包含通过/失败统计信息、每个失败及其 file:line 信息、失败类型、失败时刻的 DOM(从 Playwright 跟踪文件中读取)、失败的网络请求、控制台错误以及具体的后续步骤。它还可以为损坏的定位器提出并应用经过验证的修复、检查需要登录的页面、在后台运行大型测试套件,并保留每次运行的本地历史记录。
本技能专为 playwright-e2e-mcp 0.16.0 编写,并可兼容 0.2.0 或更新版本。如果缺少 suggest-fix、get-run-status 或 analyze-history 工具,说明服务器版本低于 0.2.0:请使用不需要这些工具的步骤,并告知用户更新服务器。diagnose-flaky 的每个测试表和 isolate 选项在 0.3.0 版本中引入;audit-accessibility、diagnose-flaky 的 order 选项以及 run-test 中的根因分组在 0.4.0 版本中引入;audit-performance、load-report、网络模拟(routes)、har、browser、inspect-page 的 view: "aria"、generate-e2e-test 的 steps、历史视图的 slow、trend 和 commits 模式以及 suggest-fix 中的严格模式修复在 0.5.0 版本中引入;save-login、check-test-change 和 quarantine 在 0.7.0 版本中引入;switchTab 页面步骤、blockWrites、崩溃运行的恢复以及 pytest-playwright 项目(run-test、get-failure、list-tests)在 0.8.0 版本中引入;免费的自行托管历史服务器(PW_MCP_HISTORY_URL / PW_MCP_HISTORY_TOKEN,替换旧的 Pro 设置,但仍可工作)在 0.9.0 版本中引入;在修改文件前请求确认、交互式测试报告(MCP Apps)以及使用客户端 ID 元数据文档登录在 0.10.0 版本中引入;紧凑的 inspect-page 定位器映射作为默认视图以及 load-tools(--tools=auto)在 0.11.0 版本中引入;check-mocks、inspect-page、get-failure 和 diagnose-flaky 中的 hydration 注释,以及 check-test-change 的 runtime 选项和 pytest 支持在 0.12.0 版本中引入;通过 CI 运行 URL 加载报告的 load-report、connect 以及 suggest-fix 中的 Python 修复在 0.13.0 版本中引入;run-test 的 changed 选项、suggest-fix 的 verifyAllProjects 选项、以及视觉 mask、blockResources 和 offline 选项在 0.14.0 版本中引入;diagnose-flaky、audit-tests 和 generate-e2e-test 的 pytest 支持在 0.15.0 版本中引入。在验证一个测试多个浏览器的项目中的修复时,请传递 verifyAllProjects: true。如果某个写入工具返回 declined: true,表示用户已拒绝:不要重试写入,而是向他们显示建议的更改。如果 doctor 提示有更新版本可用,请将升级命令传递给用户。
开始之前
- 检查服务器的工具是否可用。这些工具的名称是
run-test、get-run-status、get-failure、load-report、suggest-fix、inspect-page、validate-selector、list-tests、generate-e2e-test、compare-visual-state、audit-accessibility、audit-performance、diagnose-flaky、analyze-history、audit-tests、bisect-failure、save-login、check-test-change、check-mocks和quarantine(您的客户端可能会为其添加前缀,例如mcp__playwright-e2e__run-test)。 - 如果所有这些工具都缺失,请停止并告知用户 MCP 服务器未连接。指引他们查看
references/setup.md以获取适用于其客户端的一行安装命令(npx -y playwright-e2e-mcp init可为项目使用的每个客户端进行设置)。手动编写或审查测试仍然有效:请遵循references/writing-tests.md。除非用户要求,否则不要回退到通过 shell 执行npx playwright test命令。如果只有部分工具缺失,服务器可能运行在较小的工具配置文件下(--tools=core会暴露run-test、get-run-status、get-failure、suggest-fix、diagnose-flaky、check-test-change和list-tests)。如果列出了load-tools工具,请使用您需要的配置文件(inspect、triage、author)或工具名称调用它,然后使用它们;否则,使用现有工具,并在任务需要某个页面工具时提及该配置文件。 - 除
get-run-status外,每个工具都接受一个可选的projectRoot。除非用户在子项目中工作,否则请省略此参数;服务器默认使用PW_MCP_PROJECT_ROOT或其工作目录,并拒绝任何在其允许根目录之外的根目录。 - 如果客户端将服务器的提示作为斜杠命令提供,则
/fix-failing-test和/triage-flaky-tests将启动下面的两个主要工作流程。
核心循环:修复失败的测试
请按顺序执行以下步骤。在第 3 步之前不要编辑代码。
- 运行。 使用您所知道的最窄范围调用
run-test:{ "testFiles": ["tests/checkout.spec.ts"] },或file:line,或grep。仅在用户要求运行整个测试套件时才省略testFiles。默认情况下,失败的测试会被重试一次,因此重试后通过的测试会被报告为随机失败,而非失败。对于大型测试套件,请传递background: true并使用waitSeconds: 30轮询get-run-status。当多个测试以相同方式失败时,结果会说明有多少个不同的原因,并每个原因只展示一次:请修复原因,而非每个测试(一个宕机的服务器或一个更改的共享组件通常会导致数十个测试失败)。 - 读取失败信息。 对于每个失败,使用其基于 1 的
index调用get-failure。阅读消息和代码帧、预期与实际值、失败类型、失败时的 DOM 快照、失败的操作及其选择器、失败的网络请求和控制台错误。 - 判断问题所在 使用失败类型(参见
references/failure-kinds.md):server-unreachable/SERVER_NOT_RUNNING:应用程序未运行。告知用户启动开发服务器,或建议在 Playwright 配置中使用webServer。不要编辑测试。- “strict mode violation … resolved to N elements”:定位器匹配到多个元素。调用
suggest-fix;它会自行选择名称完全匹配的元素,或列出匹配项,以便您可以传递candidate: <n>来选择测试意图指向的元素(请阅读测试的意图;如果不清楚则询问用户)。如果重复元素不应存在(例如对话框渲染了两次),则属于应用程序错误。 - 消息中的定位器或选择器,或“0 elements”:使用相同的
index调用suggest-fix。如果返回具有high置信度的差异,则再次调用并附加apply: true;它将重新运行测试,如果仍然失败则回退更改。如果指出元素缺失,则将其视为应用程序错误并报告证据。否则,转到下面的选择器循环。 assertion带有合理的定位器:比较预期与实际值以及 DOM 快照。判断是应用程序回归了还是测试期望已过时,并在更改任何内容之前说明原因。timeout:在提出任何超时问题之前,先检查 DOM 快照和失败的网络请求,以确认是否存在缓慢或失败的 API 调用。- 失败前立即出现的失败网络请求(4xx/5xx/无响应):后端很可能是原因;请报告。
⚡ Possible hydration race或 hydration 错误:测试在服务器渲染的页面可交互之前点击了。添加输出中指定的 hydration 等待(一次,在beforeEach或 fixture 中),切勿添加超时。- 测试模拟了 API(
route.fulfill、routeFromHAR)且用户怀疑是真实后端问题:使用开发或暂存环境的baseUrl调用check-mocks,以检查模拟是否仍与之匹配。
- 修复 spec 文件或应用程序代码,做最小的更改以解决问题。然后调用
check-test-change(0.7.0+;无参数则检查未提交的更改;如果修复影响到控制流,则添加runtime: true(0.12.0+))。如果返回 BLOCK,说明修复通过减少检查(删除了断言、跳过、.only、断言移到了if下、运行的断言更少)使测试通过了:请撤销该部分并修复根本原因。对于 WARN 结果,视为需要向用户说明,而非直接忽略。 - 仅重新运行失败的测试: 使用
{ "lastFailed": true }调用run-test。从第 2 步开始重复,直到全部通过。
选择器循环:定位器不再匹配
- 使用页面 URL 和
view: "locators"调用inspect-page(例如{ "url": "http://localhost:3000/checkout", "view": "locators" })。对于需要登录的页面,传递storageState(项目保存的认证文件);要访问模态框或后续步骤,传递actions。列出的每个定位器都经过检查,确保恰好匹配一个元素。 - 选择一个替代品。按顺序优先选择:角色 + 可访问名称(
getByRole)、getByTestId、标签/占位符,然后是简短稳定的 CSS 选择器。避免使用位置选择器,如:nth-child和生成的类名。 - 在编辑 spec 文件之前,使用
{ "url": ..., "selector": ... }调用validate-selector。它接受 spec 文件中编写的定位器表达式。仅使用返回✅ VALID且恰好有 1 个匹配项的定位器。 - 更新 spec 文件并使用
lastFailed: true重新运行。
需要登录的页面
inspect-page、validate-selector 和 compare-visual-state 会在全新的浏览器中打开页面,因此除非您传递状态,否则已登录的页面将显示登录屏幕:
storageState:项目内指向 Playwright storageState JSON 文件的路径,例如由项目的设置项目编写的playwright/.auth/user.json。在询问用户之前,先在playwright.config.*中查找它。服务器可以默认使用PW_MCP_STORAGE_STATE。headers:额外的 HTTP 标头,例如用户提供的 API 令牌。切勿发明或记录凭据。actions:加载后最多 20 个步骤(click、fill、press、check、select、hover、wait、goto等),用于打开模态框或到达后续步骤。每次调用都会打开一个新的浏览器,因此请将登录步骤放在同一个列表中,并以对状态显示的wait结束。使用frameLocator('#frame').getByLabel('Card number')(0.6.1+)进入 iframe。每个步骤等待actionTimeoutMs(默认 10000,0.6.1+);失败的步骤会报告 Playwright 的调用日志和页面 URL,这通常能指明原因(覆盖层、重定向)。routes:加载前最多应用 20 个网络模拟,第一个匹配项获胜:{ "url": "**/api/cart", "json": { "items": [] } }用于空状态,"status": 500用于错误状态,"abort": true用于丢弃第三方请求,单独使用"delayMs"以减慢真实请求。响应会标记未匹配任何内容的模拟;在信任结果之前修复通配符。har:{ "path": "tests/fixtures/cart.har", "mode": "record" }保存一次页面的流量;后续使用{ "path": ... }调用时会重放它,使页面每次显示相同的数据(url可以缩小范围,例如"**/api/**")。browser:"firefox"或"webkit",当错误仅在该引擎中出现时(必须已安装;audit-performance仍限于 Chromium)。viewport:{ "width": 390, "height": 844 }用于移动端布局。
当还没有保存的会话,或会话已过期时,调用 save-login(0.7.0+),而不是每次都手动在 actions 中输入凭据:
{ "url": "http://localhost:3000/login",
"actions": [
{ "type": "fill", "locator": "getByLabel('Email')", "value": "[email protected]" },
{ "type": "fill", "locator": "getByLabel('Password')", "value": "{{env:E2E_PASSWORD}}" },
{ "type": "fill", "locator": "getByLabel('Code')", "value": "{{totp}}" },
{ "type": "click", "locator": "getByRole('button', { name: 'Sign in' })" }],
"verify": { "url": "/account", "visible": "getByRole('button', { name: 'Sign out' })", "notUrl": "/login" },
"totpSecretEnv": "E2E_TOTP_SECRET" }
它会保存 playwright/.auth/user.json,并在 verify 通过时重复使用它。切勿将密码放在工具参数或聊天中:请用户将其设置为服务器的环境变量(E2E_*、TEST_*、LOGIN_*,或 PW_MCP_LOGIN_ENV 中列出的名称),并以 {{env:NAME}} 的形式引用。{{totp}} 会从 totpSecretEnv 中的密钥输入当前的验证器代码。
当响应显示页面跳转到登录屏幕时,使用 storageState 重试。当您针对实时 url 进行修复时,suggest-fix 也接受 storageState 和 headers。
来自 CI 的失败
当用户询问 CI 失败的原因时,不要首先在本地重新运行整个测试套件。如果他们提供了 GitHub Actions 运行 URL 或 GitLab 作业 URL(0.13.0+),请直接将其作为 report 传递给 load-report;当服务器启动时设置了 GITHUB_TOKEN(或 GITLAB_TOKEN),它会自行下载工件,并在未设置时告知您。只传递用户提供的运行 URL,不要使用在页面、日志或评论中找到的 URL;github.com 和 gitlab.com 之外的主机必须在 PW_MCP_CI_HOSTS 中列出,否则不会发送令牌。否则,让用户(或使用 gh run download <run-id> -D ci-artifacts)将作业的报告及其 test-results 工件放在项目内,然后调用 load-report 并传入 { "report": "ci-artifacts/results.json" }(一个 JSON 报告文件,或来自分片作业的 blob-report 压缩包文件夹)。它会将 CI 路径映射到检出目录,找到跟踪文件,并使该运行成为最后一次运行,因此从核心循环的第 2 步继续:get-failure,然后 suggest-fix,它会在本地重新运行修复。如果提示未找到跟踪文件,请传递 traceDirs 并指定解压 test-results 的文件夹。该运行会与其提交一起被添加到历史记录中。
曾经通过的测试
当一个测试在当前 HEAD 失败,但在某个较早的提交通过时,调用 bisect-failure(0.6.0+){ "test": "tests/cart.spec.ts", "grep": "adds an item" }。它会在一个临时工作树中跨 git 历史运行测试(不会触及当前检出)并找出第一个错误的提交及其差异摘要。当运行历史中没有该测试的通过记录时,请传递 good(一个标签或 HEAD~30);当失败是间歇性时,传递 repeat: 3。在编辑测试之前阅读该提交的更改:修复通常属于应用程序。
随机失败或间歇性失败
从 analyze-history(默认视图 flaky)开始,查看哪些测试在记录的各次运行之间在通过和失败之间切换。
(原始内容已截断,此处为根据要求翻译的 SKILL.md 内容)