☰
用自然语言写UI自动化测试:Midscene.js实测与落地指南
2026/10/4 11:59:00 网站建设 项目流程

写了三年 UI 自动化脚本,我一度觉得“零代码测试”这类口号就是厂商拿来忽悠领导的。每天维护定位器、处理等待超时、应付各种弹窗,已经够让人头大了,你告诉我“一句话就能生成脚本”?直到我拿到 Midscene.js 实测了一周,才意识到这次可能真的不太一样:它不是把录制回放包装成“零编码”,而是让 AI 直接理解你的自然语言指令,然后把指令变成可执行的、可回归的 UI 测试脚本。

Midscene.js 的核心价值,是把“写脚本”变成了“说需求”。以前我们要告诉浏览器“用 id 定位登录按钮,点击后等待 3 秒,再断言页面出现用户头像”,现在只需要说“打开登录页,输入账号密码,点击登录,确认跳转到首页”就能完成同样的效果。对测试开发来说,这意味着冒烟测试、业务链路回归、甚至临时验证需求,都可以大幅压缩时间。这篇文章我会从设计思路、环境搭建、指令设计、实战案例到生产落地踩坑,完整聊一遍这套方案。

1. Midscene.js 的设计思路:为什么一句话能变成测试脚本

1.1 从“写脚本”到“说需求”,中间发生了什么

要理解 Midscene.js 为什么能“一句话生成脚本”,得先搞清楚传统 UI 自动化的痛点在哪。拿 Selenium 举例,它的工作方式是:你通过 CSS 选择器、XPath 或者 Accessibility 属性去定位页面元素,然后调用 click、send_keys、execute_script 这类 API 去模拟操作。整个过程本质上是在“翻译”人的操作意图:你脑子里想的是“点击登录按钮”,但代码里写的是 driver.find_element(By.ID, "login-btn").click()。

这套模式的维护成本非常高。页面一改版,选择器失效,脚本就挂;前端加了异步加载,固定 sleep 会假死,显式等待又得一个个配置;断言写得太粗发现不了问题,写得太细又到处脆。我见过很多团队的自动化用例,最后都变成了“每周修一次定位器”的体力活。

Midscene.js 换了一条路:它把“意图理解”交给 AI 多模态模型。模型可以直接看页面截图、读 DOM 结构,理解你输入的自然语言指令,然后自己决定“应该点击哪个元素、先做哪一步、怎么做”。所以“一句话生成脚本”的技术内核,其实是三个环节的串联:自然语言指令解析为目标意图,目标意图映射到具体的页面元素和操作序列,操作序列再通过浏览器自动化协议执行并记录回放。

这个过程并不是把文本硬替换成 click 调用的模板,而是模型在真实页面上下文中做判断。比如你说“关闭弹窗”,模型会根据截图找到那个右上角的 X 按钮;你说“把价格从低到高排序”,它会先找到筛选栏,再判断排序方式。这种灵活性是传统规则脚本完全做不到的。

1.2 Midscene.js 与传统自动化框架的核心差异在哪里

我用一个表格总结一下几类框架的差别,这样大家能快速定位 Midscene.js 的位置:

对比维度SeleniumPlaywrightMidscene.js
脚本编写方式代码定位元素代码 + 录制辅助自然语言指令
元素定位策略CSS/XPath 为主CSS/XPath + 自动等待AI 视觉 + DOM 语义双重理解
断言能力需手写断言需手写断言支持自然语言断言
维护成本高,改版必动脚本中等,仍需维护选择器低,页面改版通常不影响意图
调试手段日志 + 截图录制回放 + 时间轴截图 + 操作轨迹 + 视频回放
最适合的场景强控流程、跨端兼容复杂交互、精细化控制业务链路验证、冒烟测试

这里需要说明一下,Midscene.js 不是要完全替代 Playwright 这类框架,而是把“用例表达层”换成了自然语言。底层它仍然依赖浏览器自动化能力来驱动真实浏览器,所以并不是“AI 在云上脑补操作”,每一步操作都是真实发生在浏览器里的,脚本也能被录制、回放和检查。

