Midscene.js:基于视觉AI的跨平台UI自动化测试框架深度解析
2026/7/4 14:23:00 网站建设 项目流程

1. 项目概述:当UI自动化不再依赖选择器

如果你做过UI自动化测试,或者尝试过用脚本控制桌面、移动端应用,那你一定对“选择器”又爱又恨。爱的是,它能精准定位一个按钮;恨的是,一旦UI改个颜色、挪个位置,甚至只是字体大小变了,精心编写的选择器就可能瞬间失效,维护成本高得吓人。更别提那些没有DOM结构的原生应用、游戏界面、或者Canvas画布里的元素了,传统自动化工具在这里几乎束手无策。

这就是Midscene.js试图掀起的革命。它不是一个简单的测试框架迭代,而是一次底层逻辑的颠覆:从“代码驱动”转向“视觉驱动”。简单来说,Midscene.js 让AI直接“看”屏幕截图,理解你在自然语言中描述的任务(比如“点击登录按钮”、“在搜索框输入‘Midscene’并回车”),然后自动规划并执行操作。它彻底抛弃了对稳定选择器的依赖,将自动化能力扩展到了“凡可截图,皆可自动化”的境地。

我最初接触Midscene.js时,是抱着解决一个老大难问题的想法:如何自动化测试一个内部使用的、基于Electron开发的桌面工具,这个工具大量使用了自定义绘制的Canvas组件。传统的基于无障碍树或DOM的自动化方案全部失效。在尝试了Midscene.js之后,整个团队的自动化覆盖率从几乎为零提升到了核心流程全覆盖,维护脚本的时间反而下降了。这让我意识到,它带来的不仅是技术上的便利,更是一种思维模式的转变。

2. 四大技术突破拆解:Midscene.js如何重塑自动化

Midscene.js的官方宣传提到了“4大技术突破”,这并非虚言。下面,我将结合自己的实践,逐一拆解这四大突破背后的技术原理和实际价值。

2.1 突破一:视觉驱动的元素定位与交互

这是Midscene.js最核心、最颠覆性的能力。传统自动化(如Selenium, Playwright, Appium)依赖于应用程序的“可访问性树”或“DOM结构”来定位元素。而Midscene.js则引入了多模态大模型(如豆包Seed、Qwen-VL、Gemini等),让AI直接分析屏幕截图。

技术原理浅析: 当你发出一个指令,如aiAct('点击登录按钮'),Midscene.js内部的工作流大致如下:

  1. 截图:获取当前活动窗口或指定区域的屏幕图像。
  2. 视觉理解:将截图和你的自然语言指令一同发送给视觉大模型。模型会分析图像,理解“登录按钮”在图像中的视觉特征(如位置、形状、文字标签)。
  3. 坐标计算:模型返回一个或多个候选元素在图像中的边界框坐标。
  4. 坐标转换与交互:Midscene.js将这些图像坐标转换为屏幕上的绝对坐标,然后模拟鼠标移动、点击等事件。

带来的根本性改变

  • 无惧UI变更:按钮从蓝色变成绿色,从左边移到右边?只要人类肉眼还能认出它是“登录按钮”,AI大概率也能。你的自动化脚本无需修改。
  • 突破技术栈限制:无论是Web的Canvas、SVG,桌面的.NET WPF、Java Swing,还是移动端的原生视图、游戏引擎界面,只要能在屏幕上显示,就能被自动化。我们之前那个Electron+Canvas的工具,就是靠这个特性解决的。
  • 简化脚本编写:测试用例可以用近乎口语的自然语言描述,可读性极高,产品经理甚至都能参与评审。

实操心得:视觉定位并非100%准确,其精度受截图质量、UI复杂度、模型能力影响。在实践中,对于关键操作,我通常会结合aiAssert(视觉断言)来确保操作执行在了正确的元素上。例如,点击后,断言屏幕上应该出现“登录成功”的提示文字。

2.2 突破二:统一的多平台自动化API

