ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Midscene.js:用自然语言驱动UI自动化,让零编码从口号到落地

Midscene.js:用自然语言驱动UI自动化,让零编码从口号到落地 Midscene.js 这个名字第一次听的人大概率会把它当成又一个基于 Playwright 的 UI 自动化测试封装框架。说实话我一开始也这么想直到我亲手在测试脚本里写下一句中文指令看着浏览器自己完成了点击、输入、断言这一串动作我才意识到这个方向把“零编码”从口号变成了可落地的实践。UI 自动化测试喊了这么多年“降低门槛”录制回放、低代码平台轮番上场可真正落到业务测试团队手里脚本维护依然是最大的体力活。Midscene.js 的核心突破是把“写脚本”变成了“描述需求”你不再需要关心 CSS 选择器、XPath 和等待策略用一句话告诉它你想做什么AI 自动把这句话翻译成浏览器可执行的操作序列再驱动真实浏览器跑完并返回结果。这篇文章我把实际使用中的观察、踩坑和能直接照抄的操作流程都放进来。无论你是刚接触自动化测试的新人还是正在维护一堆脆弱脚本的老手都值得花五分钟看一下。后面讲到的内容和示例代码我会保留“以你当前使用的版本文档为准”的提醒因为这类项目迭代很快刻舟求剑没意义。1. 为什么 UI 自动化测试卡在“脚本”这道坎上1.1 传统脚本维护三个绕不开的坑先聊聊老问题。用过 Selenium、Appium 或者 Playwright 手写过脚本的人都清楚UI 自动化真正难的不是“写”而是“写完之后怎么活下去”。第一个坑是元素定位。前端稍微改一个 class 名称、换一种组件写法你精心维护的 CSS 选择器或 XPath 就直接失效脚本在跑的时候报一个 timeout你打开页面一看元素还在只是不叫这个名字了。团队里如果前端迭代快每周光修定位符就能占掉不少时间。第二个坑是步骤耦合。一段脚本通常包含“等待元素出现、点击、等待下一个页面加载、输入、断言”谁先谁后写得死死的。一旦业务流程调整比如新增一个弹窗、调整一个按钮位置脚本的改动往往要连带好几个用例一起改维护成本成倍上升。第三个坑是环境差异。本地能跑、CI 上就挂Chrome 能过、Chromium 就超时网络慢一点整个等待策略就要推倒重来。这些问题的根源在于我们把对业务的理解硬编码进了脚本的每一个细节里而不是让工具理解“这个动作的目的是什么”。这三点单拎出来任何一个都足以让团队在自动化投入和收益之间反复纠结。所以很多测试团队不是不想自动化而是被脚本维护成本劝退了。1.2 录制回放为什么没能解决问题很多团队被脚本折磨后第一个想到的就是录制回放。录屏工具看起来很美你在页面上点一遍它帮你把操作记录下来生成脚本。但实际用下来录制生成的脚本比手写的还难维护。原因很简单录制工具记录的是“鼠标在哪、点了什么坐标、哪个元素触发了事件”它不记录“用户想完成什么”。页面布局一变坐标失效元素 ID 一变回放直接断掉。更麻烦的是录制脚本里面会混入大量无意义的中间状态比如 focus、blur、hover 这类细碎事件肉眼根本看不出哪些是必要的回头排查问题非常痛苦。所以大多数团队兜兜转转最后还是回到手写脚本至少代码还能 review、能复用、能上版本管理。1.3 “零编码”真正的价值把精力还给业务意图Midscene.js 解决的不是“能不能不写代码”这个表面问题而是把自动化脚本里最耗费人力的三层劳动拆掉定位元素、设计等待、编排步骤。你在脚本里不再写“#login-btn 这个按钮点击一下然后等 .toast 出现再输入 xx”而是直接说“登录然后检查页面是否出现欢迎语”。这听起来像是把工作量推给了 AI但实际上是把人的工作重心从“怎么操作浏览器”拉回到“要验证什么业务”。测试设计本来就是测试最有价值的部分脚本只是载体。当载体不再需要逐行维护测试同学就可以把更多精力放在用例设计、数据准备和结果分析上。这也是我为什么愿意花时间研究 Midscene.js 的原因它切中的不是技术难题而是团队协作效率的难题。2. Midscene.js 的设计逻辑从“写步骤”到“说需求”2.1 一句话指令如何变成可执行操作第一次看到 Midscene.js 产物的人往往好奇它是怎么把一句自然语言变成浏览器动作的。这里我把它的工作流程拆开讲清楚。当你给它一句“点击登录按钮”时它并不是像搜索引擎那样去硬拼关键词。它首先要对当前页面做结构化采样拿到页面的可访问性树、DOM 关键信息以及截图然后把这些上下文和你的指令一起交给大模型做规划。模型在这个上下文中输出一组动作序列比如“找到类型为 button 且文本为登录的控件点击它”。再往下框架把这组动作翻译成浏览器底层可执行的指令交给 Playwright 或 Puppeteer 去执行。这里有个重要的点AI 不是凭空操作页面而是在“看得见”页面的前提下做决策。Midscene.js 每一次动作都会拿当前页面快照重新确认目标是否存在所以它对页面变化的容忍度比传统脚本要高一截。页面布局微调、文案小改AI 通常仍然能根据语义找到目标控件这是它和录制回放本质的差别。2.2 核心抽象agent、execute、assert我用一段时间之后把 Midscene.js 对外最核心的抽象总结成三个词agent、execute、assert。agent 代表一个“有能力操作浏览器的测试代理”它内部管理了浏览器实例、LLM 连接和上下文缓存。你所有自然语言指令都是发给 agent 的。execute 负责执行动作把一句指令变成实际操作assert 负责验证结果把一句断言变成可量化的通过或失败结论。用代码来说整个核心流程大概是这样的方法名以你当前使用的版本 README 为准import { createAgent } from midscene/web; const agent await createAgent({ llm: { model: gpt-4o, apiKey: process.env.LLM_API_KEY, }, browser: playwright, }); await agent.open(https://example.com/login); await agent.execute(输入用户名 test01密码 123456点击登录按钮); const result await agent.assert(页面应该显示欢迎语并且右上角有 test01 字样); console.log(result.pass); await agent.close();这个流程和你以前写测试代码的结构很像区别只在中间的动作描述从“一步步操作”变成了“一段话描述”。理解这三个抽象你后面看任何 Midscene.js 示例都不会懵。2.3 它不是替代 Playwright而是让框架多了一个 AI 驱动层有人会问我是不是该把原来的 Playwright 脚本全丢了我建议是别急着丢。Midscene.js 底层的浏览器控制仍然由 Playwright 或 Puppeteer 完成你可以把它理解成在传统框架上面加了一层 AI 驱动层。这意味着两件事第一它能和现有技术栈共存。原来写的页面对象模型、自定义工具函数在需要精确控制的场景里还能继续用。自然语言指令适合覆盖主流程精确断言和底层网络 mock 这些场景还是传统代码更稳。第二Midscene.js 并没有替你抹掉浏览器本身的能力截图、录屏、追踪文件、失败重试这些基础设施都还在你不需要重新造一套环境。我实际操作时最常用的搭配是“AI 执行主流程 传统代码处理登录态和断言”。比如用一个 Playwright 脚本先注入登录 cookie再交给 agent 执行 UI 操作这样又省 token 又稳定。3. 从零到一5 分钟让 Midscene.js 跑起来3.1 环境准备与安装先把环境准备好。Midscene.js 对运行环境的要求不复杂Node.js 版本建议 18 以上电脑上装一个 Chrome 或者 Chromium 内核浏览器再准备一个大模型接口的 key。模型这一步可以用主流的云服务也可以接本地模型看你的成本和隐私要求。取包也简单两种入口一种是直接装 CLI适合在终端里跑命令另一种是把 SDK 装进现有测试工程。以 npm 安装为例npm init -y npm install midscene/cli # 或者部署到自己的测试框架里 npm install midscene/web装完 CLI 后可以先跑一个识别命令确认环境正常。不同版本的初始化命令有差异我的习惯是装完先执行npx midscene --help看一眼当前支持的子命令再动手省得对着过时教程踩坑。如果你只想快速体验直接用官方的 Chrome 插件也行插件模式下不需要搭工程安装后打开目标网页在输入框里用自然语言描述操作插件会自动执行并展示过程回放。这个路径对新手最友好我先说插件再说 SDK。3.2 最小可运行脚本一句指令跑通一个流程假设你已经把 SDK 装好、拿到了 API key那写第一个脚本就很快了。我一般会先造一个简单的 demo 页面放一个按钮、一个输入框、一段欢迎文案目标就一句话登录后看到欢迎信息。对应的最小脚本大概是这样import { createAgent } from midscene/web; const agent await createAgent({ llm: { model: gpt-4o, apiKey: process.env.LLM_API_KEY, }, browser: playwright, }); await agent.open(http://localhost:3000/login); await agent.execute(在账号框里输入 admin在密码框里输入 123456点击蓝色的登录按钮); const r await agent.assert(页面中出现“欢迎 admin”的提示); console.log(r.pass ? 通过 : 失败); await agent.close();执行之后你会看到浏览器按照你的描述操作日志里会输出每一步的决策依据。注意我建议把账号密码直接写进自然语言指令而不是散落成多个细碎步骤。AI 理解“输入账号和密码并点击登录”这个完整意图远比理解“先点第一个 input再点第二个 input”要可靠。3.3 断言怎么玩让 AI 告诉你“通过还是失败”很多第一次用的人会忽略断言设计觉得 execute 能跑就完事了。其实断言才是 UI 自动化的灵魂Midscene.js 的 assert 也可以接收自然语言比如“页面右上角是否出现用户昵称”“订单列表第一条的状态是否为已支付”。断言返回的结果是一个结构化对象包含 pass 布尔值和模型给出的依据这样你就能在测试框架里继续处理。如果断言失败框架会带上截图和页面快照方便排查是页面真的错了还是模型判断错了。我第一次跑断言的时候有一句“检查登录后是否跳转到首页”被误判成了“检查登录页是否还在”后来把描述改得更具体指向一个明确可见的元素或文案准确率就上来了。4. 进阶玩法复杂场景怎么“说”才有效4.1 指令描述太抽象和太白话都不行等你熟悉了基本跑法会发现指令怎么写直接决定成功率。这里我总结几条实际经验。第一目标优先于过程。与其说“把鼠标移到右上角头像点一下在弹出的菜单里找退出点退出”不如说“退出当前账号登录状态”。AI 会用它对 UI 的理解去完成目标对页面改版的鲁棒性更好。但也要小心别过度抽象比如“检查用户权限正常”这种没法落地的描述模型执行不了它需要的是一个可观察的页面结果。第二关键信息要给全。涉及输入框最好把文案特征一起说比如“在标签为‘邮箱’的输入框里输入 testexample.com”而不是“在第一个框里输入”。涉及按钮带可见文本或位置信息也更稳。第三一个 execute 对应一个完整意图。太长的句子容易让模型规划出混合路径太短的又缺少上下文。我的经验是一步指令控制在 20 到 60 个字符之间类似“从首页进入商品详情页把第一件商品加入购物车”这种粒度就很好。4.2 数据驱动零编码不等于零配置“零编码”容易让人误以为所有用例都不需要写代码实际项目中要做到可维护还是要保留数据驱动的思路。Midscene.js 脚本本身可以用 JS/TS 写所以你可以把测试数据放到 JSON 或数组里循环执行同样的指令。比如批量测试多组账号的登录场景const cases [ { name: 正常用户, account: user01, password: pass1, expect: 欢迎 }, { name: 锁定用户, account: locked, password: pass2, expect: 账号已锁定 }, ]; for (const c of cases) { await agent.execute( 在账号框输入 ${c.account}密码框输入 ${c.password}点击登录 ); const r await agent.assert(页面应显示“${c.expect}”相关提示); console.log(c.name, r.pass); }这条循环体里没有一行定位代码数据却完全可控。这在回归测试里特别实用新增一组测试数据只是往数组里加一行不用复制整个脚本。4.3 接入现有测试框架与 CISDK 模式最大的价值是可以嵌入到 Jest、Mocha 或者你的自研测试平台里。你可以把自然语言脚本当成普通异步用例跑失败时让框架捕获断言结果输出标准报告。CI 里也一样给 agent 的 llm 配置加上环境变量注入跑完再存截图和日志。有一点要特别提醒大模型 API 是外部依赖比本地执行更容易出现超时和限流所以接入 CI 时要给 agent 调用加上超时设置和失败重试。第一次我直接丢到流水线里结果一个用例因为单次请求超时导致全红后来在公共步骤里加了重试情况才稳定下来。还需要关注成本尤其是大规模回归时token 消耗是笔实打实的开销建议在套件里控制并发数只对接口不稳定、视觉交互复杂的核心用例开 AI 驱动其他用例继续用传统脚本。5. 真实项目实录一次完整的“零编码”测试落地5.1 案例场景与目标设计讲完原理和方法用一个我最近做的例子串一遍完整落地流程。这个项目是个典型的电商 H5 商城需要验证的核心流程是打开首页 → 搜索商品 → 进入详情 → 加入购物车 → 提交订单 → 确认支付成功。业务方要求跨浏览器跑两遍一遍 Chrome一遍移动端模拟。放在以前这套用例大概要写上百行脚本内部包含大量等待策略、元素定位和分支处理。这次我用 Midscene.js 来做目标很直接主流程全程用自然语言描述断言全部用业务语言不再维护定位符。5.2 执行过程和脚本演化我把流程拆成四条指令搜索、进详情加购、提交订单、验证支付结果。脚本骨架大概这样await agent.open(https://example.com/shop); await agent.execute(在顶部搜索框输入“无线耳机”回车搜索); await agent.execute(在搜索结果中点击综合排名第一的商品进入详情页); await agent.execute(点击“加入购物车”如果弹出促销弹窗则跳过再点击“去结算”); await agent.execute(确认收货地址默认点击“提交订单”); const paid await agent.assert(订单页面显示“支付成功”);这里写到了“如果弹出促销弹窗则跳过”Midscene.js 对这类带分支的指令也能处理模型会先判断页面是否有弹窗再决定动作序列。执行结果第一次就有两处不理想一是搜索时它点到了搜索建议里的联想词而不是回车二是“加入购物车”之后页面还没刷新它就已经去找结算按钮了。我的调整方式不是改成显式等待而是把指令写得更符合页面真实节奏比如“输入关键词后按回车键等待搜索结果加载完成点击第一件商品”。AI 驱动脚本的迭代方式更多是调整语言描述而不是修改定位器。5.3 结果分析和复用价值跑通之后这套脚本在 Chrome 和移动端模拟下都通过了。最让我满意的是业务同学改了页面文案之后这套脚本一次没改仍然能过。因为底层不再绑定具体文本和 class只要业务流程没变“搜索、加购、下单”这些语义都还能被正确识别。当然也不是说它完全不需要维护。如果业务流程本身变了比如支付前新增了一个优惠券选择页脚本的指令就要跟着更新。但这种更新的频率和成本比传统脚本改定位符的方式低太多了。对一个迭代很快的电商项目来说这就是实打实的效率提升。6. 高频问题与避坑指南6.1 常见问题速查表我把这段时间在社区、团队内部遇到的高频问题整理成一张表方便你遇到情况时快速对照。现象常见原因解决思路指令执行到一半超时页面加载慢或 LLM 响应慢给 agent 配置超时和重试指令拆短点击了错误元素指令描述过于模糊补充可见文本、标签或位置信息断言误判通过/失败描述覆盖了多个可变化元素只针对唯一且稳定的文案或状态消耗太大token 成本高每个用例都开 AI且未控制并发核心用例才用 AI其他继续传统脚本同一指令结果不稳定模型随机性或页面动态内容提高描述确定性必要时增加重试与现有 CI 结合困难环境变量、模型配置未统一把 API key、模型名收敛到统一配置6.2 我踩过的一个最深的坑最后分享一个让我印象深刻的教训。有一回我把 Midscene.js 挂在 CI 上做全量回归一批用例明明在本地跑得好好的一到流水线里就玄学式失败。排查到最后发现问题根本不在 AI而在浏览器实例的管理。本地是有头浏览器CI 是无头模式少量用例在无头模式下对动态内容的渲染时机不同页面快照还没稳定指令就已经开始执行了。解决办法是给整段指令加一句“先等页面出现 XX 元素”作为前置条件让 AI 的决策建立在页面已就绪的前提下而不是依赖框架自带的等待。这个思路跟传统测试里写显式等待是一样的只不过表达方式换成了自然语言。所以说“零编码”只是消灭了一部分体力劳动测试功底和排查能力依然是这个岗位的核心竞争力。我个人现在的使用习惯是能描述清楚业务流程的用例交给 Midscene.js涉及复杂断言、多环境数据准备的场景保留传统脚本核心主流程用自然语言覆盖边缘情况用代码精确控制。这种混合模式既享受了 AI 带来的效率又不把稳定性全部押在模型身上。最后再给想入门的朋友一个建议别一上来就用它重构所有旧脚本。先从一条使用频率低、但价值高的主流程用例开始跑通之后你就会对它的能力和边界有直观感受。用顺手了再逐步扩大范围。
返回列表