Playwright 测试覆盖自动生成:解读 playwright-test-coverage 三阶段多 Agent 提示词流水线
导读
Playwright 不仅在运行时提供跨浏览器自动化能力,还在其 Agent(编码助手代理)体系中内置了一套"需求 → 测试计划 → 测试代码 → 自动修复"的完整闭环。本文以 packages/playwright/src/agents/playwright-test-coverage.prompt.md 这份编排型提示词模板为骨架,结合该目录下的三个子代理定义(planner / generator / healer)、generateAgents.ts 的装载机制与 tests/、examples/todomvc 中真实生成的测试计划与测试文件,深入讲解这套流水线的参数约定、XML 调用契约与底层实现。读完本文,你将理解如何驱动 Agent 为任意 Web 应用批量产出可执行的 Playwright 端到端测试,以及各子代理的角色边界、串行执行规则与可复现的 Seed 机制。
一、模板定位:一份用于"产出测试覆盖"的编排提示词
playwright-test-coverage.prompt.md 位于源码目录 packages/playwright/src/agents 下,其 YAML front matter 定义了它被编码助手加载后的元信息:
---
agent: ${defaultAgentName}
description: Produce test coverage
---
其中 agent 字段指向当前 Agent(主代理)的名字,而 description("Produce test coverage",即"产出测试覆盖")决定了该提示词何时被匹配触发——当用户要求"给某某功能补测试"时,编码助手会优先检索到它。
这个文件本身不做浏览器操作,也不直接写测试,而是扮演编排者角色:它只定义了一个三步走的调用协议,把任务层层分解给三个专职子代理:
- 先调用 #playwright-test-planner(测试规划者)产出测试计划文件;
- 再按测试计划逐条调用 #playwright-test-generator(测试生成者)生成测试代码;
- 最后调用 #playwright-test-healer(测试修复者)跑通并修复失败的测试。
值得注意的是,agent 字段与 Seed 文件路径都是 ${...} 形式的占位符,而非硬编码值。这是因为该类提示词模板会由 generateAgents.ts 中的 loadPrompt() 按正则将 \${key} 替换为真实取值(如 defaultAgentName、相对路径后的 seed 文件),并分别以不同格式派发到 Claude、GitHub Copilot、Codex、OpenCode 与 VS Code 的工程目录中。例如示例工程 examples/todomvc/.github/prompts/playwright-test-coverage.prompt.md 就是一份面向 GitHub Copilot(默认 agent 名替换为 agent)的落地副本,其中 ${seedFile} 已被替换为 tests/seed.spec.ts。
二、模板参数:Task、Seed file、Test plan file
模板开头的 Parameters 段定义了三个入参,说明如下:
| 参数 | 必填 | 说明 | 默认值/取值示例 |
|---|---|---|---|
| Task | 是 | 需要被测试覆盖的目标任务描述(如"为购物车功能补测试") | 用户自然语言 |
| Seed file | 否 | 供 Agent 理解"如何把被测页面带到可录制状态"的种子测试文件路径 | 默认 ${seedFile},落地后常为 tests/seed.spec.ts |
| Test plan file | 否 | 测试计划文件要写入的位置,必须位于项目 specs/ 目录下 |
specs/coverage.plan.md |
Seed file:让每次生成"站在同一起点"
Seed 文件是本流水线可复现性的基石。由 packages/playwright/src/mcp/test/seed.ts 的实现可以看出它的完整语义:
seedProject()(seed.ts):解析playwright.config,默认取顶层第一个项目,或按projectName查找指定项目;findSeedFile()(seed.ts):收集该项目testDir内的全部测试文件,返回文件名含seed的那个;defaultSeedFile()(seed.ts):当找不到时,默认路径即{testDir}/seed.spec.ts;- 若无 seed 文件,
ensureSeedFile()还会写入一份默认骨架("Test group / seed"空用例,注释写着// generate code here.)。
之所以强调 seed,是因为 planner/generator 在录制真实用户操作前,需要通过 seed 中的内容知道被测应用如何启动、页面如何预置。examples/todomvc/tests/seed.spec.ts 中的注释把这一角色说得很直白:
import { test, expect } from './fixtures';
test('seed', async ({ page }) => {
// This test tells agents how to start recording the test
// so that the page was already configured.
});
即:seed 用例不真正断言业务逻辑,而是充当"Agent 录制起点的操作说明",确保被测页面已就绪、后续生成脚本时复用同一入口配置。
specs/ 目录:测试计划的固定落点
initRepo()(generateAgents.ts)在初始化代理工程时会自动创建 specs/ 目录并写入 specs/README.md(标注"This is a directory for test plans")。规划子代理的独立提示词 playwright-test-plan.prompt.md 也默认把计划输出到 specs/coverage.plan.md。因此整条链路对"计划放哪、测试放哪、seed 放哪"有全局一致的目录约定。
三、阶段一:规划者(playwright-test-planner)产出测试计划
模板规定第一步用如下结构化负载调用规划子代理:
<plan>
<task-text><!-- the task --></task-text>
<seed-file><!-- path to seed file --></seed-file>
<plan-file><!-- path to test plan file to generate --></plan-file>
</plan>
三个 XML 子节点分别对应上面三个参数:任务描述、seed 文件路径、待生成的计划文件路径。
规划者的工作方式
子代理本体定义在 playwright-test-planner.agent.md(front matter 中 color: green、model: sonnet)。它被声明为"专业的 Web 测试规划专家",职责包括:
- 探索被测界面:先调用一次
planner_setup_page初始化页面,再使用一批playwright-test/browser_*MCP 工具(browser_navigate、browser_snapshot、browser_type、browser_click、browser_network_requests等)遍历应用,识别全部可交互元素、表单、导航路径与功能点;仅在必要时才截图; - 分析用户流:梳理主用户旅程与关键路径,考虑不同用户类型的典型行为;
- 设计场景:覆盖 happy path(正常路径)、边界条件、错误处理与输入校验等负面场景;
- 结构化输出:每个场景包含清晰标题、分步指令、预期结果、起始状态假设(始终按空白/全新状态起步)、成功与失败判据;
- 落盘:通过
planner_save_plan工具把计划保存为 Markdown,并保证各场景相互独立、可任意顺序执行。
计划文件的编号约定
计划文件不只是给人看的文档,它的层级编号就是生成阶段的迭代索引。以 examples/todomvc/specs/basic-operations.plan.md 为例,其结构为:
### 1. Adding Todos这样的二级编号代表"测试规格分组(test-suite)";#### 1.1. should-add-single-todo代表分组下的具体用例(对应模板中的1.1, 1.2, ...序列);- 每个用例块内声明
**Seed:** tests/seed.spec.ts、**File:** tests/adding-todos/should-add-single-todo.spec.ts(生成文件的落盘路径)以及带- expect:断言语义的逐步指令。
### 1. Adding Todos
**Seed:** `tests/seed.spec.ts`
#### 1.1. should-add-single-todo
**File:** `tests/adding-todos/should-add-single-todo.spec.ts`
**Steps:**
1. Navigate to the TodoMVC application
- expect: The application loads successfully
- expect: The input field 'What needs to be done?' is visible
2. Type 'Buy groceries' into the input field
- expect: The text appears in the input field
...
这个编号体系会被覆盖率模板第二阶段逐条消费:1.1、1.2……直至计划中全部用例被处理完毕。
四、阶段二:生成者(playwright-test-generator)逐条生成测试代码
模板规定第二阶段逐条、串行(one after another, not in parallel)地为计划中每个用例调用生成者,负载格式如下:
<generate>
<test-suite><!-- Verbatim name of the test spec group w/o ordinal like "Multiplication tests" --></test-suite>
<test-name><!-- Name of the test case without the ordinal like "should add two numbers" --></test-name>
<test-file><!-- Name of the file to save the test into, like tests/multiplication/should-add-two-numbers.spec.ts --></test-file>
<seed-file><!-- Seed file path from test plan --></seed-file>
<body><!-- Test case content including steps and expectations --></body>
</generate>
字段语义(全部来自模板原文,需照搬给子代理,以保证约定一致):
| 字段 | 含义 | 示例 |
|---|---|---|
test-suite |
规格分组名,必须去掉序号后原样保留 | Adding Todos(而非 1. Adding Todos) |
test-name |
用例名,去掉 1.1. 这类序号 |
should-add-single-todo |
test-file |
测试保存到的文件路径 | tests/adding-todos/should-add-single-todo.spec.ts |
seed-file |
从测试计划中带出的 seed 文件路径 | tests/seed.spec.ts |
body |
用例内容,含操作步骤与预期 | 计划中 1.1 的 Steps + expect 全文 |
生成者的代码规范
playwright-test-generator.agent.md(color: blue)详细约束了生成行为:
- 先读取测试计划拿到步骤与验证规格;对每个场景先调用
generator_setup_page完成页面预置; - 每个步骤都先由 Agent 实时手动执行一遍(用步骤描述作为每次 Playwright MCP 调用的意图),再通过
generator_read_log读取真实操作日志,最后调用generator_write_test依据日志落盘代码——即"先真机演示、后按录得日志生成",杜绝凭空臆造选择器; - 文件规范:一个文件只放单个测试;文件名须为文件系统友好的场景名;测试须包在"与计划顶层分组同名(去掉序号)"的
test.describe中;用例标题须与场景名一致;每个步骤执行前插入一条带步骤原文的注释,一个步骤需多个动作时不重复注释;尽量复用 log 中的最佳实践。
agent 定义里给出的映射示例直观展示了从计划到代码的转化:
// spec: specs/plan.md
// seed: tests/seed.spec.ts
test.describe('Adding New Todos', () => {
test('Add Valid Todo', async ({ page }) => {
// 1. Click in the "What needs to be done?" input field
await page.click(...);
...
});
});
仓库中真实生成的 examples/todomvc/tests/adding-todos/should-add-single-todo.spec.ts 完全符合上述规范——首行以注释记录 seed 引用,describe('Adding Todos') 与计划分组一一对应,每个操作步骤前都有 // Step N: … 与 // Expect: … 注释,断言均使用 expect(...).toBeVisible() 等自动等待式断言:
// seed: tests/seed.spec.ts
import { test, expect } from '../fixtures';
test.describe('Adding Todos', () => {
test('should add single todo', async ({ page }) => {
// Step 1: Navigate to the TodoMVC application
// Expect: The application loads successfully, The input field 'What needs to be done?' is visible
await expect(page.getByRole('textbox', { name: 'What needs to be done?' })).toBeVisible();
// Step 2: Type 'Buy groceries' into the input field
await page.getByRole('textbox', { name: 'What needs to be done?' }).fill('Buy groceries');
// Expect: The text appears in the input field
await expect(page.getByRole('textbox', { name: 'What needs to be done?' })).toHaveValue('Buy groceries');
// Step 3: Press Enter to submit the todo
await page.keyboard.press('Enter');
// Expect: The new todo 'Buy groceries' appears in the todo list
await expect(page.getByText('Buy groceries')).toBeVisible();
...
});
});
为什么必须"串行、不许并行"?
模板在第二阶段特意强调逐条串行执行。这与生成者"边用浏览器真跑、边记日志"的工作方式强相关:多个生成任务并发共享同一浏览器上下文/测试产物目录时,页面状态、日志读取与文件写入会互相污染。串行保证了每个用例都能以干净的 seed 状态起步、读到属于自己的操作日志。
五、阶段三:修复者(playwright-test-healer)跑通全部测试
第二阶段把所有用例文件写完后,模板要求以一段极简指令启动收尾:
<heal>Run all tests and fix the failing ones one after another.</heal>
即"运行全部测试,逐个修复失败项"。注意此处括号中的触发提示词模板是 playwright-test-heal.prompt.md,而真正的行为约束在 playwright-test-healer.agent.md(color: red,是三个子代理中唯一同时持有 edit 与 test_* 工具的"动手者")。
修复者的方法论是典型的"红-绿-重构"循环:
- 全量初跑:用
test_run运行所有测试,识别失败项; - 逐个调试:对每个失败用例执行
test_debug; - 现场取证:暂停在报错处,结合
browser_snapshot、browser_console_messages、browser_network_requests等工具检查页面快照、控制台与网络,分析选择器、时序或断言问题; - 根因分析:区分"选择器已随应用变更"“同步/时序问题”“数据依赖或环境问题”与"应用行为变化破坏了测试假设";
- 代码修复:通过
edit能力更新选择器、修正断言与期望值、提升可靠性;对天然动态的数据用正则构造健壮定位器; - 改后必验:每次修复后重启该测试验证,迭代直到干净通过;
- 兜底策略:若反复失败且高度确信测试本身正确,则将该用例标记为
test.fixme()跳过执行,并在失败步骤前加注释说明"实际行为与预期不符之处"。
同时它还被明令:不得向用户提问(非交互式,以通过测试为最合理行动)、永远不等待 networkidle、不使用被废弃或劝阻的 API。这说明修复者被刻意设计为"可无人值守"的最后关卡——三阶段闭环的稳定性正依赖它兜住前两阶段产物与真实应用之间的偏差。
六、底层机制:从 .agent.md 到各编码助手的装载链路
理解这份编排模板,还需要知道它背后的"运行时":
- Agent 规格即 Markdown 文件:同目录下的
*.agent.md(planner/generator/healer 三个)以 YAML front matter 声明name、description、model、color与tools白名单,正文为系统指令。任务分派方在提示词中以#playwright-test-planner这种#agent名语法引用子代理; - 多工具链适配:编写一份 agent 规格后,generateAgents.ts 中的
ClaudeGenerator、CodexGenerator、OpencodeGenerator、CopilotGenerator、VSCodeGenerator会把它翻译成对应平台格式(Claude 的.claude/agents/*.md、Codex 的 snake_case TOML、GitHub Copilot 的.github/agents/*.agent.md与 chatmode 等),并把search/edit这类短工具名映射为各平台的真实工具(如 Grep/Read/Edit/Write),把playwright-test/browser_click映射为mcp__playwright-test__browser_click或enabled_tools项; - MCP 服务器是能力底座:上述
browser_*、test_run、generator_write_test等工具统一由npx playwright run-test-mcp-server提供的playwright-testMCP 服务器暴露(Windows 下为cmd /c npx ...),生成器会自动向工程写入.mcp.json/.vscode/mcp.json等连接配置; - 一次性工程初始化:无论哪种生成器,
initRepo()都会在用户工程中补齐specs/目录与 seed 文件,确保三个子代理执行时所需的一切前提都已就绪。
七、端到端观察:examples/todomvc 的流水线产物
examples/todomvc 是本模板最完整的真实使用样例,四份配套提示词也原样发布在其 examples/todomvc/.github/prompts 下。对照流水线三个阶段,可以看到各阶段产物的对应关系:
| 阶段 | 产物 | 仓库位置 |
|---|---|---|
| 规划(planner) | 覆盖 7 大功能域(增/完成/编辑/删除/过滤/持久化/UI 状态)的计划文档 | examples/todomvc/specs/basic-operations.plan.md |
| 生成(generator) | 按"计划分组 → describe、用例 → test、分组 → 目录"组织的测试代码 | examples/todomvc/tests/adding-todos/should-add-single-todo.spec.ts |
| 起点(seed) | 告知 Agent 页面如何预置的种子用例 | examples/todomvc/tests/seed.spec.ts |
从计划文本到测试代码,字段映射是机械且可校验的:计划的 ### 1. Adding Todos 被去掉序号后成为 describe('Adding Todos', ...);#### 1.1. should-add-single-todo 成为 test('should add single todo', ...);**File:** 声明控制落盘路径;Steps 里每条带 - expect: 的子项最终编译为相应的 await expect(...) 断言。这种"计划即契约"的设计使得计划文档可以独立评审、测试可以独立追溯,也让 LLM 生成过程几乎不存在二义性。
八、把该模式迁移到自己的工程中
在真实仓库中启用这套能力的关键步骤与注意事项如下:
- 初始化:在安装了本仓库 Playwright 的工程里运行
npx playwright对应的代理初始化命令(如npx playwright codegen相关 MCP 或生成器脚本),让generateAgents.ts把specs/、seed 文件与 MCP 配置落到你的工程;工具链会在.github/prompts等位置生成本节讨论的playwright-test-coverage.prompt.md落地副本,占位符已被替换为真实默认值; - 提需求:以自然语言描述 Task,例如"为 todo 列表的添加功能产出测试覆盖",编码助手会匹配到
description: Produce test coverage的模板并启动三阶段流水线; - 提供或补建 seed:优先在
testDir下提供含seed命名、可把页面带到录制起点的用例,找不到时系统会写入默认骨架; - 审阅计划:生成的
specs/*.plan.md建议像测试代码一样纳入版本管理与人审,因为它是可执行规格; - 了解失败兜底:healer 无法修复且确认测试无误时会以
test.fixme()跳过并注释原因——不要把 fixme 当成失败,而要当成"应用行为与预期不符"的待办信号。
需要说明的是:编码助手与 MCP 服务器在仓库中面向的是一般性使用场景,不同版本对各编码助手平台的适配细节(如默认 agent 名称、文件目录命名)存在差异,本文所述以当前仓库源码与示例工程为准。
延伸阅读
- 编排模板本体:packages/playwright/src/agents/playwright-test-coverage.prompt.md
- 三个子代理规格与触发提示词:playwright-test-planner.agent.md、playwright-test-generator.agent.md、playwright-test-healer.agent.md,以及 playwright-test-plan.prompt.md、playwright-test-generate.prompt.md、playwright-test-heal.prompt.md
- 装载与适配实现:packages/playwright/src/agents/generateAgents.ts
- Seed 机制实现:packages/playwright/src/mcp/test/seed.ts
- 端到端落地样例:examples/todomvc/specs/basic-operations.plan.md、examples/todomvc/tests/adding-todos/should-add-single-todo.spec.ts、examples/todomvc/tests/seed.spec.ts、examples/todomvc/playwright.config.ts
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00