“一套API,覆盖Web、PC桌面、Mobile移动端”,这是很多自动化工具的梦想,但实现起来困难重重,因为各平台底层交互机制截然不同。Midscene.js通过一个巧妙的“桥接层”和统一的视觉驱动模型,基本实现了这个目标。

实现机制: Midscene.js本身并不直接与浏览器驱动、操作系统API或移动设备调试协议打交道。它专注于“视觉识别”和“指令规划”。对于不同平台,它提供了不同的“连接器”或“桥接模式”:

  • Web:可以无缝接入你现有的Playwright或Puppeteer实例。Midscene将识别出的操作(如点击坐标)通过Playwright的API执行,完美融入现有测试栈。
  • PC桌面:通过操作系统提供的全局鼠标键盘模拟库(如Windows的pyautogui底层调用、macOS的AppleScript/辅助功能)来执行操作。Midscene.js的Node.js版本封装了这些跨平台调用。
  • Mobile:通过ADB(Android)或WebDriverAgent(iOS)与设备连接,发送触屏操作指令。

核心价值: 这意味着,你可以用几乎相同的脚本逻辑,去测试一个网站、一个桌面客户端和一个手机App的相似业务流程。比如“登录-搜索商品-加入购物车”这个流程,你可以编写一套基于自然语言的YAML流程文件,然后在三个平台上分别运行。极大地降低了学习成本和脚本维护成本。

2.3 突破三:AI智能体(Agent)驱动的流程规划

早期的UI自动化是“录制-回放”,后来是“脚本编写”,而Midscene.js引入了“智能体规划”模式。你不需要告诉它每一步具体点哪里、输入什么,只需要给出一个高级目标。

工作模式对比

  • 传统模式driver.findElement(By.id('search-box')).sendKeys('keyword'); driver.findElement(By.css('.search-btn')).click();
  • Midscene智能体模式aiAct('搜索Midscene.js的相关文档')

在后一种模式下,Midscene.js内部的规划模型(可能是一个LLM)会进行“思考”:

  1. 目标:搜索“Midscene.js文档”。
  2. 观察当前屏幕:可能是一个浏览器首页,或者一个IDE界面。
  3. 规划步骤:首先,我需要找到一个可以输入文本的地方(地址栏或搜索框)。然后,输入关键词。最后,触发搜索(按回车或点击按钮)。
  4. 执行:调用视觉模型定位“地址栏/搜索框”,执行输入操作;再定位“搜索按钮”或模拟回车键。

这带来的不仅是便捷

  • 容错性增强:如果第一次点击的搜索按钮没反应,智能体可以尝试其他方案(比如检查是否有弹窗遮挡,或尝试按回车键)。
  • 处理复杂流程:对于“从邮箱中找到验证码并填写”这类涉及多个步骤、多个应用间切换的任务,智能体可以自主规划执行路径。
  • “Skills”生态:Midscene.js提出了“Skills”概念,可以理解为预置的、可复用的智能体能力模块。比如“上传文件Skill”、“处理验证码Skill”。社区可以贡献Skills,进一步降低使用门槛。官方提到的“让AI编程Agent通过Midscene CLI测试你的UI”,就是指Cursor、通义灵码这类AI编程助手,可以直接调用Midscene的Skills来为你生成或执行测试。

2.4 突破四:面向开发者的极致体验与集成

任何工具要想被广泛采用,光有强大的能力不够,还必须有好用的体验。Midscene.js在这方面做了大量工作。

1. 丰富的、分层的API设计

  • 原子API:如aiTap(点击)、aiFill(填写)、aiAssert(断言),给你最精细的控制权。
  • 任务级API:如aiAct,让你用一句话描述任务。
  • 流程级API:支持用YAML文件定义完整的测试流程,实现测试用例的代码与数据分离,易于管理和复用。

