E2E 测试最大的维护成本从来不是写用例,而是修选择器:前端重构一次,data-testid 换一茬,CI 红一片。DOM 方案的另一半问题是"看不见"——icon-only 按钮、<canvas> 渲染的图表、无语义标注的自定义控件,选择器和无障碍树都摸不到,更别说 Android/iOS 原生界面和跨域 iframe。Midscene.js(ByteDance web-infra-dev 出品,GitHub 14.5K+ stars,MIT,最新 v1.10.12 于 2026-08-13 发布)换了一条路:元素定位只依赖截图,不读 DOM。测试描述用自然语言,模型直接在图上看"搜索框在哪",返回坐标执行点击输入。定位与渲染栈解耦,跨 Web/Android/iOS/HarmonyOS/桌面端共用同一套 API 和心智模型。

定位原理:截图 → 多模态模型 → 坐标

纯视觉定位的调用链极短,一次 aiAct 大致是这样:

页面截图(viewport) ──► 多模态模型(Default role) ──► 定位结果 JSON ──► 执行层(click/input/hover)
      ▲                                                                        │
      └──────────── 动作后截图,进入下一步(多步任务循环)◄──────────────────────┘

模型返回的不是"哪个 DOM 节点",而是一组元素坐标和动作参数。这一步有两个关键设计:

  1. 动作与数据提取分离。动作(点哪里、输入什么)永远只看截图,保证跨端一致;数据提取和页面理解(aiQuery/aiAssert)可以按需带上 DOM,弥补纯视觉在精确文本读取上的短板。
  2. token 消耗与 DOM 规模无关。传统 AI 自动化把整个 DOM/无障碍树塞进 prompt,页面元素越多 token 越贵;纯视觉方案的 token 只取决于截图分辨率和任务复杂度。这是它敢用于大型后台系统的底气。

代价是模型门槛:不是任意 LLM 都能做 GUI 定位,官方限定了一批 GUI 能力稳定的多模态模型——Qwen3.x、Doubao-Seed-2.1、GLM-4.6V、gemini-3.5-flash,以及可自托管的开源 UI-TARS。

与主流方案放一起看,取舍更清楚:

维度 传统 Playwright 选择器 DOM/无障碍树 + AI Midscene 纯视觉
定位依据 CSS/XPath/testid DOM 结构 + 标注截图 截图本身
重构抗性 低,选择器随 UI 失效 中,结构变化仍会挂 高,只要"看着没变"就能跑
canvas/原生端/跨域 iframe 不支持 部分不支持 支持(人眼可见即可定位)
断言对象 DOM 节点存在性 节点 + 部分视觉 用户实际看到的状态(颜色/高亮/布局)
token 成本 随 DOM 规模膨胀 只随截图分辨率变化
模型依赖 需要 LLM 需要指定的多模态模型

一个常见误解是"纯视觉 = 完全不用 DOM"。实际是动作层不依赖 DOM,aiQuery/aiAssert 这类数据提取和页面理解任务仍可按需注入 DOM 上下文,官方 API 里保留了显式开关。

模型角色分工:Default / Planning / Insight

单模型能跑通全部场景,但复杂任务可以拆三个角色各干各的:

角色 职责 典型场景
Default(必配) 元素定位(Locate)+ 兜底所有任务 点击、输入、hover
Planning(可选) 复杂目标的多步规划、分支决策 "下单流程走完,遇到弹窗就关掉"
Insight(可选) 数据提取、断言、页面理解 aiQuery 结构化抽取、aiAssert 视觉校验

多模型组合会显著增加延迟和 token 消耗——规划模型和定位模型各推理一轮。我的建议:先单模型跑通,只有断言质量或复杂任务规划不达标时再引入 Insight/Planning,别一开始就堆配置。

代码实践:五分钟接入 Playwright 套件

import { chromium } from 'playwright';
import { PlaywrightAgent } from '@midscene/web/playwright';
import 'dotenv/config';

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

