Playwright AI Agent 之 playwright-test-generator:基于实时浏览器交互的端到端测试自动生成指南
导读
playwright-test-generator 是 Playwright 仓库中为“AI 驱动测试生成”设计的专用 Agent(智能体)。它的核心思路不是让模型凭空写断言,而是让模型先通过真实浏览器一步步执行测试场景,再依据执行日志回放生成稳定、可运行、符合最佳实践的 Playwright 测试代码。阅读本文后,你将理解该 Agent 的系统提示词设计、其挂载的浏览器工具清单、generator_setup_page → 逐步执行 → generator_read_log → generator_write_test 的完整工作流,以及它在仓库源码(MCP test 服务层)中的底层实现与对应测试验证。
本文以 playwright-test-generator.agent.md 为骨架展开,并结合其实现源码 generatorTools.ts、testContext.ts、seed.ts 及测试用例 generator.spec.ts 进行纵深剖析。
Agent 概览:一个“会动手操作浏览器”的测试生成器
playwright-test-generator.agent.md 是标准的 Agent 声明文件(frontmatter + 系统提示词),其 frontmatter 明确定义了 Agent 的身份与能力边界:
name: playwright-test-generator
description: Use this agent when you need to create automated browser tests using Playwright
model: sonnet
color: blue
tools:
- search
- playwright-test/browser_click
- playwright-test/browser_drag
- playwright-test/browser_evaluate
- playwright-test/browser_file_upload
- playwright-test/browser_handle_dialog
- playwright-test/browser_hover
- playwright-test/browser_navigate
- playwright-test/browser_press_key
- playwright-test/browser_select_option
- playwright-test/browser_snapshot
- playwright-test/browser_type
- playwright-test/browser_verify_element_visible
- playwright-test/browser_verify_list_visible
- playwright-test/browser_verify_text_visible
- playwright-test/browser_verify_value
- playwright-test/browser_wait_for
- playwright-test/generator_read_log
- playwright-test/generator_setup_page
- playwright-test/generator_write_test
几点值得注意的设计信息:
- 模型与主题色:
model: sonnet与color: blue用于在 Agent 管理/展示层区分身份(同目录下的 planner 使用model: sonnet, color: green,见 playwright-test-planner.agent.md),提示词中不含具体模型指令。 - 工具命名空间:所有工具都挂载在
playwright-test/命名空间下,由 MCP test 服务端暴露。其中browser_*系列是“动作工具”,负责在真实页面执行点击、拖拽、输入、悬停、文件上传、对话框处理、键盘按键、选项选择、导航、取值等操作;browser_snapshot负责读取当前页面可访问性快照(yaml 格式的 ref 树);browser_verify_*与browser_wait_for负责可见性/文本/数值的验证与等待。 - 三个生成专用工具:
generator_setup_page(初始化场景页面)、generator_read_log(读取执行日志)、generator_write_test(写出测试文件),它们是本 Agent 工作流的“脚手架”。
该 Agent 与上游的 playwright-test-planner.agent.md 形成流水线:planner 通过 planner_setup_page + planner_save_plan 产出带编号步骤与验证规格的测试计划(Test Plan);generator 则消费该计划,把每一条步骤真实执行一遍并沉淀为测试代码。
生成每个测试必须遵循的工作流
系统提示词为 Agent 规定了固定的执行顺序,这是保证生成质量的关键约束:
- 获取测试计划:拿到包含全部步骤与验证规格(verification specification)的测试计划;
- 初始化场景:调用
generator_setup_page工具为当前场景准备好页面; - 逐条执行并回放:对场景中的每一步与每一项验证:
- 使用某个 Playwright 浏览器工具在实时页面上手动执行该步骤;
- 将该步骤的文字描述作为每次工具调用的
intent(意图)参数传入;
- 读取生成日志:通过
generator_read_log获取生成器日志; - 立即写测试:读取日志后立刻调用
generator_write_test,把生成的源码写入测试文件。
这里的核心机制是 intent 驱动 + 执行日志回放:Agent 在执行 browser_click、browser_type 等动作时,附带描述性 intent 字符串(如 “Click submit button”),底层后端在执行成功后会返回对应的可执行代码,并连同 intent 一并记录进“生成日志”;generator_read_log 返回的正是这份结构化日志,供模型在写测试时引用真实使用过的可靠定位器而非凭空臆造。
日志的四个组成部分
从 testContext.ts 中 GeneratorJournal.journal() 的实现可以看到,generator_read_log 返回的日志严格包含四部分:
# Plan:本次测试计划全文;# Seed file: <path>:seed 文件相对路径及其源码(```ts 代码块);# Steps:按序排列的每个步骤,格式为### <intent>+ 对应可执行代码块;# Best practices:从日志中应遵循的最佳实践清单。
测试文件的生成规范
提示词对 generator_write_test 产出的文件提出了明确的格式要求:
- 文件只含单个测试(single test);
- 文件名必须是文件系统友好的场景名(fs-friendly scenario name,例如
add-valid-todo.spec.ts); - 测试必须放进一个与“顶层测试计划条目”同名的
test.describe分组中; - 测试标题必须与场景名一致;
- 每个步骤执行前要写入包含步骤原文的注释;若一个步骤需要多个动作,则不要重复注释;
- 写测试时始终采用日志中的最佳实践。
提示词中的 example-generation 给出了计划到代码的映射示例:计划顶层标题 1. Adding New Todos 映射为 test.describe('Adding New Todos'),场景 1.1 Add Valid Todo 映射为 test('Add Valid Todo'),步骤 “Click in the ...” 映射为文件内 // 1. Click in the ... 注释下的真实点击代码;文件头还保留了来源溯源注释 // spec: specs/plan.md 与 // seed: tests/seed.spec.ts。
随后给出的 XML 风格 example 则是给下游生成/组装层传递测试套件名(test-suite)、测试名(test-name)、目标测试文件(test-file)、seed 文件(seed-file)与测试体(body)的接口示意。
关键工具深度解读(源码级)
三个 generator 专用工具在 generatorTools.ts 中逐一实现,均通过 defineTestTool 注册,属于 type: 'readOnly' 类别(不修改被测应用,只产出测试文件)。
generator_setup_page —— 建立场景并启动“暂停态”测试运行器
inputSchema: {
plan: z.string() // 必填:完整测试计划(含所有步骤)
project: z.string() // 可选:使用的项目,例如 "chromium";缺省取配置中第一个项目
seedFile: z.string() // 可选:用于搭建测试页面的 seed 文件,如 "tests/seed.spec.ts";缺省自动创建默认 seed
}
其内部实现逻辑(setupPage.handle)分为三步:
context.getOrCreateSeedFile(params.seedFile, params.project):解析出 seed 文件路径与项目;- 用该 plan + seed 创建
GeneratorJournal并挂到上下文; context.runSeedTest(...)启动一次带 globalSetup、单 worker、无超时、pauseAtEnd: true的测试运行,等待TestPaused事件,从而让页面停留在可交互状态。
当 status !== 'paused' 时该工具返回 isError: true。seed 文件解析规则(seed.ts 中 getOrCreateSeedFile)为:先在项目的 testDir 下解析,再回退到 config 目录与客户端工作目录;均不存在则报错 seed test not found。若未传 seedFile,则查找 testDir 下文件名含 seed 的既有文件;找不到就自动创建 testDir/seed.spec.ts,内容为内置模板:
import { test, expect } from '@playwright/test';
test.describe('Test group', () => {
test('seed', async ({ page }) => {
// generate code here.
});
});
默认项目选择逻辑见 seedProject():未指定 project 时取第一个顶层项目,否则按 project.name 精确匹配,找不到会抛出 Project ... not found。
在 generator.spec.ts 中,seed 文件可以是携带 test.beforeEach 的自定义夹具(例如先 page.setContent('<button>Submit</button>')),运行后返回的 pause 消息形如:
### Paused at end of test. ready for interaction
### Page state
- Page URL: about:blank
- Page Title:
- Page Snapshot:
```yaml
- button "Submit" [ref=e2]
### browser_* 动作工具 —— intent 是日志记录的关键
任何带 `intent` 参数的动作工具在成功执行后,其返回的响应中会携带真实的 `code`(如 `await page.getByRole('button', { name: 'Submit' }).click();`)与最新页面快照。这正是“先执行、后生成”的关键点:**代码不是模型写出来的,而是真实操作回放出来的**。
底层机制位于 [testContext.ts](https://gitcode.com/GitHub_Trending/pl/playwright/blob/46cd5008d12d4e1297793d921e6cc3b595e388da/packages/playwright/src/mcp/test/testContext.ts?utm_source=gitcode_repo_files) 的 `sendMessageToPausedTest`:当请求参数里存在字符串类型的 `intent` 时,后端调用 `tools.parseResponse` 解析动作结果,若响应无错误且含 `code`,就调用 `generatorJournal.logStep(intent, code)`,把“意图标题 + 可执行代码”追加进日志。换言之,**日志只收录真实执行成功、能够稳定产出的步骤**,天然排除了模型幻觉。
从 [generator.spec.ts](https://gitcode.com/GitHub_Trending/pl/playwright/blob/46cd5008d12d4e1297793d921e6cc3b595e388da/tests/mcp/generator.spec.ts?utm_source=gitcode_repo_files) 的断言可见,browser 工具还会尊重项目配置中的 `testIdAttribute`(例如自定义 `data-tid`),此时生成代码会自动使用 `page.getByTestId('submit')`,说明测试代码是**在用户项目真实配置语境下生成**的。
### generator_read_log —— 读取执行日志
```ts
generator_read_log: 输入为空;返回 GeneratorJournal.journal()
若 Agent 在未执行 generator_setup_page 前就调用本工具,后端会直接抛错:
Error: Please setup page using "generator_setup_page" first.
对应测试 'generator_setup_page is required' 在 generator.spec.ts 中验证了这一前置约束对 generator_read_log 与 generator_write_test 均生效。
generator_write_test —— 安全写出测试文件
inputSchema: {
fileName: z.string() // 测试要写入的文件
code: z.string() // 生成的测试代码
}
写入逻辑带有多重安全与一致性校验:
- 前置条件:必须先
setup page且存在活跃的 test runner,否则抛错; - 路径安全:通过
resolveWithinRoot(rootPath, fileName)将目标文件解析限定在项目根内; - 目录匹配:遍历
playwright.config中所有项目的testDir,只有当目标文件isPathInside(projectTestDir, resolvedFile)(即落在某个项目的测试目录内)时才会mkdir -p并writeFile;否则抛出错误Test file did not match any of the test dirs: <dirs>,其中会列出所有可用的测试目录,帮助 Agent 下次选择正确路径。
成功时返回 ### Result\nTest written to <fileName>。
写入日志的最佳实践清单
generator_read_log 返回内容的尾部固定附有 # Best practices 清单(定义于 testContext.ts 的 bestPracticesMarkdown),系统提示词也要求 Agent “始终采用日志中的最佳实践”。完整原文为:
- 不要即兴发挥,不要添加未被要求的指令;
- 使用清晰、描述性的断言来验证期望行为;
- 使用本日志中的可靠定位器(reliable locators);
- 对多次使用的定位器使用局部变量保存;
- 采用日志中的 Playwright 自动等待断言与最佳实践;
- 绝不使用
page.waitForLoadState(); - 绝不使用
page.waitForNavigation(); - 绝不使用
page.waitForTimeout(); - 绝不使用
page.evaluate()。
这四条“绝不”与 Playwright 推荐的“自动等待 + 可重试断言 + 优先用 locator”理念一致:依赖自动等待而非手动等待 API,能让生成出的测试具备更强的健壮性。
与 Plannner/Healer Agent 的协作关系
playwright-test-generator.agent.md 并不是孤立文件。在 packages/playwright/src/agents 目录下,还并存着:
playwright-test-planner.agent.md:负责探索应用、产出结构化测试计划(场景含标题、逐步指令、预期结果、起始状态假设与成功/失败标准),经planner_save_plan保存为 markdown 计划文件;playwright-test-healer.agent.md:负责在测试失败时自我修复;- 配套的 prompt 模板:
playwright-test-plan.prompt.md、playwright-test-generate.prompt.md、playwright-test-coverage.prompt.md、playwright-test-heal.prompt.md,以及generateAgents.ts(将 agent 声明批量生成为正式 Agent 配置的构建脚本)与agentParser.ts(frontmatter 解析器)。
可见本项目把“规划 → 生成 → 覆盖率评估 → 修复”拆解为多个专职 Agent,playwright-test-generator 是其中负责“将计划落成测试代码”的执行者,其输入(测试计划、seed 文件)与输出(.spec.ts 测试文件)均与前后端 Agent 强耦合。
如何在仓库中验证与体验
由于该 Agent 依赖 MCP test 服务端能力(BrowserMCP/TestMCP),仓库中与之直接对应的自动化测试集中在 tests/mcp/generator.spec.ts,它通过 mcpServerType: 'test-mcp' 启动真实服务端,并覆盖以下行为:
- 所有
browser_*动作工具都具备intent参数('generator tools intent'); generator_setup_page返回 “Paused at end of test” 暂停消息与页面 yaml 快照;- 动作执行后
generator_read_log能回放出# Plan、# Seed file、# Steps下### <intent>+ 真实代码; - 未 setup 先读日志/写文件会得到前置错误;
generator_write_test会真实写出文件内容;- 自定义
testIdAttribute会被生成的代码正确采用。
如需阅读完整链路,可按下列路径继续深入本仓库源码:
- Agent 声明:packages/playwright/src/agents/playwright-test-generator.agent.md
- 上游规划 Agent:packages/playwright/src/agents/playwright-test-planner.agent.md
- 三个 generator 工具实现:packages/playwright/src/mcp/test/generatorTools.ts
- 日志与运行器状态机:packages/playwright/src/mcp/test/testContext.ts
- seed 文件查找/默认模板:packages/playwright/src/mcp/test/seed.ts
- 端到端行为验证:tests/mcp/generator.spec.ts
小结
playwright-test-generator 的设计精髓可归纳为三点:真实执行优先于凭空生成(所有代码来自真实操作回放);intent 贯穿执行与日志(步骤文字描述与可执行代码一一对应,保证可追溯性);强约束的输出规范(单测试单文件、describe 对齐计划顶层条目、注释对齐步骤原文、仅落盘于合法 testDir)。这套“planner 出计划、generator 用浏览器跑一遍再回放成代码”的机制,正是 Playwright 仓库在 AI 原生测试生成方向上的落地形态,也解释了为何生成的测试能够直接使用项目中真实的定位器策略与 testId 配置。
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