2. 强大的调试与报告工具

  • Playground:这是一个交互式调试环境。你可以实时截图,输入自然语言指令,观察AI如何理解和执行。这对于编写和调试复杂的自动化流程至关重要,能直观看到AI“眼中”的屏幕是什么样子。
  • 可视化报告:测试执行后,会生成详细的报告,其中包含每一步的屏幕截图、AI执行的动作、以及结果。你可以像看幻灯片一样回放整个自动化过程,精准定位失败步骤。

3. 灵活的集成策略: 你可以把它当作一个独立的自动化运行器,也可以将其集成到现有的Jest、Mocha、Playwright Test等测试框架中。这种灵活性保证了它能平滑地融入任何技术栈。

3. 核心细节解析与实操要点

理解了四大突破,我们来看看在实际项目中如何上手和使用Midscene.js,以及有哪些必须注意的细节。

3.1 环境搭建与项目初始化

Midscene.js的核心是一个Node.js库。安装非常简单:

npm install midscene # 或者 yarn add midscene # 或者 pnpm add midscene

关键依赖与配置

  1. AI模型API密钥:Midscene.js本身不包含模型,需要你配置大模型的API。它支持多种模型,官方推荐豆包Seed、DeepSeek-VL、Qwen-VL等。你需要在环境变量或配置文件中设置如DASHSCOPE_API_KEY(阿里通义)、SILICONFLOW_API_KEY(硅基流动,用于DeepSeek-VL)等。
  2. 平台桥接依赖
    • Web:需要已安装Playwright或Puppeteer,并下载好浏览器驱动。
    • PC:可能需要系统权限(如macOS的辅助功能权限、Windows的管理员权限)。
    • Mobile:需要配置好Android SDK(ADB)或iOS的WebDriverAgent。

注意事项:在macOS上首次运行PC端自动化时,系统会频繁弹出权限请求,务必在“系统设置-隐私与安全性-辅助功能”中授予终端或Node.js进程权限。这是新手最容易卡住的地方。

3.2 编写你的第一个视觉自动化脚本

让我们从一个最简单的Web示例开始。假设我们要自动化在掘金网站搜索文章。