1.3 它适合什么场景,又不适合什么场景

先说适合的:如果你手上有大量业务冒烟用例,场景是“登录 → 搜索 → 加购 → 下单 → 支付”这种链路非常固定、但元素经常微调的项目,那 Midscene.js 会很香。我实测下来,页面轻微改版基本不影响用例执行,因为 AI 不依赖某一个写死的 id,它通过视觉和 DOM 的综合判断就能找到新位置。

还有一类场景也特别适合:业务同事临时想看某个页面状态、验证某个入口是否正常,以前得求着测试开发帮忙写脚本,现在把需求用中文说清楚就行。团队里非技术角色也能参与用例维护,这在传统自动化里很难想象。

不适合的场景也很明确:如果你要做毫秒级性能监控、要模拟特殊的弱网环境、要在 Network 层精确拦截请求做 mock,那还是老老实实用 Playwright 或 Cypress。另外,对“每一步为什么这么做”有严格审计要求的合规场景,AI 生成脚本的可解释性还比不上显式代码。还有像素级 UI 比对,AI 目前做不到像素精度,这类需求建议交给截图对比工具。

2. 环境准备与第一个零编码脚本

2.1 环境要求与依赖安装

Midscene.js 依赖 Node.js 环境和真实浏览器,安装方式非常常规。我这边演示的是目前主流的接入方式,具体包名和版本号以官方文档为准,但整体流程不会有太大变化。

首先确认 Node.js 版本不低于 18,建议用 20 LTS,避免一些原生模块编译问题。然后在项目目录里初始化:

mkdir midscene-demo cd midscene-demo npm init -y npm install @midscene/web

这里装的是浏览器侧的运行时。Midscene.js 还依赖一个 AI 模型服务,用来解析自然语言指令并理解页面内容。官方默认支持 OpenAI 兼容接口,也支持通过环境变量对接国内模型服务,你可以根据自己的网络和合规情况选择。

需要提醒的是,尽量不要用普通文本模型来做页面理解,最好用支持视觉输入的多模态模型。原因很简单:AI 要“看”页面截图才能定位元素,纯文本模型只能靠 DOM 描述,遇到前端框架渲染的复杂界面,理解准确率会明显下降。我测试下来,视觉模型的元素定位成功率比纯文本模型高出不少。

2.2 配置模型服务连接

模型服务的配置一般是读环境变量。我习惯在项目根目录放一个 .env 文件,把密钥和模型名称集中管理:

# .env 示例 OPENAI_API_KEY=sk-your-key OPENAI_BASE_URL=https://your-endpoint.example.com/v1 MIDSCENE_MODEL_NAME=gpt-4o

如果你用的是本地部署的模型,或者国内厂商的 OpenAI 兼容接口,只需要把 BASE_URL 换成对应的地址。这里有个实践细节:模型名称一定要写成服务端真实支持的那个名字,比如有些平台叫 qwen-vl-max,有些叫 glm-4v,要是写错了运行时会直接报 404。

加载 .env 的方式可以用 Node.js 的 --env-file 参数,也可以自己引入 dotenv:

node --env-file=.env your-script.js

2.3 写第一个“一句话脚本”

我来看一段最小可用示例,这段代码就是全部逻辑了:

import { createAgent } from '@midscene/web'; import { chromium } from 'playwright'; (async () => { const browser = await chromium.launch({ headless: true }); const page = await browser.newPage(); const agent = await createAgent({ page, model: 'gpt-4o', }); const script = ` 打开 https://example.com/login 在用户名输入框输入 demo 在密码输入框输入 123456 点击登录按钮 断言页面出现 “欢迎回来,demo” `; const report = await agent.run(script); console.log('用例是否通过:', report.status); console.log('AI 认为每一步做了什么:', report.details); await browser.close(); })();

你看,真正描述业务逻辑的部分就是中间那个多行字符串。没有任何选择器、没有等待代码、没有断言 API,这就是标题里说的“零编码”体验。

