mcpField
P
playwright-testing

playwright-testing

github.com/chongdashu测试与质量8691 次安装40 周前更新
代码仓库

关于 playwright-testing

面向前端开发者的测试技能,帮助选择合适的测试层级,并通过可观测性和确定性降低误报与不稳定。涵盖 Playwright MCP 的端到端测试流程,也适用于 Canvas 游戏。

主要功能

  1. 01按风险选择测试层级
  2. 02控制时间、随机性与网络
  3. 03添加稳定的应用测试接口
  4. 04收集错误、请求和截图证据
  5. 05对截图进行视觉差异比较

适用场景

  1. 01为关键用户流程编写端到端测试
  2. 02稳定 Canvas 游戏测试
  3. 03诊断 CI 中的间歇性失败

MCP 相关

提供使用 Playwright MCP 执行浏览器导航、页面检查、控制台与网络诊断及截图的工作流。面向 Playwright MCP 工具的客户端使用者。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/chongdashu/phaserjs-oakwoods --skill playwright-testing

安装后在 Claude Code 中输入/playwright-testing确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
flake-reduction.md
phaser-canvas-testing.md
playwright-mcp-cheatsheet.md
scripts/
imgdiff.py

详细介绍

前端测试

快速建立可靠信心:选择合适的测试层、让应用具备可观测性,并消除不确定性,从而安全地重构,并让失败具有可操作性。

理念:每分钟获得的信心

前端测试失败有两个原因:产品出了问题,或者测试在撒谎。你的任务是最大限度地提高信号质量,尽量避免“测试在撒谎”。

编写测试前,先问自己:

  • 我在防范哪种用户风险(金钱、进度、身份验证、数据丢失、崩溃)?
  • 哪个范围最小的测试层可以捕获这类 bug(纯逻辑、UI,还是完整浏览器)?
  • 存在哪些不确定性(时间、随机数生成器、异步加载、网络、动画、字体、GPU)?
  • 除了 setTimeout,我还能等待什么“就绪”信号?
  • 失败时应该打印或截图哪些内容,才能在 CI 中诊断问题?

核心原则:

  1. 测试契约,而非实现:断言稳定且对用户有意义的结果,以及公开的接口。
  2. 确定性优先于重试:让时间、随机数生成器和网络可控;从源头消除不稳定因素。
  3. 像调试器一样观察:发生失败时,记录控制台错误、网络故障、截图和状态转储。
  4. 先覆盖一个关键流程:可靠的冒烟测试胜过 50 个不稳定的测试。

测试层级决策树

选择能提供所需信心的最轻量级测试层:

层级速度用途
单元测试最快纯函数、reducers、验证器、数学计算、寻路、确定性模拟
组件测试中等使用模拟 IO 的 UI 行为(React Testing Library、Vue Testing Library)
E2E最慢覆盖路由、存储和真实打包及运行时环境的关键用户流程
视觉测试专用布局或像素回归;对于 canvas/WebGL,仅在锁定确定性之后进行

快速开始:编写第一个冒烟测试

  1. 定义 1 个关键流程:“页面加载 → 用户可以开始 → 一个关键操作正常”
  2. 在应用中添加测试接口(见下文)
  3. 选择测试运行器:E2E 使用 Playwright MCP,逻辑使用单元测试
  4. 明确暴露失败:将控制台错误和请求失败视为测试失败
  5. 确保稳定:设置随机数种子、冻结时间、固定视口、禁用动画

具体 MCP 工作流:测试游戏

测试 Phaser/canvas 游戏的分步流程:

1. mcp__playwright__browser_navigate
   → http://localhost:3000?test=1&seed=42

2. mcp__playwright__browser_evaluate
   → () => new Promise(r => { const c = () => window.__TEST__?.ready ? r(true) : setTimeout(c, 100); c(); })
   (Wait for game ready)

3. mcp__playwright__browser_console_messages
   → level: "error"
   (Fail if any errors)

4. mcp__playwright__browser_snapshot
   → Get UI state and refs

5. mcp__playwright__browser_click
   → element: "Start Button", ref: [from snapshot]

6. mcp__playwright__browser_evaluate
   → () => window.__TEST__.state()
   (Assert game state is correct)

7. mcp__playwright__browser_press_key
   → key: "ArrowRight" (or WASD for movement)

8. mcp__playwright__browser_evaluate
   → () => window.__TEST__.state().player.x
   (Verify movement happened)

9. mcp__playwright__browser_take_screenshot
   → filename: "gameplay-state.png"
   (Visual evidence after deterministic setup)

建议添加的测试接口

为便于测试,可在应用中添加以下内容(只读、稳定、精简):

window.__TEST__ = {
  ready: false,           // true after first interactive frame
  seed: null,             // current RNG seed
  sceneKey: null,         // current scene/route
  state: () => ({         // JSON-serializable snapshot
    scene: this.sceneKey,
    player: { x, y, hp },
    score: gameState.score,
    entities: entities.map(e => ({ id: e.id, type: e.type, x: e.x, y: e.y }))
  }),
  commands: {             // optional mutation commands
    reset: () => {},
    seed: (n) => {},
    skipIntro: () => {}
  }
};

规则:公开 ID 和必要字段,不要公开原始 Phaser/引擎对象。

