用 Midscene.js 跑通视觉 UI 自动化测试:一份从零上手的完整指南
【免费下载链接】midsceneGUI Agent for E2E Testing项目地址: https://gitcode.com/GitHub_Trending/mid/midscene
给一个界面天天在变的 App 写回归测试,你可能经历过这种事:发布前一天,前端重构了一批类名,两百条用例里有六十条在选择器上挂掉。Midscene.js 走的是另一条路——它让多模态大模型直接看截图来定位元素、执行操作,你用自然语言写测试步骤,不需要维护任何选择器。这是一套面向 E2E 场景的 GUI Agent 工具链,覆盖 Web、Android、iOS、HarmonyOS 和桌面端,适合正在被 UI 自动化维护成本困扰的测试工程师和开发者。
三步跑通第一个视觉脚本
装好 CLI
先确认终端里 Node.js 是 20.19 以上、22.12 以上或 24 以上,CLI 部分执行路径依赖的构建工具链会拒绝更旧的版本。然后全局安装:
npm i -g @midscene/cli配好模型
在运行目录放一个.env文件(dotenv 约定,不写export),填入你的多模态模型配置:
MIDSCENE_MODEL_BASE_URL="https://你的模型服务地址/v1" MIDSCENE_MODEL_API_KEY="你的API密钥" MIDSCENE_MODEL_NAME="模型名称" MIDSCENE_MODEL_FAMILY="模型系列"注意.env必须放在工具运行目录下,跟 YAML 文件在哪没关系。
跑第一个脚本
新建bing-search.yaml,内容只有几行:
page: url: https://www.bing.com tasks: - name: 搜索天气 flow: - ai: 搜索 "今日天气" - sleep: 3000 - aiAssert: 结果显示天气信息执行midscene ./bing-search.yaml,命令行实时输出进度,结束后在输出目录生成 JSON 结果和 HTML 可视化报告。
一张截图能替代多少选择器
把 Midscene.js 想象成一个视觉测试员:你递给他一张屏幕截图和一句"点击登录按钮",他扫一眼图就找到位置点下去,全程不需要知道按钮的 class 叫什么。这就是纯视觉驱动的含义——元素定位只依赖截图,DOM 结构和可访问性树完全不参与。
为什么坚持这么做?因为很多真实元素根本"看不见"在结构里:没有语义标记的纯图标按钮、canvas 画出来的界面、跨域 iframe 里的内容,对传统 DOM 方案都是盲区,而对一张截图来说统统平等。另一个直接好处是测试语义变了:断言验证的是用户实际看到的画面——颜色、高亮、布局,而不只是"某个 DOM 节点存在"。
看懂架构:从模型调用到平台适配
源码分几层,各管各的事:
- 核心层
packages/core/src/:agent/目录是规划与执行的主脑,ai-model/负责多模态模型的接入与解析。 - 平台适配层:
packages/web-integration/(Playwright、Puppeteer)、packages/android/(ADB + scrcpy 投屏)、packages/ios/(WebDriverAgent)、packages/computer/(桌面键鼠与截图)。 - CLI 层
packages/cli/:负责加载.env、批量执行 YAML、汇总结果与生成报告。 - 可视化层
apps/playground/、apps/report/、apps/studio/:浏览器侧边栏、报告页面和桌面应用。
写用例时你只接触最上面两层:一段 YAML 或几个 Agent API 调用,底下怎么切图、怎么问模型、怎么落到手指或鼠标,不用关心。
实测三种最常用的操作
aiAct/ai规划执行、aiQuery结构化提取、aiAssert断言,是日常用例的三板斧。
用自然语言驱动点击和输入
前面 Bing 的例子就是最小组合。同一个 YAML 结构换个开头就能切到真机,比如 Android:
android: deviceId: s4ey59 # adb devices 可查 tasks: - name: 地图导航 flow: - ai: 打开地图应用 - ai: 在搜索栏输入 "杭州西湖",然后点击搜索按钮 - aiAssert: 显示了西湖的路线规划页面iOS 把开头的android:换成ios:(配wdaPort)即可,任务主体一字不动。
让模型吐出结构化数据
aiQuery可以带类型声明,返回的 JSON 直接进断言或落库。在 Playwright 项目里:
const agent = new PlaywrightAgent(page); const items = await agent.aiQuery( '{itemTitle: string, price: number}[], 找出列表里的商品和价格', ); await agent.aiAssert('列表第一件商品显示在库存');注意点是描述里尽量给出字段和范围的约束,模型返回的结构会更稳。
断言验证用户看到的东西
aiAssert是视觉断言,适合验证高亮、颜色、布局这类"看起来对不对"的状态,这些用 DOM 断言很难覆盖。调试时建议加--headed打开浏览器窗口,或--keep-window结束后保留窗口,肉眼对照执行过程比只看报告快得多。
压低维护成本的两个常用手段
问题:重复执行太费模型调用,怎么办?
做法:给任务加缓存标识agent: { cache: { id: "my-cache" } }。相同的规划指令和元素定位会命中缓存、跳过模型调用,官方文档里的实测案例执行耗时从 51 秒降到 28 秒。缓存文件落在./midscene_run/cache,失效时自动回退到重新分析,不会卡死;查询类操作(aiQuery、aiAssert等)永远走实时结果,不会被缓存。
问题:想把 Midscene.js 塞进现有 Playwright 项目?
做法:把现有page对象直接交给PlaywrightAgent,测试文件里的其余断言照旧写。集成细节见 集成 Playwright 文档。批量跑脚本则用通配符:midscene './scripts/**/*.yaml',每个脚本各自生成报告,另有汇总的 JSON 结果。
四个高频问题快速排查
- 现象:装完 CLI 一运行就报 Rspack
Unsupported Node.js version。原因:Node 版本低于 20.19。解法:升级 Node 后重装全局 CLI。 - 现象:脚本报模型未配置,明明
.env里写了。原因:.env放错了目录。解法:它必须在工具运行目录下,与 YAML 所在目录无关;也可以用全局环境变量替代。 - 现象:结果忽对忽错,像是用了旧数据。原因:上次运行留下的规划或定位缓存命中了过期状态。解法:调试期配
cache: false,或删掉./midscene_run/cache重来。 - 现象:Chrome 扩展里调 Ollama 本地模型报 403。原因:浏览器侧请求被拦截。解法:设置环境变量
OLLAMA_ORIGINS="*"再重启浏览器。
和传统方案放在一起对比
| 选择器/DOM 方案 | Midscene.js 视觉方案 | |
|---|---|---|
| 界面重构后 | 批量改选择器 | 截图仍可读则照常通过 |
| 纯图标按钮、canvas | 结构里定位不到 | 截图里看得见就能点 |
| 跨域 iframe | 基本不可达 | 截图无跨域问题 |
| 验证渲染效果 | 只能验证节点存在 | 能断言颜色、高亮、布局 |
下一步
Midscene.js 把"找到元素"这件事从代码搬到了模型里,维护成本随之从选择器转移到了自然语言描述上,而后者显然更接近界面本身。如果还想往下走:克隆仓库 https://gitcode.com/GitHub_Trending/mid/midscene 跑一遍示例,或先读 基本概念文档 把aiAct、aiQuery、aiAssert的边界弄透,再挑一个现有用例试着用截图重写。
【免费下载链接】midsceneGUI Agent for E2E Testing项目地址: https://gitcode.com/GitHub_Trending/mid/midscene
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考