执行完之后,Midscene.js 会生成一份执行报告,包含每一步的截图、AI 的操作日志、断言结果。我通常会打开报告看一眼,确认 AI 理解得对不对,而不是直接闭眼信任。

第一次跑的时候有个坑:AI 模型首次调用会比较慢,尤其是要分析整个页面截图再决定操作,单步可能要 5 到 15 秒。这是正常现象,不是脚本卡死了。后续如果觉得慢,可以把 headless 模式关掉,让 AI 在真实窗口里操作,某些页面的动态渲染问题会少一些。

3. 写出 AI 能准确理解的“自然语言指令”

3.1 指令设计的四条经验

“一句话生成脚本”听起来很爽,但实际用下来就会发现一个残酷事实:AI 对自然语言的理解是概率性的,指令写得太含糊,执行结果就会跑偏。我在这个环节踩了不少坑,总结出四条经验。

第一条,目标要明确,动作要具体。不要让 AI 猜“我想干嘛”,直接告诉它“点击右上角的购物车图标”。哪怕是人类,听到“去把那个东西弄一下”也会懵,AI 也一样。

第二条,指定可见元素,别只靠记忆。比如“点击提交按钮”这种指令,如果页面有多个“提交”字样,AI 可能选错。这时候补充位置信息或视觉特征就很关键:“点击表单底部蓝色的提交按钮”。

第三条,一次指令做一件完整的事。把“登录→搜索→加购”拆成三个独立指令来跑,中间用断言确认状态,比一个超长指令从头甩到尾要稳定得多。AI 的上下文窗口再大,也会在长链路里逐渐丢失前面的细节。

第四条,避免口头禅和歧义词。说“最上面那个”之前,想一下页面上有没有多个“上面”;说“右侧菜单”之前,确认这个页面在手机端和桌面端布局是否一致。移动端和桌面端的响应式布局差异,经常让 AI 的理解产生偏差。

3.2 断言怎么写才靠谱

Midscene.js 的断言能力是最让我惊喜的部分,因为它同样支持自然语言。你不用写 expect(selector).toHaveText,只需要在指令里说:

断言页面标题包含 “订单确认” 断言购物车数量是 2 断言页面不出现 “系统异常”

AI 会结合页面截图和 DOM 结构来判断这些条件是否成立。这就解决了一个老问题:传统断言写得太久、太具体,页面一改就挂;而自然语言断言的容错性更高,它理解的是“语义”,不是“文本精确匹配”。

不过这里也有一个度。如果你对某个值有硬性的数据要求,比如断言价格精确等于 99.90 元,建议你在指令里把数值写全,并补充“不要忽略小数点后两位”之类的约束。AI 有时候会把“99.9”和“99.90”视为等价,这在账目核对场景是致命的。

3.3 动态内容与复杂交互怎么处理

实际业务里没有几个页面是老老实实静态渲染的。下拉框、日期选择器、懒加载列表、iframe 嵌套,这些都会让纯视觉方案翻车。我的做法是混合策略:优先让 AI 自己判断,但给它必要的约束。

比如日期选择器,直接说“选择 2025 年 6 月 1 日”,AI 可能知道要点击日历图标,但未必知道先点年份再点月份。更靠谱的写法是:

点击日期输入框 在弹出的日历组件中选择 2025 年 6 月 1 日 如果日历默认不是 2025 年 6 月,先点击年份切换,再选择月份

这样一来,即使 AI 第一次尝试出错,也能根据补充信息进行自我纠正。页面存在懒加载时,我会加一句“滚动到页面底部,等待内容加载完成”来触发后续渲染,否则 AI 可能以为页面就是当前这么短。

iframe 是一个大坑。有些页面把登录框嵌在第三方 iframe 里,视觉截图是能看到的,但 DOM 操作可能跨不到。我的经验是直接把地址和 iframe 的特征描述进指令:

在 id 为 login-frame 的 iframe 里,输入用户名 demo

3.4 参数化与数据驱动的扩展姿势

“零编码”不意味着数据也要硬编码在脚本里。我经常用数组循环来做多组账号的遍历测试,把自然语言模板拼进循环体:

