当选择器全部失效之后:我为什么转向 AI 视觉自动化测试
【免费下载链接】midsceneGUI Agent for E2E Testing项目地址: https://gitcode.com/GitHub_Trending/mid/midscene
Midscene.js 是一款基于视觉 AI 与自然语言驱动的跨平台 UI 自动化测试工具——它不解析 DOM、不维护选择器,只凭一张屏幕截图理解界面,你只需用一句大白话描述"想做什么",剩下的定位、点击、输入和校验都交给它完成。这篇文章会从一个测试工程师的真实视角,讲清楚它解决的是什么问题、怎么在十分钟内跑通第一段脚本,以及落地前值得算清的三笔账。
先聊聊那段让人想转行的日子
如果你维护过一套传统 UI 测试用例,下面这些场景应该不陌生:
- 产品经理说"把登录按钮改个样式",前端顺手重构了 DOM,你追着更新了十八条
xpath,第二天又碎了一地; - 页面上一排只有图标没有文字的按钮,可访问性树里全是空白,测试脚本根本不知道该点哪个;
- 遇到
<canvas>渲染的图表、跨域 iframe 里的组件、或者压根没有 DOM 概念的原生 App,传统工具直接宣告无能为力; - 更憋屈的是,样式错位、颜色不对这类"看起来有问题"的 bug,结构性断言完全发现不了。
这些问题不是某个框架的锅,而是"依赖页面结构"这条路线本身的局限。结构是脆弱的,也是残缺的——它只描述了"这里有什么元素",却描述不了"这个界面看起来对不对"。
Midscene.js 的解题思路:跳过 DOM,直接"看图"
Midscene.js 换了一条完全不同的路线:把整张屏幕截图直接喂给多模态视觉模型,让模型像人一样"看"界面、理解界面,再根据你的自然语言指令去定位元素、执行动作。
翻译成大白话就是:它关心的不是代码结构,而是像素本身。你写"点击右上角的设置图标",它就在截图里找到那个图标;你写"检查表单是否校验通过",它就盯着截图判断错误提示有没有出现。
这套逻辑带来的直接好处有三点:
| 对比维度 | 传统选择器方案 | Midscene.js 视觉方案 |
|---|---|---|
| 维护成本 | 每次 UI 改动都要同步更新选择器 | 界面变了只要语义不变,描述就能继续用 |
| 元素覆盖 | 只认语义化标记,图标按钮、canvas、iframe 容易失明 | 人眼可见的一切都能作为操作目标 |
| 断言能力 | 验证"节点是否存在" | 验证颜色、布局、高亮、渲染状态等用户真正看到的东西 |
核心 API 也很直观,基本可以分成两派:一类是"规划并交互"的aiAct,给它一个目标,它会自己拆步骤、执行到底;另一类是"即时交互"的aiTap、aiInput等,一次只做一件事。具体用法后面实战部分会看到。
十分钟上手:从安装到跑通第一段脚本
先说结论:不用写一行代码,也能先跑起来。最简单的方式是安装 Chrome 扩展,在任意网页的侧边栏里直接输入自然语言指令,浏览器就会照做。
想走"脚本化"路线的话,步骤如下:
- 确认 Node.js 版本在
20.19+、22.12+或24+(CLI 依赖的工具链对旧版本不友好); - 安装命令行工具:
npm i -g @midscene/cli; - 在运行目录建一个
.env,填入模型配置:
MIDSCENE_MODEL_BASE_URL="https://your-model-gateway.example.com/v1" MIDSCENE_MODEL_API_KEY="sk-xxxx" MIDSCENE_MODEL_NAME="qwen2.5-vl-72b" MIDSCENE_MODEL_FAMILY="qwen"- 写一个 YAML 脚本。以在线教育平台"完成课程报名"为例:
page: url: https://demo-edu.example.com tasks: - name: 完成课程报名 flow: - ai: 进入"课程中心"页面 - ai: 在搜索框输入"数据结构",然后点击搜索 - ai: 打开第一门课程的详情页 - ai: 点击"立即报名"按钮 - aiAssert: 页面出现"报名成功"提示- 一条命令跑起来:
midscene ./edu-course.yaml执行过程中命令行会实时输出进度,跑完自动生成一份可视化报告。如果你想把整个仓库拿下来研究,可以用git clone https://gitcode.com/GitHub_Trending/mid/midscene拉取源码,monorepo 结构下packages/web-integration/、packages/android/、packages/ios/等目录对应着各平台的实现。
第一次实战:用一句话让浏览器自己干活
装好之后,就可以试试 JavaScript SDK 的写法了。下面这段代码基于 Playwright,完成一次在线问诊预约:
import { AgentOverPlaywright } from '@midscene/web'; const agent = new AgentOverPlaywright(page); // 规划式交互:自己拆步骤、自己执行 await agent.aiAct('在科室列表中选择"呼吸内科",打开今天可预约的医生'); // 提取结构化数据 const doctors = await agent.aiQuery< Array<{ name: string; title: string; rating: number }> >('当前页面展示的医生列表,{name: string, title: string, rating: number}[]'); // 校验界面状态 await agent.aiAssert('预约确认页显示医生姓名和就诊时间');注意aiAct和aiTap这类即时交互的区别:aiAct把提示词当成"工作流",允许 AI 连续规划多步、自己处理中间的分支;而aiTap('预约挂号按钮')这类 API 只把提示词当成"某个元素的描述",点一下就结束,不会擅自多做别的事。写脚本时想清楚"我要的是一个目标,还是一个动作",能省掉很多调试时间。
那些传统工具够不着的角落
选择器方案最大的软肋,是"无结构可依"的场景。Midscene.js 因为只看截图,这些场景反而成了它的主场:
- 纯图标按钮:没有文字、没有 aria-label,人眼能认出来,视觉模型就能认出来;
- canvas 绘制的图表与游戏:整个界面就是一块画布,DOM 里什么都没有,但截图里有全部信息;
- 跨域 iframe:同源策略拦得住脚本,拦不住"看一眼";
- 原生 App 与桌面应用:根本没有 DOM 和选择器这回事,但一定有屏幕。
这也是它能同时覆盖 Web、Android、iOS、HarmonyOS 和桌面端的原因——只要"能截到图、能回放操作",剩下的理解工作都交给视觉模型。各平台的接入文档可以在apps/site/docs/zh/platforms/下找到。
一份脚本,五种设备:跨平台自动化测试怎么做到
跨平台不是"五套工具",而是同一套 API 背后的五个适配层:
| 平台 | 底层通道 | 源码位置 |
|---|---|---|
| Web | Playwright / Puppeteer | packages/web-integration/src/playwright/ |
| Android | adb + scrcpy 投屏 | packages/android/src/ |
| iOS | WebDriverAgent | packages/ios/src/ |
| HarmonyOS | hdc 工具链 | packages/harmony/src/ |
| 桌面端 | 原生键鼠控制(Windows / macOS / Linux) | packages/computer/ |
写起来几乎一样。比如用同一套 YAML 思路驱动 Android 设备做地图导航:
android: deviceId: s4ey59 # 通过 adb devices 获取 tasks: - name: 地图导航 flow: - ai: 打开地图应用 - ai: 在搜索栏输入"杭州西湖",然后点击搜索按钮 - ai: 点击第一个搜索结果,进入详情页 - ai: 点击"路线"按钮,进入路线规划页面 - ai: 点击"开始"按钮开始导航这种"一套心智、多端复用"的模式,特别适合移动端和 Web 端都需要回归、又不想维护两套框架的团队。
断言与取数:校验用户真正"看到"的东西
传统断言的局限在于只能证明"元素存在",而aiAssert可以直接校验视觉事实:
await agent.aiAssert('登录按钮处于不可点击的置灰状态'); await agent.aiAssert('页面顶部的警告横幅是红色');配合aiQuery,还能把界面里的信息直接抽成结构化数据(比如医生列表、课程价格、订单明细),省掉"定位 + 取值 + 清洗"一长串样板代码。
对于"这个问题是或否"的判断,还有返回布尔值的aiBoolean可用。整套界面理解类 API 只读不改,天然适合做巡检和数据核对类的任务。
调试、报告与翻车现场
纸上谈兵容易,真跑起来总会遇到状况。几个实用经验:
- 先用 Playground 试指令:在交互式环境里把每条自然语言指令验证通过,再固化进脚本,能省掉大量试错。想驱动"你正在用的这个浏览器",可以用 Bridge 模式让本地脚本连接已打开的 Chrome,复用现有登录态和插件环境;
- 给指令加业务上下文:通过
agent.setAIActContext()补充"遇到 Cookie 弹窗先关掉"这类背景,能明显减少 AI 的"自由发挥"; - 批量跑的时候用上 CLI 的并发与重试:
--concurrent 4并行执行互不依赖的脚本,--retry 2缓解大模型偶发输出不稳定导致的失败,--continue-on-error让单个失败不拖垮整批; - 截图会累积开销:官方文档里有缓存策略(
apps/site/docs/zh/caching.mdx),命中缓存能显著缩短执行时间,建议默认开启。
跑完生成的报告会把每一步的操作、截图和时间轴拼在一起,复盘失败用例时非常直观。
落地前,把这三笔账算清楚
把工具引入团队之前,有三个问题值得认真想:
第一,模型选谁、成本多少。Midscene.js 依赖具备 UI 定位能力的多模态模型,官方支持 Qwen、豆包 Seed、GLM-4V、UI-TARS 等,其中也有可以本地自部署的开源模型。每条指令背后都是一次模型调用,页面越复杂、步骤越多,token 消耗越大。对数据敏感的场景,自托管模型是值得考虑的路子,相关取舍可以看apps/site/docs/zh/model-strategy.mdx。
第二,稳定性怎么兜底。视觉方案偶尔会出现"这次认得、下次认不得"的波动。应对手段有三层:复杂任务开deepThink(任务拆解更稳)、目标元素小或容易混淆时开deepLocate(定位更准)、CI 里配置重试与失败后的人工复核。它替代的是"维护选择器"的体力活,而不是"理解业务"的脑力活。
第三,哪些用例适合视觉方案。我的建议是:凡是"人眼能判断对错"的场景(界面回归、跨端一致性、无结构元素、视觉缺陷),都值得迁过来;凡是"纯逻辑、无界面"的校验,传统断言依然更便宜、更确定。两种手段搭配,而不是互相替代。
写在最后
从"追着选择器跑"到"用一句话描述目标",改变的不仅是写用例的方式,更是思考测试的方式——你开始关心"用户看到了什么",而不是"DOM 里有什么"。
如果你也想试试,推荐从克隆仓库git clone https://gitcode.com/GitHub_Trending/mid/midscene开始,装上扩展、配好模型,找一个你维护的页面,写下第一条自然语言指令。也欢迎在评论区聊聊:你手头最想摆脱选择器的那个用例是什么?我猜大概率是 canvas,或者某个连文案都没有的图标按钮。
【免费下载链接】midsceneGUI Agent for E2E Testing项目地址: https://gitcode.com/GitHub_Trending/mid/midscene
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考