一个实时购物车应用上的三个Playwright代理:规划器、生成器和故障处理器。
一个Playwright框架,其中一个代理负责规划测试范围,一个从实时浏览器会话中生成测试用例,另一个则处理故障,从而在大约16秒内完成22个并行测试。
大多数人都有看过演示:向模型发出指令,获取 Playwright 脚本,运行一次后,不久就会发现它出问题。而高效的 QA 团队则遵循探索、规划、自动化和维护这一循环流程,此处的目标便是让智能体负责每个阶段的工作。最终形成了一个可重复使用的 Playwright 框架,背后有三种专用智能体支撑:
- 规划者负责探索实际应用并编写测试计划。
- 生成器将规划好的单个场景转化为可运行的测试用例。
- 修复者执行测试套件,分析测试失败的原因并解决根本问题。
演示目标是一个小型购物车应用,流程包括登录、查看商品、加入购物车、结账以及感谢页。最终共设计了22个自动化场景,涵盖正常流程、异常情况以及验证边界情况。这些场景在智能体自行维护的页面对象之上并行运行。Playwright的HTML报告显示22个场景全部通过,0个失败,0个结果不稳定,整个测试套件耗时16.2秒。
智能体运行前的准备工作
首先需要具备三样东西。大多数演示都会跳过这些步骤,而它们决定了生成的测试结果是否可用。
Playwright的MCP测试服务器。智能体不应凭猜测操作DOM,因此需要使用真实的浏览器。一个配置文件即可实现二者的连接:
{
"servers": {
"playwright-test": {
"type": "stdio",
"command": "npx",
"args": ["playwright", "run-test-mcp-server"]
}
}
}
这为每个智能体提供了诸如 browser_navigate、browser_snapshot 和 browser_click 这样的工具,同时为 Healer 提供了 test_run 和 test_debug 工具。
框架契约。 一个 framework.md 文件规定了文件夹结构与规范:选择器应存放在 pages/ 中,用户流程存放在 flows/ 中,地址与凭证则存放在 .env 文件中。每个智能体在执行任何操作前都会先读取该文件,因此生成的结果看起来像是一个统一的代码库,而非三种不同的个人风格。
种子测试。 一个简短的测试用例会打开真实的首页并验证某些稳定状态。每个生成的测试都是从这种已知良好的状态开始的。
智能体的性能取决于其运行的框架,而这三种工具就是这样的框架。
规划者:决定哪些内容需要测试
规划师完全不编写代码。它打开应用程序,像一名好奇的测试员一样四处查看,梳理其中存在的元素:表单、身份验证机制、购物车、结账流程、验证信息以及空状态。
其操作步骤如下:
- 调用一次
planner_setup_page函数。 - 使用浏览器工具进行探索,查看DOM快照而非屏幕截图。
- 找出主要的用户流程以及每种流程可能出错的方式。
- 将规划内容以markdown格式保存到
specs/-plan.md文件中。
计划中的每个场景都会包含标题、编号步骤、预期结果、关于初始状态的假设(除非另有说明,否则视为全新会话),以及该场景对应的文件路径。
结账流程共分为22种场景,涵盖登录、购物车、结账以及完整的端到端流程。这种结构后来证明非常有用,因为生成器会将每个环节名称转换为test.describe代码块,从而使计划与代码在结构上保持一致。
为何要设置单独的阶段?测试覆盖率是一个需要思考的问题。当一个提示要求同时进行规划与编码时,规划工作会变得更困难。仅输出计划内容的话,可以在任何测试代码生成之前进行审核和修改。
生成器:将单一场景变为现实
生成器一次只处理一个场景,而非整个计划。对于每个场景,它会:
- 运行
generator_setup_page以进入初始状态。 - 在浏览器中实时执行每一步操作,将步骤描述视为具体指令。
generator_read_log读取执行日志,该日志记录了实际生效的定位器及等待操作。generator_write_test来生成一个测试规范文件。第三步决定了数据的来源——训练数据中的信息不会被保留。文件中存储的是针对真实接口刚刚完成的一次会话的记录。
输出内容会自动遵循框架规则:
// spec: specs/checkout-e2e-plan.md
// seed: tests/web/seed.spec.js
import { test, expect } from '../../../fixtures';
import { users } from '../../../testdata';test.describe.configure({ mode: 'parallel' });test.describe('E2E checkout journey', () => {
test('positive: login → add product → checkout → thank you → home', async ({ flow }) => {
await flow.completeHappyPathPurchase();
});
});
输出中明显缺失的是 CSS 选择器、明文密码以及 URL 字符串。选择器会被移至页面对象中,而多步骤流程则成为流程类中的方法:
async completeHappyPathPurchase(user = users.standard, info = checkout.valid) {
await this.goToCheckoutInformation(user);
await this.fillValidInformation(info);
await this.continueToOverview();
await this.app.checkoutOverview.expectProductVisible(products.first.name);
await this.finishOrder();
await this.backHomeToProducts();
}
通过固定装置,每个测试都会获得独立的浏览器上下文、页面对象图以及流程实例。由于不存在共享的可变状态,该测试套件从一开始就具备并行安全性,而非事后添加的功能。这正是脚本与框架之间的区别。
修复工具:定位正确的故障层
生成测试是一次性的成果,而维护则是持续的成本,正是在这里第三个组件发挥了作用。它的运行流程如下:
test_run负责执行测试套件并收集失败案例。test_debug会在每个失败点暂停执行。- 它会检查实时快照、控制台输出、网络流量以及出错的断言内容。
- 它进而诊断故障原因:是定位器发生变化、时间顺序错位、接口协议改变,还是真正的产品缺陷。
pages/,当接口定义变动时则会更新api/endpoints/。有两项机制确保其可靠性。它绝不会为了让测试通过而弱化断言条件。如果产品存在错误而测试结果正确,它会用test.fixme()标记该测试,并附上描述实际行为的注释,这样失败项就会保持可见而不会被忽略。此外,它还会避免使用networkidle这类仅用于解决竞态条件的临时解决方案。
这样做的好处在于能够集中处理变更。只需重命名一个按钮,相应的单个页面对象方法就会被修改,之后所有使用该方法的测试都能恢复正常。由于有22个测试使用了分布在10个类中的325行页面对象代码,因此重新设计不会影响整个测试套件。总体而言,每个模块都负责代码库中的明确部分,而共享的页面对象层则支撑着整个系统的运行。
从头到尾运行它
设置命令如下:
1. Copy .env.example → .env, set BASE_URL (+ credentials)
2. npm install && npx playwright install
代理将按顺序执行以下操作:
3. Run the Planner
→ specs/checkout-e2e-plan.md (22 scenarios, reviewed by me)4. Run the Generator, scenario by scenario
→ tests/web/login/login.spec.js
→ tests/web/cart/cart.spec.js
→ tests/web/checkout/checkout.spec.js
→ tests/web/e2e/checkout-journey.spec.js5. npm test (4 workers, fully parallel)6. Any red? Run the Healer → re-run → green
切换到其他产品时,这些代理程序不会受到影响。只需将BASE_URL设置为新产品,重新创建页面对象和测试数据,然后再发出相同的三个指令即可。由于这些代理程序读取的是framework.md和.env文件中的内容,而非硬编码的产品名称,因此该流程具有可移植性,无需为特定产品定制。
实际快了多少?
像“人工智能让处理速度提升了十倍”这样的说法,若没有详细说明就不应轻信。手动编写端到端测试往往并非简单的输入操作,而是需要打开开发者工具、寻找稳定的选择器、在复杂的容器结构中定位按钮、重新运行以排查断言过早触发的问题,然后再次从头开始。大部分时间都耗费在这段探索过程中,而生成器通过实时执行各步骤并报告哪些操作有效,从而避免了这些浪费。
其优势体现在多个阶段:
- 确定测试范围。手动方式缺乏系统性,常常会遗漏负面案例。规划工具能提前列出正常、负面及边界场景。
- 查找定位器。原先需要逐个元素在开发者工具中手动搜索,现在则可直接使用已通过测试的会话中所记录的定位器。
- 首次成功测试。原先需要反复进行编写、运行、修复的循环,现在只需基于已验证的测试用例即可完成。
- 维持测试套件正常运行。原先需要逐个检查每个规范中的失效选择器,现在只需修复一个页面对象即可解决所有相关测试的问题。
最大的成本节省体现在第二项到第二十项测试中。第一项测试需要为页面对象、固定装置及初始数据付出实际的准备成本。从那之后,新的测试场景大多只是现有组件的组合,每项测试的成本便会迅速下降。
执行速度源自完全不同的地方。并行性并非人工智能的专属特性,而是智能体必须遵守的设计规则。每项测试都会从固定配置中获取全新的上下文,且没有任何一个会修改共享模块的状态,因此配置可以完全并行运行:本地有四个工作进程,在持续集成环境中有两个工作进程并允许两次重试,只有在测试失败时才会记录追踪信息和视频。任何重复使用同一登录会话的测试套件都无法如此安全地运行。而当前这个方案能够做到,是因为“一个场景对应一项独立测试”是生成器在每个文件中都必须遵循的规则。
四点值得借鉴的经验
- 让角色职责明确。试图通过一个庞大的提示词同时完成规划、编码和调试会导致结果混乱不清。将任务划分为三个专注的角色,每个角色配备自己的工具,这样在每个阶段都能留下可审查的成果。
framework.md对提升质量的作用远超过任何提示词调整。适用人群
那些花费更多时间修复定位器而非设计测试覆盖率的QA工程师将会从中受益。采用Playwright的团队也是如此,他们希望在有序的结构中运用AI而非用其取代人工;同时,将Copilot或Cursor这类智能工具与Playwright的MCP测试服务器进行对比的人也会受益。
这些工具并不能取代QA工作。关于什么重要、什么算真正的漏洞以及哪些测试覆盖率缺失的判断仍需由人来完成。这些智能工具负责探索、处理重复性工作以及修复问题,从而实现计划制定、生成代码、运行测试、修复错误并再次运行的循环。