关于 playwright-in-sandbox
用于浏览器验证和确定性端到端测试的 Playwright 技能。它指导 Agent 执行交互检查、视觉审查,并为变更后的用户流程建立回归覆盖。
主要功能
- 01交互式浏览器验证
- 02确定性 E2E 测试编写
- 03基于截图的视觉检查
- 04选择器与就绪条件指导
- 05E2E 数据和产物规范
适用场景
- 01在浏览器中验证 UI 变更
- 02为工作流添加回归覆盖
- 03重写或整合 Playwright 测试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ customware-ai/ skills --skill playwright-in-sandbox安装后在 Claude Code 中输入/playwright-in-sandbox确认已加载。
详细介绍
Playwright 沙盒
这是用于沙盒浏览器验证和确定性端到端覆盖的主要 Playwright 技能。
请以两种明确模式之一使用:
- 交互式沙盒模式:在任务实现状态看起来合理正确后,进行最终浏览器验证。
- 确定性 E2E 模式:在完成任务前,为需要可靠回归测试保护的改动流程提供覆盖。
此技能有意保持通用,适用于:
- Agent 完成 UI 工作后,通过截图驱动的任务级验证来获取浏览器端证据
- 在下游应用代码库中正式编写或重写 Playwright E2E 测试
- 在将任务视为完成之前需要进行最终浏览器验证的任务流程
对于仅涉及后端的工作、不值得使用浏览器自动化的一次性页面操作,或尚未了解工作流清单和根因就发生的大范围故障,不要使用此技能。
核心工作流
- 操作浏览器前,先编写简要的 QA 清单。
- 先确定模式:交互式沙盒模式或确定性 E2E 模式。
- 在持久会话中启动或确认应用已运行。
- 实现改动,并确保功能状态看起来合理正确,然后再使用 Playwright 进行验收。
- 通过交互方式运行改动后的流程,并检查截图作为证据,而不只是检查 DOM 状态。
- 记录你了解到的契约:
- 路由就绪信号
- 模态框打开和关闭信号
- 操作启用条件
- 保存完成信号
- 持久的
data-testid或语义选择器
- 如果该流程涉及 Bug 修复、工作流、回归关键功能或有实质性改动,应将其纳入确定性 E2E 覆盖。
- 如果交互验证显示产品行为有误,就修复产品代码或数据契约。不要通过弱化测试来掩盖错误行为。
- 完成任务前,确保改动后的流程同时具备:
- 成功的交互验证
- 持久的 E2E 覆盖,或明确说明为何仅保留交互式验证
通用规则
这些规则同时适用于交互式沙盒模式和确定性端到端(E2E)模式。
- 交互式验证是变更后的签收步骤。不要在实现尚未完成时,把它当作任务中途随意试探的手段。
- 如果浏览器验证证明产品行为有误,就修复功能或底层数据契约。不要想方设法绕过错误,让测试变绿。
- 严格遵循仓库的规范 E2E 数据库契约。如果仓库标准是
e2e.db,就使用e2e.db。如果仓库要求使用e2e.db,但该文件缺失,就创建或配置e2e.db,并继续遵循这一契约。不要悄悄退回使用常规应用数据库。 - 优先查询规范 E2E 数据库或已植入的业务数据,以推导预期值、状态、分配情况和聚合结果。如果仓库使用
better-sqlite3,可以直接检查数据库,在断言 UI 之前确认真实的预期值。 - 选择器优先级如下:
- 明确的
id、data-*、data-testid或其他由项目维护的语义契约 - 可访问角色加稳定的可访问名称
- 标签与控件的关联
- 稳定的 URL、路径名或查询参数契约
- 仅当文本本身就是产品契约时,才使用纯文本选择器
- 仅用于有意进行结构检查时,才使用 CSS、XPath 或 DOM 顺序选择器
- 明确的
- 在签收前,清除失败或已被取代的运行所产生的过期截图、跟踪记录和临时产物。
- 如果仓库有维护中的全套测试运行、夜间 QA 运行或自动化健康检查,请持续关注其是否实际运行,以及运行结果是否保持通过。针对性检查不能永远取代套件健康检查。
- 某些迁移中的应用或一次性客户端应用,暂时可能需要比典型的全新应用更广泛的迁移验证覆盖。这是允许的,但质量标准不变:选择器必须确定、数据必须由项目维护、必须遵循真实的用户契约,且不能制造虚假的通过结果。
模式选择
在以下情况下使用交互式沙盒模式
- 实现已处于合理正确的状态
- 需要通过最终的浏览器验证,证明变更后的流程确实可供用户使用
- 需要通过截图证据判断 UI 是否正确
- 在编写或更新自动化覆盖之前,需要了解或确认就绪门槛、模态框行为或稳定的选择器
在以下情况下使用确定性 E2E 模式
- 此变更修复了一个 Bug
- 此任务创建或实质性改变了用户工作流
- 此流程对业务至关重要,或很可能出现回归
- 正在重写、整合或弃用旧版 Playwright 覆盖
- 没有回归保护就不应认为此任务已完成
仅在以下情况下继续使用交互式模式
- 此变更是探索性的或临时的
- 此流程尚不够稳定,无法纳入回归覆盖
- 此任务不会实质性改变受维护的工作流
- 迁移中的应用或一次性应用需要临时验证,但尚未稳定到可以转为持久的 E2E 覆盖
如果决定不升级为已提交的 E2E 覆盖,请明确说明原因。
共享环境约定
- 除非仓库明确另有规定,否则优先使用
127.0.0.1,而不是localhost。 - 优先遵循仓库明确规定的服务契约。若仓库没有规定,则
4444是常见的沙盒默认端口。 - 在沙盒环境中,Playwright 浏览器可能位于
/ms-playwright;不要假设它位于默认缓存路径。 - 在沙盒环境中,显式以无头模式启动 Chromium:
chromium.launch({ headless: true })。 - 对运行时载荷有疑问时,确认 Playwright 浏览器路径:
echo "$PLAYWRIGHT_BROWSERS_PATH"
ls -al /ms-playwright
- 在执行
page.goto(...)之前,确认目标端口确实正在监听,且应用能够响应。 - 对于标准运行,使用仓库规范的 E2E 数据库约定。如果仓库标准使用
e2e.db,则始终使用e2e.db。 - 如果仓库要求使用
e2e.db,但该文件不存在,则在运行测试前创建或准备好e2e.db。 - 只有当仓库明确支持隔离验证通道,且你有意隔离工作进程运行时,才使用其他数据库名称或路径。
- 将交互式产物与已提交的回归测试资源分开。
- 临时脚本和屏幕截图应放在临时目录或专用产物目录中
- 已提交的回归测试覆盖应放在
tests/e2e/或仓库正式的测试位置
- 在最终确认前,清除失败或已被取代的运行所产生的过时屏幕截图、追踪记录和临时产物。
- 并行运行多个重写或验证通道时,应隔离运行时资源:
- 端口
- 数据库或种子状态
- 输出文件夹
- 屏幕截图和追踪记录
交互式沙盒模式
在实现完成到足以进行验证后,使用此模式确认更改后的用户流程当前可正常运行。
交互模式并不意味着可以不断尝试,直到某次成功。应在实现更改且确信功能理应正常运行后使用此模式,然后通过浏览器对真实用户流程进行最终的视觉和功能验证。
QA 清单
根据以下三个来源编制清单:
- 用户提出的需求
- 你实现或更改的用户可见行为
- 你预计会在最终回复中提出的声明
以上任一来源中出现的内容,在最终确认前都必须对应至少一项 QA 检查。
列出:
- 你打算最终确认的用户可见声明
- 每个有意义的控件、模式切换或已实现的交互行为
- 每个控件可能导致的状态变化或视图变化
- 至少两个探索性探测或偏离正常流程的探测
桌面端验证脚本
将 TARGET_URL 设置为你正在调试的应用地址。优先使用 127.0.0.1,而不是 localhost。
import { chromium } from "playwright";
const TARGET_URL = "http://127.0.0.1:4444";
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 1600, height: 900 },
});
const page = await context.newPage();
try {
await page.goto(TARGET_URL, { waitUntil: "domcontentloaded" });
console.log("Loaded:", await page.title());
// Add the task-specific interactions and assertions here.
await page.screenshot({ path: "playwright-desktop.png", type: "png" });
} finally {
await context.close().catch(() => {});
await browser.close().catch(() => {});
}
移动端验证脚本
如果任务涉及响应式布局或触控行为,请使用单独的移动端脚本。
import { chromium } from "playwright";
const TARGET_URL = "http://127.0.0.1:4444";
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
viewport: { width: 390, height: 844 },
isMobile: true,
hasTouch: true,
});
const page = await context.newPage();
try {
await page.goto(TARGET_URL, { waitUntil: "domcontentloaded" });
console.log("Loaded mobile:", await page.title());
// Add the task-specific interactions and assertions here.
await page.screenshot({ path: "playwright-mobile.png", type: "png" });
} finally {
await context.close().catch(() => {});
await browser.close().catch(() => {});
}
迭代模型
- 针对每个专注的流程,使用一个独立的 Node.js 验证脚本。
- 代码更改后,从干净进程重新运行验证脚本,不要尝试在多次运行之间保留状态。
- 让每个脚本保持精简:只包含一项更改后的流程、其主要断言和屏幕截图产物。
- 如果桌面端和移动端都需要验证,请运行单独的脚本或分别调用脚本。
- 屏幕截图审查是约定的一部分。不要仅凭 DOM 断言就进行最终确认。
交互式检查清单
会话循环
- 编写 QA 清单
- 更改代码
- 针对当前流程运行 Playwright 验证脚本,进行最终浏览器验证
- 使用真实用户输入重新进行功能 QA
- 单独重新进行视觉 QA
- 仅在 UI 处于实际评估的状态后,才捕获最终产物
- 记录可用于正式 E2E 的选择器和就绪条件
功能 QA
- 使用真实用户控件进行验收:键盘、鼠标、点击、触摸或等效的 Playwright 输入 API。
- 至少验证一个端到端关键流程。
- 确认该流程的可见结果,而不只是内部状态。
- 按照共享 QA 清单逐项检查,不要临时抽查。
- 验收前至少覆盖每个明显可见的控件一次,而不只是验证顺利路径。
- 脚本化检查通过后,使用常规输入进行简短的探索性检查。
page.evaluate(...)可以检查或预置状态,但不算作验收输入。
视觉 QA
- 将视觉 QA 与功能 QA 分开处理。
- 在相关状态下明确验证每项可见声明。
- 滚动前检查初始视口。
- 检查 QA 期间能够到达的最复杂真实状态。
- 留意裁切、溢出、变形、对比度不足、图层错乱、动画不自然以及过期浮层。
- 如果 UI 之所以“能用”,只是因为没有注意到隐藏的阻挡元素,那么该流程还不能通过验收。
交互式验收
- 使用常规用户输入通过了功能路径
- 视觉检查覆盖了整个相关界面
- 针对预期初始视图的视口适配检查已通过
- 最终截图与待验收的声明相符
- 最终回复中说明了探索性检查
- 已记录用于编写 E2E 测试的稳定选择器和就绪条件
- 已移除失败迭代遗留的过期截图或临时产物
确定性 E2E 模式
在编写或重写真实 Playwright 回归测试时使用此模式。
目标是保护真实功能。如果应用行为有误,就修复应用。不要通过调整测试来保留 bug。
工作流
- 从交互式验证已证明的内容开始。
- 将已了解的 UI 约定转化为稳定的自动化检查。
- 让每个测试专注于一个工作流系列或一个连贯的用户旅程。
- 确保每个测试自行准备测试环境,或明确接收所需的环境。
- 对值、状态和聚合结果,优先使用规范的预置数据或基于数据库的预期值,而不是测试本身不负责的数据字面量。
- 删除或合并旧测试覆盖前,先验证修改后的流程。
- 如果要重写脆弱的测试套件,请将每个移除的场景归入以下一类:
- 保留
- 有理由地合并
- 有理由地明确标记为过时
- 附带明确说明地隔离
选择器层级
如果存在更好的约定,就不要使用偶然出现的文本、通用组合框模式、视觉样式或易受浮层影响且不稳定的 DOM 结构来编写稳定测试。 除非文本本身就是真实的产品约定,否则纯文本选择器只能作为最后手段。
等待与就绪规则
- 不要默认使用
waitForLoadState("networkidle")。 - 对于导航,等待 URL 变化并确认页面就绪标记,或等待响应约定并确认就绪标记。
- 对于对话框,交互前等待明确的打开状态,下一个依赖步骤开始前等待明确的关闭状态。
- 对于保存操作,等待可观察的保存完成约定。
- 对于异步控件,先断言控件启用的条件,再点击它。
- 对于存在浮层、抽屉或命令面板的流程,在与下一个界面交互前,确认它们已关闭。
- 如果交互因其他界面仍占有焦点或指针事件而失败,应修正就绪模型,而不是不断叠加重试。
导航与断言规则
- 断言行为,而非实现。
- 优先关注用户可见的结果,而非内部实现细节。
- 当数值、状态、名册分配或汇总数据来自预置业务数据时,先根据测试自身的设置或规范数据库契约推导预期值,再断言 UI 与其一致。
- 仅当文本本身就是契约时,才使用文本断言。
- 如果真正的契约位于特定卡片、区域、对话框或行中,请避免在整个页面范围内进行宽泛的文本匹配。
- 不要仅为让测试规范显得全面,就为同一个工作流结果保留多个冗余断言。
- 除非较弱的契约才是产品真正预期的行为,否则不要通过扩大选择器范围、降低预期或接受当前缺陷来让失败的测试变绿。
严禁事项
- 将默认的
networkidle作为主要就绪策略 - 使用
page.evaluate(...)断言 UI 可直接呈现的行为 - 编写涵盖多个工作流的巨型综合测试规范
- 将
button[role="combobox"]这类通用选择器作为主要契约 - 默默复用先前测试遗留的状态
- 在工作流映射明确之前删除或合并旧测试
失败收敛协议
大量测试失败时,默认不要逐个修补。
- 先按根本原因归类失败。
- 身份验证或引导流程
- 服务过期或共享端口争用
- 模态框或遮罩状态
- 选择器契约缺失
- 就绪状态缺失
- 数据或设置不确定性
- 工作流假设已过时
- 先修复共用契约,再处理单个测试。
- 如果测试规范的结构有问题,就停止修补并重写该工作流系列。
- 如果测试规范因混合了过多工作流而反复损坏,就弃用综合测试规范并将其拆分。
重写治理
- 覆盖率损失必须明确说明,绝不能意外发生。
- 每条已移除的旧断言都必须有对应的替代项,或有书面的过时理由。
- 优先进行有意义的合并,而非重复的绿色检查,但不要悄悄降低用户旅程覆盖率。
- 仅在以下情况下保留隔离的
fixme覆盖:- 该行为确实受阻
- 隔离状态已明确标注
- 该系列的其余部分仍可安全推进
- 正式的 E2E 资源应保留在已提交的测试目录中,探索性脚本或截图则应放在这些目录之外。
并行重写验证
可以并行进行重写工作,但前提是所有权划分和运行时隔离真实有效。
- 按工作流系列或互不重叠的文件所有权进行并行处理。
- 未明确划分所有权时,不要让多个工作者编辑同一个综合测试规范或共用辅助工具。
- 如果工作者并行验证,请隔离以下内容:
- 端口
- 数据库或种子路径
- 输出文件夹
- 截图、追踪记录和构建产物
- 如果无法进行运行时隔离,即使重写代码仍可并行,也要串行执行 Playwright 验证。
全套测试的时效性
- 保持针对性验证快速,但不要让维护中的全套测试契约变得过时。
- 如果仓库或自动化技术栈支持每日、每夜或发布前运行全套测试,就应将其视为质量可见性的一部分。
- 如果预期由自动化 Agent 保持 QA 通过,就应有可观察的证据,说明它们已运行、运行了哪些内容,以及是否持续通过。
- 针对性测试规范通过,不足以替代对更广泛测试套件的长期维护。
开发服务器
进行本地 Web 调试时,请在持久的 TTY 会话中保持应用运行。不要依赖短生命周期 shell 发起的一次性后台命令。
请先使用仓库文档说明的启动流程。如果没有明确约定,常见的沙盒模式是:
pnpm run build
PORT=4444 pnpm run start
在执行 page.goto(...) 之前,请确认目标端口正在监听且应用能够响应。
交互式验证完成后,请停止自己启动的服务器进程,确保沙盒保持干净,便于继续执行任务。
常见失败模式
- 浏览器流程之所以通过,只是因为遮罩层或模态框拦截器实际上从未关闭。
- 测试证明了 DOM 发生变化,却未证明用户可见的流程能够正常运行。
- 规范使用了错误的名单、种子数据或身份假设,最终“测试”的是假状态。
- 测试通过适应当前缺陷而变绿,而不是修复应用或数据约定。
- 测试硬编码了本应从测试自有数据库或种子状态推导出的显示文本、计数或值。
- 多个工作线程并行重写文件,但验证仍共用一个固定端口和一个可变数据库。
- 测试套件看起来全绿,只是因为保留了重复测试,而没有妥善整合。
- 一个大型综合规范持续掩盖独特的覆盖范围,因为没人梳理提取出的规范现在分别负责哪些工作流。
签核要求
- 存在针对变更流程的交互式验证。
- 如果该流程对回归测试很重要,也应有持久的端到端覆盖。
- 浏览器证据应与最终回复中的声明相符。
- 选择器、等待条件和断言应基于真实的 UI 约定。
- 应明确说明任何跳过、隔离、整合或弃用的覆盖范围。