const accounts = [ { username: 'demo', password: '123456' }, { username: 'test', password: 'abc123' }, ]; for (const item of accounts) { const template = ` 打开 https://example.com/login 在用户名输入框输入 ${item.username} 在密码输入框输入 ${item.password} 点击登录按钮 断言页面不出现 “用户名或密码错误” `; const report = await agent.run(template); console.log(`${item.username} 的执行结果:`, report.status); }

这样既保持了用例的可读性,又复用了同一套逻辑。我通常把模板放进 YAML 或 JSON 配置文件,让不懂代码的业务同事也能维护账号清单。

4. 实战:一条完整业务链路的自动化怎么落地

4.1 场景拆解与指令分段

理论知识聊完,直接上一个完整的实战。我选的场景是一个电商站点的核心链路:登录 → 搜索商品 → 加入购物车 → 进入结算页。这是最典型的冒烟路径,每一步跨一个页面状态。

我的习惯是不写一个“超级长指令”,而是拆成三段,每段之间用结果状态衔接。第一段是登录,断言登录成功;第二段是搜索与加购,断言购物车数量;第三段是结算,断言进入结算页。为什么要分三段?因为长链路一旦中间某一步理解出错,后面所有步骤都会连锁跑偏,到时候排查问题就像大海捞针。

4.2 脚本实现与执行结果分析

下面是我实际运行的简化版本:

import { createAgent } from '@midscene/web'; import { chromium } from 'playwright'; (async () => { const browser = await chromium.launch({ headless: false }); const page = await browser.newPage(); const agent = await createAgent({ page, model: 'gpt-4o' }); const step1 = ` 打开 https://ecommerce.example.com 点击右上角 “登录” 在用户名输入框输入 demo 在密码输入框输入 123456 点击登录按钮 断言页面出现 “我的订单” `; const r1 = await agent.run(step1); console.log('步骤1:', r1.status); const step2 = ` 在搜索框输入 机械键盘 点击搜索按钮 等待搜索结果加载完成 点击第一个商品卡片 点击 “加入购物车” 断言页面出现 “商品已加入购物车” `; const r2 = await agent.run(step2); console.log('步骤2:', r2.status); const step3 = ` 点击页面右上角购物车图标 等待购物车列表加载完成 点击 “去结算” 断言页面出现 “填写收货地址” `; const r3 = await agent.run(step3); console.log('步骤3:', r3.status); await browser.close(); })();

这里有个细节:步骤三我特意把断言写成“页面出现‘填写收货地址’”,而不是“页面出现‘提交订单’”。因为很多电商的结算页会分步骤,提交订单按钮可能在地址填完之后才出现,如果一开始就断言提交按钮,就会误判。AI 的视觉理解能分辨页面状态,但你在指令里给它一个更合理的观测点,成功率会高很多。

4.3 回放报告与人工确认

执行完成后,Midscene.js 会为每个步骤生成报告。我习惯点开报告里的截图,重点看两个东西:一是 AI 点击的元素是不是目标元素,二是断言的发生时机是不是在页面真正渲染完成后。有时候 AI 看截图点对了位置,但操作太快,断言执行时页面还没刷新,就会产生假失败。

第一次跑的时候,AI 在步骤三把“去结算”理解成了“直接提交订单”,一口气跳到了支付码页面,因为页面右上角有一个“结算”按钮和一个“提交订单”按钮,视觉上很接近。我改了一下指令文案,写成“点击购物车列表底部的‘去结算’按钮”,问题就解决了。这再次说明:不是 AI 不行,而是你的指令要给它足够多的上下文。

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

5.1 AI 定位不到元素,卡在第一步

最典型的报错是 AI 说“找不到登录按钮”。我遇到这种情况,先不做任何代码改动,直接打开页面截图看一眼:是不是页面还在登录框加载中,AI 没等渲染完成就截图了?如果是,我会在指令开头加一句“等待页面加载完成,直到出现登录表单”。如果页面本身有多个登录入口,比如顶部导航一个、页面中央一个,我会补充“点击页面中央表单区域的登录按钮”。

