作为 10 年前端,我对"测试"这件事一直有个执念:改完的界面,得有个东西替我盯着,而不是每次靠人眼刷一遍。今天给妖灵守卫(Cocos Creator 3.8.8 的山海经塔防游戏)做的这件事,算是把这个执念落地了大半——把 UI 自动化测试从 puppeteer 换到 browser-skill(bsk),从"截图走查"升级成"截图 + 数值断言"双保险,最后沉淀成 skill 发布了出去。
为什么放弃 puppeteer
之前用 puppeteer-core 跑 Cocos 预览(localhost:7456),最大的痛点是 headless 跑 WebGL 要维护 swiftshader 启动参数,环境一换就崩,参数折腾起来非常消耗耐心。bsk 走的是另一条路:驱动我真实在用的 Chromium(浏览器扩展连接),不用维护那套参数,截图自带裁剪,evaluate 还能直接读 cc.director 查引擎状态。对游戏项目来说,能看真实渲染结果比 headless 可靠得多。
第一个坑:canvas 里的按钮点不到
真正动手测,第一个坑立刻出现:游戏按钮是 canvas 里的 cc.Node,不是 DOM 元素。bsk 的 snapshot 拿不到 aria 树,click 也点不到坐标——按钮根本不在页面上,它活在 WebGL 画布里。
解决办法是 evaluate 模拟真实鼠标事件。按 Label 文本遍历节点树找到按钮(按钮是纯代码建的 Node + TOUCH_START 事件,没有 cc.Button 组件),用 Node.getWorldPosition 拿世界坐标,Camera.worldToScreen 转屏幕坐标,再换算 CSS 的 clientX/clientY,最后给 canvas 派发 PointerEvent + MouseEvent 双发。一套流程下来,主菜单、选关、战斗、图鉴四个页面全部跑通,走完"找按钮 → 点击 → 截图 → 读图验证"闭环。
2px 带来的反转
用户指出选关页"进入"按钮跟卡片边框贴边,问这种问题测试为什么没发现。诚实复盘:截图走查对人眼是盲区——1280px 下 2px 的间距,缩放压缩后根本看不出来。用 evaluate 读真实坐标拿到铁证:按钮中心 x=165 加半宽 48 是 213,卡片右缘 215,只有 2px。修完按钮 x 挪到 147,间距 20px 达标。
数值断言体系
这次教训直接推动测试升级。每个页面用 evaluate 补五条数值断言:元素到容器边界内边距 ≥15px、同类元素对齐偏差 ≤2px(按 centerX 聚类,不能按行分组——金字塔布局按行分全是误报)、文字溢出估算、颜色语义(增益按钮不该用危险红)、画布边界 ≥5px。
新断言上岗第一天就有收获:战斗页"强化"按钮用了危险红系色,坐实了之前人眼手动发现的问题。而断言模板自己也有 bug——2+2+1 布局按行分组产生 false positive,改成按 centerX 聚类后 dev=0 全绿。修模板的过程,就是"自动化测试也得测自己的代码"的现场教学。
编辑器最小化的坑
中途还踩了一个 Cocos 专属坑:改完 .ts 截图完全没变化,怀疑脚本问题,查了半天发现是 temp/programming/packer-driver/targets/preview/chunks/ 目录是空的、mtime 停在旧时间——编辑器最小化也会暂停 watch/编译,浏览器跑的是旧 bundle。把编辑器拉回前台,几秒后新产物出现,浏览器自动拉新,bsk 端连 reload 都不用。
沉淀与发布
整套方案沉淀成了 skill(cocos-preview-bsk-test),带 HTML 报告生成,和 cocos-dev-guide(写 UI 防坑)、cocos-project-scaffold(搭骨架)组成三件套分工,发布到了 SkillHub 和 github.com/xinghunMeng/cocos-skills。
回头看今天最大的收获:截图走查适合结构性、大尺度问题;像素级问题必须数值断言兜底。测试工具本身,也需要被测试。这套"能自己发现问题"的流水线,以后每次改 UI 都能少操心一轮。