Playwright 测试规划 Agent 解析:从 Agent 定义到 MCP 测试规划工具的完整工作流
Playwright 仓库在 examples/todomvc 示例中内置了一个名为 playwright-test-planner 的测试规划 Agent,它由 Claude Code 加载、通过 Playwright Test MCP 服务器驱动浏览器,自动探索 Web 应用界面并产出结构化的测试计划文档。本文以该 Agent 定义文件为核心,逐段拆解其工具清单、五步规划流程与质量标准,并结合 MCP 规划工具源码、seed 解析逻辑 与 官方测试用例 说明每个工具背后的真实实现,帮助读者完整复现“Agent 探索页面 → 设计场景 → 落盘 Markdown 测试计划”的自动化测试规划链路。
Agent 定义文件结构与 Frontmatter
playwright-test-planner.md 是一个标准的 Claude Code subagent 定义文件,采用 YAML frontmatter + Markdown 正文的形态。frontmatter 声明了 Agent 的元信息:
| 字段 | 取值 | 作用 |
|---|---|---|
name |
playwright-test-planner |
Agent 唯一标识,主 Agent 据此调用 |
description |
“Use this agent when you need to create comprehensive test plan for a web application or website” | 描述触发时机,供主 Agent 判断何时委派 |
tools |
Glob, Grep, Read, LS 及一组 mcp__playwright-test__* 工具 |
限定该 Agent 可用的工具白名单 |
model |
sonnet |
指定底层模型 |
color |
green |
终端中的展示颜色 |
工具白名单分为三类,这个划分本身就揭示了规划者(Planner)的职责边界:
- 只读文件工具:
Glob、Grep、Read、LS,用于了解代码结构与已有测试; - 浏览器探索工具:
browser_click、browser_navigate、browser_navigate_back、browser_type、browser_press_key、browser_hover、browser_drag、browser_select_option、browser_file_upload、browser_handle_dialog、browser_snapshot、browser_take_screenshot、browser_evaluate、browser_network_requests、browser_console_messages、browser_wait_for、browser_close、browser_run_code_unsafe,全部来自playwright-test这个 MCP 服务器(前缀mcp__playwright-test__); - 规划专用工具:
planner_setup_page(搭建规划页面)与planner_save_plan(保存测试计划),是 Planner 工作流的两个锚点。
值得注意的是,工具列表中刻意不包含代码生成类工具(如 generator_save_test)——规划者只负责“想清楚测什么”,把“写成代码”交给后续的生成者 Agent 处理。同一目录下还配套了 playwright-test-generator.md(把计划转成测试代码)与 playwright-test-healer.md(修复失败测试)两个 Agent,三者构成规划 → 生成 → 修复的流水线;本文聚焦其中的规划环节。
工作流第一步:Navigate and Explore(导航与探索)
Agent 正文第一部分规定了探索纪律:
- 必须先调用一次
planner_setup_page,在任何其他浏览器工具之前完成页面初始化; - 通过浏览器快照(snapshot)而非截图来理解界面,“Do not take screenshots unless absolutely necessary”——快照是带元素引用(ref)的结构化文本,比像素更适合 LLM 消费;
- 使用
browser_*工具充分遍历界面,识别所有可交互元素、表单、导航路径与功能点。
planner_setup_page 的底层实现在 plannerTools.ts 中:它接受两个可选参数——
inputSchema: z.object({
project: z.string().optional().describe('Project to use for setup. For example: "chromium", if no project is provided uses the first project in the config.'),
seedFile: z.string().optional().describe('A seed file contains a single test that is used to setup the page for testing, for example: "tests/seed.spec.ts". If no seed file is provided, a default seed file is created.'),
}),
其处理逻辑是 context.getOrCreateSeedFile(...) 后 runSeedTest(...),只有运行状态为 'paused' 才视为成功。也就是说,这个工具并不是简单打开一个 URL,而是运行一个 seed 测试并让它暂停在“可交互”状态:测试执行到一半停住,把页面 URL、标题、aria 快照(### Paused at end of test. ready for interaction + Page Snapshot)回传给 Agent,之后 Agent 的每次 browser_* 操作都发生在这个暂停中的测试上下文里。
seed 文件的解析规则在 seed.ts 中,有三条关键行为:
- 项目选择(seed.ts#L26-L33):未指定
project时,取配置中的顶层项目(无依赖链上的dependencies的上游项目);指定了项目名则精确查找,找不到直接抛Project xxx not found。 - seed 文件查找(seed.ts#L35-L38):在项目收集到的测试文件中,找文件名包含
seed子串的文件(如tests/seed.spec.ts); - 默认 seed 兜底(seed.ts#L40-L53):找不到时自动在
testDir下创建seed.spec.ts,内容是一个带test('seed', ...)的空壳模板(seed.ts#L55-L62),等待后续生成器往里填充导航与登录代码。
第二、三步:分析用户流与设计场景
Agent 定义中的中间两步规定了思考框架:
- Analyze User Flows:映射主要用户旅程,识别应用中的关键路径,并考虑不同用户类型及其典型行为;
- Design Comprehensive Scenarios:产出的测试场景必须覆盖三类——
- Happy path scenarios(正常用户行为);
- Edge cases and boundary conditions(边界情况与边界条件);
- Error handling and validation(错误处理与校验)。
例如在 TodoMVC 这个被规划对象上,对应的覆盖点就是:单条/多条待办的增删改完成、空白输入与首尾空格的边界、全部完成后的“Clear completed”出现、按 Active/Completed 过滤等。仓库里保存的一份真实产出 basic-operations.plan.md 正是按这个框架生成的:应用概览一段,场景按“Adding Todos / Completing Todos / ...”分组,每组内既有 should-add-single-todo 这类 happy path,也有 should-trim-whitespace-from-new-todo、should-not-add-empty-todo 这类边界与负向场景。
第四步:Structured Test Plans(结构化计划的要求)
Agent 对每个场景给出了硬性格式要求,这也是规划文档与随意笔记的分界线:
- Clear, descriptive title(清晰、描述性的标题);
- Detailed step-by-step instructions(详细分步说明);
- Expected outcomes where appropriate(适当标注期望结果);
- Assumptions about starting state — always assume blank/fresh state(起始状态一律假设为空白/全新,这保证场景间无隐式依赖);
- Success criteria and failure conditions(成功标准与失败条件)。
第五步:planner_save_plan 落盘与计划的 Schema
规划完成后,Agent 被要求必须通过 planner_save_plan 工具提交计划,而不是把 Markdown 直接写在对话里。该工具的实现(plannerTools.ts#L79-L134)揭示了计划数据的完整 Schema,其输入由 planSchema 定义:
const planSchema = z.object({
overview: z.string(), // 被测应用的简要概述
suites: z.array(z.object({
name: z.string(), // 套件名称(如 "Adding Todos")
seedFile: z.string(), // 用于搭建页面的 seed 文件
tests: z.array(z.object({
name: z.string(), // 测试名(如 "should-add-single-todo")
file: z.string(), // 测试将落盘的目标文件,如 "tests/<suite>/<name>.spec.ts"
steps: z.array(z.object({
perform: z.string().optional(), // 执行动作,如 'Click on the "Submit" button'
expect: z.string().array(), // 该动作的期望结果列表
})),
})),
})),
});
planner_save_plan 在此 Schema 上扩展 name(计划名)与 fileName(保存路径,相对 workspace 根目录)两个字段,然后由工具端按固定模板渲染成 Markdown:# 计划名 → ## Application Overview → ## Test Scenarios → ### n. 套件名(附 **Seed:**)→ #### n.m. 测试名(附 **File:**)→ **Steps:** 下的编号步骤与 expect: 子项。对照 basic-operations.plan.md 可以逐行验证:其章节标题、**Seed:** tests/seed.spec.ts、**File:** tests/adding-todos/should-add-single-todo.spec.ts 与两级编号完全吻合模板输出。
两个值得注意的实现细节:
- 路径安全:
fileName经resolveWithinRoot(context.rootPath, ...)解析,plannerTools.ts#L122-L126 明确拒绝落在 workspace 之外的路径,写入前会mkdir -p式创建目录。示例中计划保存在 specs/ 目录,即 prompt 中传入的specs/basic-operations.plan.md; - file 字段的前瞻性:每个测试都预先指定了未来的落盘文件路径(
tests/<suite-name>/<test-name>.spec.ts),这使得后续生成者 Agent 能“照单抓药”地按套件建目录、逐条转写代码,规划与生成交付物之间形成了机器可读的契约。仓库 tests/ 下adding-todos、completing-todos、deleting-todos、editing-todos、filtering-todos、todo-creation六个子目录,正是这份计划逐套件落地的结果。
另外还有一个不落盘的兄弟工具 planner_submit_plan(返回计划 JSON,供调试与校验),两者共用同一 planSchema。
官方测试验证的行为边界
tests/mcp/planner.spec.ts 用 MCP 客户端直接调用这些工具,验证了若干容易被忽视的运行时语义:
- 暂停即就绪:seed 运行成功后响应包含
### Paused at end of test. ready for interaction,且紧随其后的browser_click会真实产出 Playwright 代码(如 planner.spec.ts#L56-L66 中点击 Submit 按钮生成await page.getByRole('button', { name: 'Submit' }).click();); - seed 相对路径解析:
seedFile既可相对testDir(seed.test.ts)也可相对配置目录(tests/seed.test.ts),多根工作区(monorepo)场景还支持相对 rootPath 的完整路径(planner.spec.ts#L69-L129); - 项目依赖链:带
dependencies的项目会先执行依赖项目的 setup 测试,再暂停在目标项目的 seed 上,且不会误暂停到无关项目(planner.spec.ts#L131-L169); - 错误可见:seed 加载报错会原样回传(
Error: loading error);指定了不存在的测试文件则返回Error: seed test not found.且标记isError: true(planner.spec.ts#L171-L198); - 默认行为:完全不带参数调用时,自动在顶层项目的
testDir下创建并使用默认seed.spec.ts(planner.spec.ts#L200-L254)。
这些语义解释了 Agent 定义中“先 planner_setup_page 再用其他工具”这条纪律的必要性:没有暂停中的 seed 上下文,所有 browser_* 工具都无处附着。
质量标准的工程含义
Agent 定义末尾给出了三条质量标准,结合源码可以理解其工程意图:
- Write steps that are specific enough for any tester to follow:
steps的 Schema 强制perform(单一动作)与expect(结果列表)分离,天然要求“一步一验”,避免“点击并完成提交”这类不可执行描述; - Include negative testing scenarios:对应场景设计中的 Error handling 要求,如
should-not-add-empty-todo; - Ensure scenarios are independent and can be run in any order:与“always assume blank/fresh state”呼应——因为每个测试将来会被生成器转成独立 spec 文件、由测试框架并行执行,计划阶段就必须杜绝跨场景状态依赖。
输出格式要求则规定:始终将完整计划保存为 Markdown 文件,带清晰标题、编号步骤与面向开发和 QA 团队的正式排版——这恰好就是 planner_save_plan 模板渲染出的形态。
完整复现路径:以 TodoMVC 示例为准
在仓库中复现该 Agent 的工作流,涉及以下已存在的文件与步骤:
-
配置 MCP 服务器:examples/todomvc/.mcp.json 声明了
playwright-test服务器,命令为npx playwright run-test-mcp-server,这正是 Agent 工具白名单中mcp__playwright-test__*前缀的来源; -
提供项目骨架:examples/todomvc/package.json 提供
test/ctest/ftest/wtest四个脚本(全量及 chromium/firefox/webkit 单浏览器),配合 playwright.config.ts 作为 seed 解析与项目选择的依据; -
触发规划:示例仓库内置了触发 prompt playwright-test-plan.md,其内容为:
Create test plan for basic operations of my todo app. - Seed file: `tests/seed.spec.ts` - Test plan: `specs/basic-operations.plan.md`即指定 seed 文件与计划落盘位置两个参数,与
planner_setup_page.seedFile、planner_save_plan.fileName一一对应; -
查看产出:计划文件 specs/basic-operations.plan.md 与由计划生成的测试目录 tests/ 可直接对照,理解“计划 → 代码”的映射关系。
适用前提说明:该 Agent 定义遵循 Claude Code 的 .claude/agents/ 约定(示例中同时存在 .github/agents 与 .github/prompts 对应副本,适配 GitHub Copilot 场景);运行依赖本地可启动的 playwright run-test-mcp-server MCP 服务器及有效 playwright.config.ts;planner_setup_page 会在 testDir 下自动创建默认 seed.spec.ts,这是该流程唯一会写入用户工作区的常规文件(除显式指定的计划文件外)。
小结
playwright-test-planner 这个 Agent 定义文件虽然篇幅不长,但它把“测试规划”约束成了可执行的机器流程:frontmatter 声明工具边界,正文规定“先 setup、后探索、再设计、后落盘”的五步纪律,而 plannerTools.ts 中的 Schema 与 Markdown 模板保证了产出计划的结构性与可追溯性,seed.ts 的解析规则与 planner.spec.ts 的测试用例则固化了暂停语义、路径解析与错误处理等运行时边界。对开发者而言,这套“Planner 出计划、Generator 出代码、Healer 保通过”的三 Agent 分工,是理解 Playwright 测试 MCP 服务器在 AI 辅助测试中定位的完整入口。
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