还有一种情况是 AI 模型本身不支持中文页面理解得很好,换个更强的新模型版本,或者把指令改成中英混合,往往能解决。

5.2 脚本执行速度太慢,怎么优化

AI 驱动的自动化流程必然没有传统脚本那么快,因为每一步都要走一次模型理解。我的优化策略有三个:

  • 把 headless 设为 false,让浏览器保持前台窗口,某些页面动画和懒加载会更快稳定。
  • 缩小单次指令步骤数,从“10 个动作”拆成“3 个动作 + 1 个断言”,降低单次模型判断难度。
  • 对没有动态渲染的纯静态页面,手动指定一个缩小的窗口尺寸,减少截图像素、提升模型处理速度。

5.3 模型理解偏差导致的误操作

这属于 AI 绕不过去的问题。有一次我让它“把商品按价格从低到高排序”,它直接点击了销量排序,因为销量排序也在同一个下拉菜单里,可能恰好离“价格”文字更近。我的排查方法是看报告里的操作轨迹图,发现它在排序弹窗里点偏了位置。最后我在指令里补充了筛选面板的特征:

点击 “排序” 下拉框 在弹出的面板中选择 “价格从低到高” 不要选择 “销量从高到低” 或 “综合推荐”

加了排除项之后,再没有出过错。这类经验其实很适合沉淀成团队内部的“指令模板库”:某个页面容易混淆的操作,配上一段固定的防御性指令,日后人人都能用。

5.4 常见问题速查表

现象可能原因解决思路
第一步就识别不到元素页面未加载完全指令开头加“等待页面加载完成”
点击了错误的元素指令描述含糊,多个相似目标增加位置、颜色、特征描述,加排除项
断言失败但肉眼判断成功断言时机太早,页面状态未更新在断言前加入一步页面状态确认
执行速度慢模型单次分析负载过高拆小步骤、降低截图尺寸、关闭多余标签页
无头模式偶发失败浏览器无头模式下渲染差异改为有头模式,或固定窗口大小
中文指令偶尔理解偏差模型对中文 UI 语境不敏感改为中英混合描述,或指定 UI 上真实文字

6. 这套方案能不能直接上生产:我的真实结论

6.1 说说我对“零编码”的真实看法

Midscene.js 确实降低了 UI 自动化的门槛,但“零编码”更多是愿景,不是全部真相。在真实团队落地时,还是会有人需要维护模型配置、处理复杂页面逻辑、排查 AI 误操作。所以我的判断是:零编码对业务描述层成立,对测试基础设施不成立。

如果你把 Midscene.js 当成一个“让测试用例表达层更贴近业务语言”的框架,那它非常适合用来缩短冒烟回归的时间;但如果你想彻底裁掉测试开发岗位,那大概率会翻车。AI 能理解意图,但谁来定义意图、谁来检查理解得对不对、页面结构变动后谁来更新指令模板,这些仍然需要懂测试的人来把关。

6.2 我推荐的落地方案:混合模式

我在当前团队的做法是:核心支付链路、库存流转链路这些“不能出错”的用例,仍然保留 Playwright 写的传统脚本,断言精确到数据层;业务冒烟、PC 端主流程探索、验收环境快速验证,这批用例全部切换到 Midscene.js 的自然语言指令。好处很明显:页面改版时,传统脚本最先崩,但冒烟用例往往不用改,AI 看一眼新页面就能继续执行。

建议团队里建立一个“指令模板仓库”,把前 20 个高频操作的优秀指令沉淀下来。新人进来不需要学 XPath,先读模板、跑用例,再慢慢理解底层原理,上手速度比传统方式快一个量级。

最后再分享一个小技巧:Midscene.js 生成的报告不要只看“通过/失败”两个字段,把 AI 的每一步思考轨迹截图保存下来,挂在缺陷单后面。这类证据在跨团队扯皮时特别管用,产品说“功能没问题”,你甩一张截图说“AI 点击的位置是错的”或者“页面元素实际没渲染出来”,问题归属马上清晰。

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

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

立即咨询