const { connect } = require('midscene'); const { chromium } = require('playwright'); (async () => { // 1. 用Playwright启动浏览器 const browser = await chromium.launch({ headless: false }); // 非无头模式,方便观察 const page = await browser.newPage(); await page.goto('https://juejin.cn'); // 2. 连接Midscene到Playwright页面 const driver = await connect(page); // 3. 使用自然语言进行自动化操作 try { // AI会“看”页面,找到搜索框,并输入关键词 await driver.aiAct('在搜索框输入“Midscene.js”'); // AI会找到搜索按钮并点击,或者直接模拟回车 await driver.aiAct('点击搜索按钮或按回车进行搜索'); // 4. 进行视觉断言:验证搜索结果页面是否包含预期内容 const result = await driver.aiAssert('页面上应该显示与“Midscene.js”相关的文章列表'); console.log('断言结果:', result.passed ? '通过' : '失败'); // 可以继续操作,例如点击第一篇文童 // await driver.aiAct('点击第一篇搜索结果文章'); } catch (error) { console.error('自动化执行失败:', error); } finally { // 5. 清理 await browser.close(); } })();

代码解读与技巧

  • connect(page):这是将Midscene与Playwright页面绑定的关键步骤。Midscene通过这个连接,能捕获页面截图并将操作指令委托给Playwright执行。
  • aiAct:参数是自然语言指令。指令应尽可能清晰、无歧义。例如,“点击那个按钮”就不如“点击蓝色的、写着‘提交’的按钮”。
  • aiAssert:用于验证。它不仅会判断元素是否存在,还会利用模型的视觉问答能力,判断内容是否符合描述。这是比传统expect(page.locator('text=xxx')).toBeVisible()更强大的断言。

3.3 使用YAML定义可复用的测试流程

对于复杂的业务流,使用YAML文件管理用例更清晰。创建一个search_juejin.yaml文件:

name: 在掘金搜索并验证 steps: - name: 打开掘金首页 act: 打开浏览器并访问 https://juejin.cn - name: 执行搜索 act: 在页面上方的搜索框输入“Midscene.js”,然后按回车键 - name: 验证搜索结果 assert: 当前页面应该显示一个列表,列表中的项目包含“自动化”或“测试”相关字样 - name: 进入第一篇文章 act: 点击搜索结果列表中的第一篇文章的标题 # 你可以添加更多步骤,比如评论、点赞等

然后,使用Midscene CLI或Node.js脚本运行这个YAML文件:

# 假设已全局安装midscene-cli midscene run ./search_juejin.yaml --platform web --model qwen

YAML设计的优势

  • 非技术人员可参与:产品、运营同学也能看懂甚至编写简单的验收用例。
  • 易于维护:逻辑和测试数据分离,修改流程只需改YAML文件。
  • 便于集成:可以很容易地被CI/CD流水线调用。

4. 实操过程与核心环节实现

让我们深入一个更综合的场景:自动化一个跨平台的笔记应用(Web端创建笔记,移动端查看)。这个场景能充分展示Midscene.js统一API的价值。

4.1 场景设计与架构

假设我们有一个笔记应用:

  • Web端:用于创建和编辑富文本笔记。
  • 移动端(Android App):用于查看和简单编辑笔记。

测试目标:在Web端创建一篇带标题和内容的笔记,然后在Android App上打开该应用,找到并验证这篇笔记存在且内容正确。

技术栈选择

  • Web端:Midscene.js + Playwright
  • Android端:Midscene.js + ADB (通过midscene/android桥接)
  • AI模型:选择Qwen-VL(性价比和开源自托管支持较好)

4.2 Web端:创建笔记自动化脚本

// web_create_note.js const { connect } = require('midscene'); const { chromium } = require('playwright'); require('dotenv').config(); // 加载API密钥环境变量 (async () => { const browser = await chromium.launch({ headless: false }); const page = await browser.newPage(); const driver = await connect(page); await page.goto('https://your-note-app.com/login'); // 1. 登录(假设已有cookie或简单表单) await driver.aiAct('在用户名输入框输入“testuser”'); await driver.aiAct('在密码输入框输入密码'); await driver.aiAct('点击登录按钮'); await page.waitForTimeout(2000); // 等待跳转 // 2. 创建新笔记 await driver.aiAct('点击页面左上角或浮动按钮中的“新建笔记”按钮'); await page.waitForTimeout(1000); // 3. 输入标题和内容 await driver.aiAct('在最大的空白区域顶部,也就是标题栏输入“Midscene.js 测试笔记”'); await page.waitForTimeout(500); // 聚焦到内容区可能需要额外操作,这里假设aiAct能处理 await driver.aiAct('在标题下方的正文编辑区域输入以下内容:本文用于测试跨平台视觉自动化工具Midscene.js。创建于Web端,将在移动端验证。'); // 4. 保存笔记 await driver.aiAct('点击工具栏或页面上的“保存”或“完成”按钮'); await page.waitForTimeout(3000); // 等待同步 // 5. 获取笔记的唯一标识(例如URL中的ID),用于移动端验证 const noteUrl = page.url(); const noteId = noteUrl.split('/').pop(); console.log(`创建的笔记ID: ${noteId}`); // 将noteId存储到临时文件或环境变量,供移动端脚本读取 const fs = require('fs'); fs.writeFileSync('./temp_note_id.txt', noteId); await browser.close(); console.log('Web端笔记创建完成。'); })();

4.3 Android端:验证笔记自动化脚本

// android_verify_note.js const { connect } = require('midscene/android'); // 注意引入Android桥接 const fs = require('fs'); require('dotenv').config(); (async () => { // 1. 连接设备(确保设备已通过USB连接并开启调试模式) // Midscene会通过ADB查找设备,也可以指定设备序列号 const driver = await connect(); // 2. 启动笔记应用(需要知道应用包名和启动Activity) await driver.aiAct('在手机主屏幕上找到名为“我的笔记”的应用图标并点击打开'); // 或者使用ADB命令精确启动 // await driver.adb.shell('am start -n com.yournote.app/.MainActivity'); // 3. 等待应用加载 await driver.pause(3000); // 4. 读取Web端生成的笔记ID const noteId = fs.readFileSync('./temp_note_id.txt', 'utf-8').trim(); // 假设应用有搜索功能,我们搜索笔记标题的一部分 const searchKeyword = 'Midscene.js 测试'; // 5. 在App内搜索笔记 await driver.aiAct('点击应用顶部的搜索图标或搜索框'); await driver.pause(1000); await driver.aiAct(`在出现的搜索输入框中输入“${searchKeyword}”`); await driver.aiAct('点击键盘上的搜索或确认按钮'); await driver.pause(2000); // 等待搜索结果 // 6. 视觉断言:验证搜索结果中存在包含特定标题的笔记项 const assertResult = await driver.aiAssert(`在搜索结果列表中,应该有一条笔记的标题包含“Midscene.js 测试笔记”`); if (assertResult.passed) { console.log('✅ 移动端成功找到Web端创建的笔记。'); // 可以进一步点击进入笔记详情,验证内容 await driver.aiAct('点击那条标题包含“Midscene.js 测试笔记”的搜索结果'); await driver.pause(1000); const contentCheck = await driver.aiAssert('页面正文中应该包含“跨平台视觉自动化”这几个字'); console.log('内容验证:', contentCheck.passed ? '通过' : '失败'); } else { console.log('❌ 未在移动端找到对应笔记。'); // 可以截图保存现场,用于调试 await driver.screenshot('./error_android_search.png'); } // 7. 关闭连接 await driver.disconnect(); })();

这个流程的核心价值

  1. API统一:Web端和Android端的脚本,其核心交互命令(aiAct,aiAssert,pause)的写法是高度一致的。开发者无需分别深入学习Playwright和Appium两套体系。
  2. 视觉驱动:无论Web笔记编辑器是何种富文本组件(Quill、Slate等),无论Android App用的是原生控件还是跨端框架(Flutter、React Native),只要屏幕上能看到,就能被操作和断言。
  3. 流程串联:通过一个简单的文件(temp_note_id.txt)传递状态,就将两个独立平台的自动化任务串联成一个完整的E2E业务流程测试。

5. 常见问题与排查技巧实录

在实际使用Midscene.js近半年后,我积累了一些典型问题的排查经验,这往往是官方文档不会详细提及的。

5.1 视觉识别失败或不准

这是最常见的问题。表现是aiAct执行了,但点击的位置不对,或者根本没找到元素。

排查步骤与技巧

  1. 检查截图质量

    • 问题:屏幕分辨率过高/过低、缩放比例非100%、截图区域不对。
    • 解决:确保测试运行环境(尤其是CI环境)的显示设置标准化。使用driver.screenshot(‘debug.png’)保存当前AI“看到”的画面,检查是否完整包含了目标元素。
  2. 优化指令描述

    • 问题:指令模糊,如“点击那个按钮”。
    • 解决:使用更精确的描述。结合元素附近的文字、颜色、相对位置。
      • 点击按钮
      • 较好点击页面顶部导航栏中,最右边那个蓝色的、写着“发布”的按钮
      • 进阶:如果页面有多个相似按钮,可以先用aiAct(‘将页面滚动到用户头像附近’)调整上下文,再操作。
  3. 尝试不同模型

    • Midscene支持多模型。如果默认的豆包Seed在某场景下不准,可以在连接时指定其他模型,如Qwen-VL或Gemini。它们的视觉理解能力各有侧重。
    const driver = await connect(page, { model: 'qwen-vl-plus' // 指定模型 });
  4. 使用组合定位策略

    • 纯视觉定位是最终手段,但Midscene也支持传统的选择器。对于稳定的、有语义的元素,可以混合使用。
    // 先用选择器定位到大致区域(如一个侧边栏),再用视觉在区域内精确定位 const sidebar = page.locator('.sidebar'); const sidebarDriver = await connect(sidebar); // 连接到特定元素 await sidebarDriver.aiAct('点击设置图标');

5.2 自动化操作执行后无效果

AI点击了,但页面没反应。

  1. 元素状态问题

    • 问题:按钮是禁用状态(disabled)或不可见。
    • 解决:AI可能不会判断元素状态。需要在指令中前置条件,或使用aiAssert先验证元素可交互。
      await driver.aiAssert('“提交”按钮应该是可点击的状态(不是灰色的)’); await driver.aiAct('点击“提交”按钮');
  2. 等待与同步

    • 问题:网络请求或动画未完成,元素尚未就绪。
    • 解决:在关键操作后增加显式等待driver.pause(毫秒)。更好的方式是结合Playwright的等待机制:
      await driver.aiAct('点击加载更多'); // 等待某个特定元素出现,作为加载完成的信号 await page.waitForSelector(‘.new-item’, { timeout: 10000 });
  3. 操作类型错误

    • 问题:某些元素需要双击、长按、拖拽,而非单击。
    • 解决:Midscene提供了更底层的API,如driver.aiTap(x, y)(基于坐标点击),可以组合实现复杂手势。或者,在指令中明确说明:`aiAct(‘长按这条消息,直到出现菜单’)。

5.3 在CI/CD流水线中运行不稳定

无头环境、资源限制可能导致问题。

  1. 截图尺寸与模型限制

    • 问题:CI服务器无显示器,虚拟帧缓冲区(Xvfb)设置的分辨率可能与模型训练数据不匹配。
    • 解决:在启动浏览器或连接驱动时,明确设置窗口大小。
      const browser = await chromium.launch({ headless: ‘new’ }); const page = await browser.newPage(); await page.setViewportSize({ width: 1920, height: 1080 }); // 设置为常见分辨率
  2. 模型API超时或限流

    • 问题:免费或低配的模型API有调用频率限制,在并行测试时容易触发。
    • 解决
      • 在测试中增加合理的间隔driver.pause
      • 考虑使用更稳定、配额更高的商用API,或在本地部署开源模型(如Qwen-VL-Chat)。
      • 在流水线脚本中加入重试逻辑。
  3. 依赖项缺失

    • 问题:CI环境中缺少Playwright浏览器或ADB。
    • 解决:在流水线配置中显式安装。
      # 例如在GitHub Actions中 - name: Install Playwright Browsers run: npx playwright install --with-deps chromium - name: Setup ADB run: | sudo apt-get update && sudo apt-get install -y android-sdk-platform-tools

5.4 性能与成本考量

视觉AI调用是有成本的(无论是金钱还是时间)。

  • 成本优化

    • 缓存策略:对于不变的界面(如登录页),可以缓存第一次识别出的元素坐标,后续直接使用坐标操作,避免重复调用AI。Midscene的某些模式可能支持此优化。
    • 混合定位:对稳定不变的核心元素(如导航栏Logo),使用传统选择器定位;对动态、易变的业务元素,使用视觉定位。
    • 选择性价比模型:对于简单定位,使用Qwen-VL-Flash等轻量模型;对于复杂场景,再切换为更强的模型。
  • 速度优化

    • 区域截图:如果知道目标元素的大致区域,可以只截取部分屏幕传给AI,减少数据传输量和模型处理时间。
    • 并行与异步:合理设计测试用例,避免不必要的线性等待。Midscene的API是Promise-based,支持异步操作。

从我个人的经验来看,Midscene.js代表了UI自动化测试的一个新方向。它用“视觉”这把万能钥匙,打开了无数扇曾经被“技术栈”和“选择器”锁住的门。虽然目前它在极端复杂场景下的准确率和执行速度还有提升空间,但其带来的生产力解放和思维转换是革命性的。对于面临多端测试、无DOM/无辅助功能应用测试挑战的团队,投入时间学习和尝试Midscene.js,很可能是一笔回报率极高的投资。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询