应避免的反模式

❌ 选错测试层:为纯逻辑编写 E2E 测试
看似合理的原因:“干脆通过浏览器测试所有内容吧。”
更好的做法:逻辑使用单元测试;E2E 留给集成契约

❌ 测试实现细节:断言 DOM 结构或类名
看似合理的原因:通过 DevTools 可以轻松断言看到的内容
更好的做法:断言对用户有意义的结果(文本、分数、HP 变化)

❌ 依赖休眠的测试:wait 2s then click
看似合理的原因:简单,而且“在我的机器上能跑”
更好的做法:等待明确的就绪信号(DOM 标记、window.__TEST__.ready)

❌ 随机性不受控:在断言中使用随机数生成器或时间
看似合理的原因:“游戏使用随机数,测试也应该如此。”
更好的做法:设置随机数种子(?seed=42)、冻结时间,并断言稳定的不变量

❌ 未确保确定性就进行像素快照:canvas 截图不稳定
看似合理的原因:“这样可以自动捕获视觉 bug。”
更好的做法:先启用确定性模式,再在已知稳定的帧截图

❌ 把重试当作策略:“把重试次数加到 3 就行。”
看似合理的原因:快速修复,让 CI 通过
更好的做法:修复导致不稳定的根源;重试会掩盖真正的问题

调试失败的测试

测试失败时,按以下顺序收集证据:

  1. 控制台错误:mcp__playwright__browser_console_messages({ level: "error" })
  2. 网络故障:mcp__playwright__browser_network_requests() → 检查是否有非 2xx 状态码
  3. 屏幕截图:mcp__playwright__browser_take_screenshot() → 查看失败时的视觉状态
  4. 应用状态:mcp__playwright__browser_evaluate({ function: "() => window.__TEST__.state()" })
  5. 分类间歇性故障(参见 references/flake-reduction.md):
    • 就绪状态?→ 添加显式等待
    • 时序问题?→ 控制动画/物理效果
    • 环境问题?→ 固定视口/DPR
    • 数据问题?→ 隔离测试数据

达标标准:测试做到什么程度才算“足够”?

最低可行测试套件:

  • 1 个冒烟测试,证明应用已加载且主要操作可用
  • 存在测试接缝(window.__TEST__,包含就绪标志和状态)
  • 确定性模式(适用于 canvas/游戏;?test=1 启用种子设定)
  • 控制台错误会导致测试失败(不允许静默失败)
  • CI 在每次推送时运行测试

满足以下条件时可进一步完善:

  • 关键路径(身份验证、付款、保存/加载)有专门的 E2E 测试
  • 单元测试覆盖复杂逻辑(寻路、伤害计算、状态机)
  • 对关键屏幕(菜单、HUD)进行视觉回归测试,并锁定确定性

使用 imgdiff.py 进行视觉回归测试

比较屏幕截图的像素:

# Compare baseline to current
python scripts/imgdiff.py baseline.png current.png --out diff.png

# Allow small tolerance (anti-aliasing differences)
python scripts/imgdiff.py baseline.png current.png --max-rms 2.0

退出代码:0 = 相同,1 = 不同,2 = 错误

UI 切片回归(九宫格切片 / 丝带 / 条)

Canvas UI 问题(面板接缝、分段丝带、不可见的 HUD 填充)最好通过专门的 UI 测试工具来捕获,而不是依赖完整的游戏流程。

  1. 构建简单的 test.html/场景,只加载 UI 资源。
  2. 将原始切片与组装后的面板并排渲染(多种尺寸),并展示采用“原始裁剪 + 缩放”和“多切片拼接”两种方式的丝带/条。
  3. 暴露 window.__TEST__,并提供 .commands.showTest(n),以便 Playwright 确定性地切换各模式。
  4. 截取指定区域的屏幕截图(面板、丝带、条),并在 CI 中进行差异比较。

确定性设置和屏幕截图工作流请参见 references/phaser-canvas-testing.md。

按场景调整指南

根据上下文调整方法:

  • DOM 应用:使用标准 Playwright 选择器,等待文本/元素
  • Canvas 游戏:必须设置测试接缝,通过 window.__TEST__.ready 等待
  • 混合应用:菜单使用 DOM,游戏过程使用测试接缝
  • 仅 CI 环境有 GPU:可能需要软件渲染标志,或跳过视觉测试
  • UI 切片回归:对于九宫格切片/丝带/条的瑕疵,优先使用小型 UI 测试场景/页面,配合确定性模式和指定区域的屏幕截图(references/phaser-canvas-testing.md)。

随附资源

需要时请阅读:

  • references/playwright-mcp-cheatsheet.md:MCP 工具模式详解
  • references/phaser-canvas-testing.md:Phaser 游戏的确定性模式
  • references/flake-reduction.md:间歇性故障的分类和修复方法

请记住

只需添加一个小而稳定的接缝,用于检查就绪状态和状态信息,几乎任何前端(包括 canvas/WebGL 游戏)都能变得可测试。一个可靠的冒烟测试就是基础。目标是让测试易于维护:结果确定、明确检查就绪状态,并能提供丰富的失败证据。目标是建立信心,而不是追求覆盖率数字。

评论

支持 Markdown