(async () => {
  const browser = await chromium.launch({ headless: false });
  const page = await browser.newPage();
  await page.goto('https://www.ebay.com');
  await sleep(3000);

  const agent = new PlaywrightAgent(page);

  // 自然语言动作
  await agent.aiAct('type "Headphones" in the search box, then hit Enter');
  await agent.aiWaitFor('there is at least one headphone product in the list');

  // 结构化数据提取
  const items = await agent.aiQuery(
    '{ title: string, price: number }[], the headphone products in the list',
  );
  console.log('in stock:', items);

  // 视觉断言:校验的是用户"看到"的状态
  await agent.aiAssert('There is a category filter on the left side');

  await browser.close();
})();

模型配置走环境变量,四种组合即可切换模型:

export MIDSCENE_MODEL_BASE_URL="https://openrouter.ai/api/v1"
export MIDSCENE_MODEL_API_KEY="your-api-key"
export MIDSCENE_MODEL_NAME="qwen/qwen3.7-plus"
export MIDSCENE_MODEL_FAMILY="qwen3"

跑完会生成 ./midscene_run/report/<id>.html 报告,每一步动作、查询、断言都带截图可回放,定位 AI 干了什么是靠它,不是靠日志。和现有 Playwright/Vitest 套件是平级集成——aiAssert 抛错即用例失败,不改变原有断言体系。

不想写代码时,同一条自然语言指令可以直接写成 YAML 剧本,交给 agent 模式或 CI 执行:

- aiAct: 'open the search box and type "Headphones", then hit Enter'
- aiWaitFor: 'the result list shows at least one headphone product'
- aiQuery: '{ title: string, price: number }[], headphone products in the list'
- aiAssert: 'the page shows a category filter on the left side'

声明式剧本的好处是测试即文档,产品、测试、开发三方都能 review 用例意图,也方便在 CI 里按环境变量切换目标环境。

踩坑与实测建议

模型选择是最大的坑。 纯视觉定位对模型要求苛刻,用不支持的多模态模型会出现"看得见但点不准"——模型描述对了元素,坐标却偏了几个像素。生产环境建议:国内链路用 Qwen3.x/Doubao,数据敏感场景用自托管的 UI-TARS 7B 跑在本地 GPU 上(延迟可控,无出网合规问题);追求极致效果再上 gemini。先在小流量页面上跑 20 条用例对比定位准确率再定。

token 成本按"步"算。 每步动作 = 一张截图 + 一次模型推理,一个 10 步的流程就是 10 次调用。压成本的手段:减少不必要的 aiWaitFor 轮询(它每次轮询都调模型)、能用普通 Playwright waitForSelector 的等待就别用 AI 等待、长列表分页后只对首屏做 aiQuery

确定性要靠"可观测性 + 重试"兜底。 模型输出偶尔会解析失败,v1.10.6 起支持配置响应格式和解析失败自动重试;v1.10.10 的 record model calls、v1.10.11 的请求 tracing headers 把每次模型调用的入参出参都留痕。遇到 flaky,先看报告里模型到底"看"到了什么——80% 的 flaky 是页面弹窗/懒加载遮挡,不是模型问题,在动作前加一个"关掉弹窗"的 aiAct 比调模型参数有效。

明确纯视觉的边界。 精确文本断言(如金额必须等于 ¥1,234.56)别依赖视觉模型读字,用 aiQuery 带 DOM 提取后做数值断言;校验"按钮是否高亮、布局是否错位"这类视觉状态才是 aiAssert 的主场。混用策略是常态:动作走纯视觉、关键数据校验走 DOM,各取所长。

收尾

Midscene.js 的价值不在"AI 写测试",而在把测试的维护成本结构改了:选择器维护从 O(每次重构) 变成 O(0),跨端复用从"每端一套框架"变成"一套自然语言描述"。进阶方向:YAML agent 模式把测试写成声明式剧本、Midscene Skills 接 OpenClaw 做自主探索测试、以及把同一套 aiAct 直接搬到 Android/iOS/桌面端。适合先拿一个页面复杂度高、选择器频繁失效的业务模块试点,用报告里的定位成功率数据决定是否全量铺开。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