Midscene 使用 YAML格式实现AI自动化测试(附实战操作演示)
Midscene 提供基于 YAML 的轻量级自动化测试方案,无需维护大型测试框架。通过简单的 YAML 文件即可定义 Web 或 Android 自动化测试流程,支持 AI 驱动的交互操作(如点击、输入、断言等)。开发者只需配置 AI 模型服务(如 OpenAI API),安装命令行工具后即可运行 YAML 脚本。脚本结构清晰,包含目标环境配置(URL/设备)和任务流定义,支持网络等待、结果输出
一、使用 YAML 格式的自动化脚本
在大多数情况下,开发者编写自动化脚本只是为了执行一些简单流程,比如检查某些内容是否出现,或者验证某个关键用户路径是否可用。此时维护一个大型测试项目会显得毫无必要。
Midscene 提供了一种基于 .yaml
文件的自动化测试方法,这有助于你专注于编写流程,而不是测试框架。
这里有一个示例,通过阅读它的内容,你应该已经理解了它的工作原理。
web:
url: https://www.bing.com
tasks:
- name: 搜索天气
flow:
- ai: 搜索 "今日天气"
- sleep: 3000
- name: 检查结果
flow:
- aiAssert: 结果中展示了天气信息
:::info 样例项目
你可以在这里找到使用 YAML 脚本做自动化的样例项目
:::
配置 AI 模型服务
将你的模型配置写入环境变量。更多信息请查看 选择 AI 模型。
# 替换为你的 API Key
export OPENAI_API_KEY="sk-abcdefghijklmnopqrstuvwxyz"
# 可能需要更多配置,如模型名称、接入点等,请参考 《选择 AI 模型》文档
export OPENAI_BASE_URL="..."
或使用当前命令运行目录下的 .env
文件存储配置,Midscene 命令行工具在运行 yaml 脚本时会自动加载它
OPENAI_API_KEY="sk-abcdefghijklmnopqrstuvwxyz"
使用命令行工具
全局安装 @midscene/cli
npm i -g @midscene/cli
# 或在项目中安装
npm i @midscene/cli --save-dev
编写一个名为 bing-search.yaml
的文件来驱动 web 浏览器的自动化任务
web:
url: https://www.bing.com
tasks:
- name: 搜索天气
flow:
- ai: 搜索 "今日天气"
- sleep: 3000
- aiAssert: 结果显示天气信息
或者驱动安卓设备的自动化任务(需要使用 adb 连接安卓设备)
android:
# launch: https://www.bing.com
deviceId: s4ey59
tasks:
- name: 搜索天气
flow:
- ai: 打开浏览器并导航到 bing.com
- ai: 搜索 "今日天气"
- sleep: 3000
- aiAssert: 结果显示天气信息
运行脚本
midscene ./bing-search.yaml
# 或者如果你在项目中安装了 midscene
npx midscene ./bing-search.yaml
你将会看到脚本的执行进度和可视化运行报告文件。
脚本文件结构
脚本文件使用 YAML 格式来描述自动化任务。它定义了要操作的目标(如网页或安卓应用)以及一系列要执行的步骤。
一个标准的 .yaml
脚本文件包含 web
或 android
部分配置环境,以及一个 tasks
部分来定义自动化任务。
web:
url: https://www.bing.com
# tasks 部分定义了要执行的一系列步骤
tasks:
- name: 搜索天气
flow:
- ai: 搜索 "今日天气"
- sleep: 3000
- aiAssert: 结果显示天气信息
web
部分
web:
# 访问的 URL,必填。如果提供了 `serve` 参数,则提供相对路径
url: <url>
# 在本地路径下启动一个静态服务,可选
serve: <root-directory>
# 浏览器 UA,可选
userAgent: <ua>
# 浏览器视口宽度,可选,默认 1280
viewportWidth: <width>
# 浏览器视口高度,可选,默认 960
viewportHeight: <height>
# 浏览器设备像素比,可选,默认 1
deviceScaleFactor: <scale>
# JSON 格式的浏览器 Cookie 文件路径,可选
cookie: <path-to-cookie-file>
# 等待网络空闲的策略,可选
waitForNetworkIdle:
# 等待超时时间,可选,默认 2000ms
timeout: <ms>
# 是否在等待超时后继续,可选,默认 true
continueOnNetworkIdleError: <boolean>
# 输出 aiQuery/aiAssert 结果的 JSON 文件路径,可选
output: <path-to-output-file>
# 是否保存日志内容到 JSON 文件,可选,默认 `false`。如果为 true,保存到 `unstableLogContent.json` 文件中。如果为字符串,则保存到该字符串指定的路径中。日志内容的结构可能会在未来发生变化。
unstableLogContent: <boolean | path-to-unstable-log-file>
# 是否限制页面在当前 tab 打开,可选,默认 true
forceSameTabNavigation: <boolean>
# 桥接模式,可选,默认 false,可以为 'newTabWithUrl' 或 'currentTab'。更多详情请参阅后文
bridgeMode: false | 'newTabWithUrl' | 'currentTab'
# 是否在桥接断开时关闭新创建的标签页,可选,默认 false
closeNewTabsAfterDisconnect: <boolean>
# 是否忽略 HTTPS 证书错误,可选,默认 false
acceptInsecureCerts: <boolean>
# 在调用 aiAction 时发送给 AI 模型的背景知识,可选
aiActionContext: <string>
android
部分
android:
# 设备 ID,可选,默认使用第一个连接的设备
deviceId: <device-id>
# 启动 URL,可选,默认使用设备当前页面
launch: <url>
# 输出 aiQuery/aiAssert 结果的 JSON 文件路径,可选
output: <path-to-output-file>
tasks
部分
tasks
部分是一个数组,定义了脚本执行的步骤。记得在每个步骤前添加 -
符号,表明这些步骤是个数组。
flow
部分的接口与 API 几乎相同,除了一些参数的嵌套层级。
tasks:
- name: <name>
continueOnError: <boolean> # 可选,错误时是否继续执行下一个任务,默认 false
flow:
# 自动规划(Auto Planning, .ai)
# ----------------
# 执行一个交互,`ai` 是 `aiAction` 的简写方式
- ai: <prompt>
cacheable: <boolean> # 可选,当启用 [缓存功能](./caching.mdx) 时,是否允许缓存当前 API 调用结果。默认值为 True
# 这种用法与 `ai` 相同
- aiAction: <prompt>
cacheable: <boolean> # 可选,当启用 [缓存功能](./caching.mdx) 时,是否允许缓存当前 API 调用结果。默认值为 True
# 即时操作(Instant Action, .aiTap, .aiHover, .aiInput, .aiKeyboardPress, .aiScroll)
# ----------------
# 点击一个元素,用 prompt 描述元素位置
- aiTap: <prompt>
deepThink: <boolean> # 可选,是否使用深度思考(deepThink)来精确定位元素。默认值为 False
xpath: <xpath> # 可选,目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
cacheable: <boolean> # 可选,当启用 [缓存功能](./caching.mdx) 时,是否允许缓存当前 API 调用结果。默认值为 True
# 鼠标悬停一个元素,用 prompt 描述元素位置
- aiHover: <prompt>
deepThink: <boolean> # 可选,是否使用深度思考(deepThink)来精确定位元素。默认值为 False
xpath: <xpath> # 可选,目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
cacheable: <boolean> # 可选,当启用 [缓存功能](./caching.mdx) 时,是否允许缓存当前 API 调用结果。默认值为 True
# 输入文本到一个元素,用 prompt 描述元素位置
- aiInput: <输入框的最终文本内容>
locate: <prompt>
deepThink: <boolean> # 可选,是否使用深度思考(deepThink)来精确定位元素。默认值为 False
xpath: <xpath> # 可选,目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
cacheable: <boolean> # 可选,当启用 [缓存功能](./caching.mdx) 时,是否允许缓存当前 API 调用结果。默认值为 True
# 在元素上按下某个按键(如 Enter,Tab,Escape 等),用 prompt 描述元素位置
- aiKeyboardPress: <按键>
locate: <prompt>
deepThink: <boolean> # 可选,是否使用深度思考(deepThink)来精确定位元素。默认值为 False
xpath: <xpath> # 可选,目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
cacheable: <boolean> # 可选,当启用 [缓存功能](./caching.mdx) 时,是否允许缓存当前 API 调用结果。默认值为 True
# 全局滚动,或滚动 prompt 描述的元素
- aiScroll:
direction: 'up' # 或 'down' | 'left' | 'right'
scrollType: 'once' # 或 'untilTop' | 'untilBottom' | 'untilLeft' | 'untilRight'
distance: <number> # 可选,滚动距离,单位为像素
locate: <prompt> # 可选,执行滚动的元素
deepThink: <boolean> # 可选,是否使用深度思考(deepThink)来精确定位元素。默认值为 False
xpath: <xpath> # 可选,目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
cacheable: <boolean> # 可选,当启用 [缓存功能](./caching.mdx) 时,是否允许缓存当前 API 调用结果。默认值为 True
# 在报告文件中记录当前截图,并添加描述
- logScreenshot: <title> # 可选,截图的标题,如果未提供,则标题为 'untitled'
content: <content> # 可选,截图的描述
# 数据提取
# ----------------
# 执行一个查询,返回一个 JSON 对象
- aiQuery: <prompt> # 记得在提示词中描述输出结果的格式
name: <name> # 查询结果在 JSON 输出中的 key
# 更多 API
# ----------------
# 等待某个条件满足,并设置超时时间(ms,可选,默认 30000)
- aiWaitFor: <prompt>
timeout: <ms>
# 执行一个断言
- aiAssert: <prompt>
errorMessage: <error-message> # 可选,当断言失败时打印的错误信息。
name: <name> # 可选,给断言一个名称,会在 JSON 输出中作为 key 使用
# 等待一定时间
- sleep: <ms>
# 在 web 页面上下文中执行一段 JavaScript 代码
- javascript: <javascript>
name: <name> # 可选,给返回值一个名称,会在 JSON 输出中作为 key 使用
- name: <name>
flow:
# ...
命令行工具的高级用法
@midscene/cli
提供了灵活的方式来运行你的自动化脚本。
运行一个或多个脚本
你可以直接向 midscene
命令传递一个 .yaml
脚本文件或使用通配符模式来匹配多个 .yaml
。这是 --files
参数的简写方式。
# 运行单个脚本
midscene ./bing-search.yaml
# 使用通配符模式运行所有匹配的脚本
midscene './scripts/**/*.yaml'
命令行选项
命令行工具提供了一些选项来控制脚本的执行行为。
--files <file1> <file2> ...
: 指定要执行的脚本文件列表,文件将按顺序执行。支持通配符模式,遵循 glob 支持的语法。--concurrent <number>
: 设置并发执行的数量。默认为1
。--continue-on-error
: 如果设置了此选项,即使有脚本文件执行失败,也会继续运行余下的脚本文件。默认关闭。--share-browser-context
: 在所有脚本之间共享同一个浏览器上下文(例如 Cookies 和localStorage
)。这对于需要登录状态的连续测试非常有用,默认关闭。--summary <filename>
: 指定生成的 JSON 格式汇总报告文件的路径。--headed
: 在有图形界面的浏览器中运行脚本,而不是在无头模式下。--keep-window
: 脚本执行结束后保持浏览器窗口打开。此选项会自动启用--headed
参数。--config <filename>
: 指定配置文件,配置文件中的参数将作为命令行参数的默认值。--web.userAgent <ua>
: 设置浏览器 UA,这将覆盖所有脚本文件中的web.userAgent
参数。--web.viewportWidth <width>
: 设置浏览器视口宽度,这将覆盖所有脚本文件中的web.viewportWidth
参数。--web.viewportHeight <height>
: 设置浏览器视口高度,这将覆盖所有脚本文件中的web.viewportHeight
参数。--android.deviceId <device-id>
: 设置安卓设备 ID,这将覆盖所有脚本文件中的android.deviceId
参数。--dotenv-debug
: 设置 dotenv 的 debug 日志,默认关闭。--dotenv-override
: 设置 dotenv 是否覆盖同名的全局环境变量,默认关闭。
举例:
使用 --files
参数来指定文件顺序,并行执行
midscene --files ./login.yaml ./buy/*.yaml ./checkout.yaml
以 4 个并发数运行所有脚本,并在任一文件出错时继续
midscene --files './scripts/**/*.yaml' --concurrent 4 --continue-on-error
以文件形式编写命令行参数
你可以编写 YAML 格式的配置文件,然后通过 --config
来引用它。调用命令行工具时,命令行参数的优先级高于配置文件。
files:
- './scripts/login.yaml'
- './scripts/search.yaml'
- './scripts/**/*.yaml'
concurrent: 4
continueOnError: true
shareBrowserContext: true
使用方法:
midscene --config ./config.yaml
更多特性
在 .yaml
文件中使用环境变量
你可以在 .yaml
文件中使用环境变量,通过 ${variable-name}
的方式。
例如,如果你有一个 .env
文件,内容如下:
topic=weather today
你可以在 .yaml
文件中使用环境变量,如下所示:
#...
- ai: type ${topic} in input box
#...
运行在有界面(Headed)模式下
仅
web
场景下支持
‘headed’ 模式意味着浏览器窗口是可见的。默认情况下,脚本会在无界面模式下运行。
如果你想运行在有界面模式下,你可以使用 --headed
选项。此外,如果你想在脚本运行结束后保持浏览器窗口打开,你可以使用 --keep-window
选项。--keep-window
选项会自动开启 --headed
模式。
headed 模式会消耗更多资源,所以建议你仅在本地使用。
# 运行在有界面模式下
midscene /path/to/yaml --headed
# 运行在有界面模式下,并在结束后保持浏览器窗口打开
midscene /path/to/yaml --keep-window
使用桥接模式
仅
web
场景下支持
通过使用桥接模式,你可以利用 YAML 脚本在已有的桌面浏览器上执行自动化。这对于需要复用 Cookies、插件和页面状态,或者需要人工与自动化脚本交互的情况非常有用。
使用桥接模式,你需要先安装 Chrome 扩展,然后在 target
部分使用以下配置:
web:
url: https://www.bing.com
+ bridgeMode: newTabWithUrl
请参阅 通过 Chrome 扩展桥接模式 了解更多详细信息。
使用 JavaScript 运行 YAML 脚本
你也可以使用 JavaScript 运行 YAML 脚本,调用 Agent 上的 runYaml
方法即可。注意,这种方法只会执行 YAML 脚本中的 tasks
部分。
分析命令行工具的运行结果
执行完成后,会在输出目录中生成以下文件:
- 由
--summary
选项指定的文件路径(默认是index.json
),包含所有文件的执行状态和统计信息 - 各个 YAML 文件的独立执行结果(JSON 格式)
- 各个文件的可视化报告(HTML 格式)
配置 dotenv 的默认行为
Midscene 使用 dotenv
加载 .env
文件中的环境变量。
关闭 dotenv 的 debug 日志
默认情况下,Midscene 会打印 dotenv 的 debug 信息,如果你不想看到这些信息,你可以使用 --dotenv-debug
选项关闭。
midscene /path/to/yaml --dotenv-debug=false
使用 .env 中的环境变量覆盖同名的全局环境变量
默认情况下,dotenv
不会覆盖.env
文件中同名的全局环境变量。如果希望覆盖,你可以使用 --dotenv-override
选项。
midscene /path/to/yaml --dotenv-override=true
FAQ
如何从 Chrome 中获取 JSON 格式的 Cookies?
你可以使用这个 Chrome 扩展 来导出 Cookies 为 JSON 格式。
如何打开 dotenv 的 debug 日志?
Midscene 使用 dotenv
加载 .env
文件中的环境变量。你可以使用 --dotenv-debug
选项来打开 dotenv 的 debug 日志。
midscene /path/to/yaml --dotenv-debug=true
二、 实战演练
项目目录结构如下:
演示的用例代码
- 打开支付窗链接点击立即支付跳转二维码界面支付金额
web:
url: https://vip.wps.cn/vcl_svr/static/docerpay?app=wpsoffice&version=12.9.0.21714&csource=pc_docer_resume&position=newpri_docermall_mywps_zdsearch_resume_startcv_headopen&sku_key=package_resume_10&payconfig=pc_docer_resume_new_vip_expire&collect_key=b855f64b3f93efe0d7cbfbb343672cbc&biz_content=eyJta19rZXkiOiIxTWdTRWhwcW1oblJSeW1zUTFoODJiVGxiVmJjWnlwY3BMbzh4cyJ9&biz_pay=eyJwYXlfa2V5IjoiYjg1NWY2NGIzZjkzZWZlMGQ3Y2JmYmIzNDM2NzJjYmMifQ%3D%3D&privilege_ids=resume_package_new&channel=1.1&component=wpsoffice&bunifypay=true&is_large_size=true&client_pay_version=202301&new_vip=1#/
cookie: account.wps.cn_cookies.json
timeout: 10000 # 全局超时设置(毫秒)
tasks:
- name: 简历支付流程检查
retry: 1 # 失败后重试1次,总共最多执行2次
retryInterval: 2000 # 重试间隔2秒
description: 使用AI判断处理弹窗
flow:
# 页面加载等待
- sleep: 2000
description: 等待2秒确保弹窗有足够时间出现
# 合并弹窗检测和处理为一个步骤,由AI判断是否需要操作
- ai: 首先检查页面上是否存在任何弹窗:
1. 如果没有弹窗,不执行任何操作
2. 如果有弹窗,按以下优先级处理:
- 点击弹窗右上角的关闭按钮(X图标)
- 等待500ms检查,若未关闭则点击"开心收下"按钮
- 再等待500ms检查,若仍未关闭则点击"使用大额券"按钮
- 最后等待1000ms确认
retry: 1
retryInterval: 1000
description: 由AI自主判断是否存在弹窗并决定是否处理
# 点击立即支付按钮
- ai: 找到并点击"立即支付"按钮
retry: 2
retryInterval: 1000
# 处理可能的支付确认弹窗
- ai: 检查是否出现"同意并支付"弹窗,若有则点击,若无则不操作
retry: 0
timeout: 2000
# 等待支付页面加载
- sleep: 2000
# 验证支付页面内容
- aiAssert: 页面必须包含"支付金额"或"支付宝"文案
timeout: 5000
retry: 1
retryInterval: 1000
- .env 文件的内容
OPENAI_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
OPENAI_API_KEY="sk-xxx" #这里写自己使用模块的api_key 我这里使用的是通义千问
MIDSCENE_MODEL_NAME="qwen-vl-max-latest"
MIDSCENE_USE_QWEN_VL=1
-
获取对应网址的cookie
安装Chrome浏览器插件 Get cookies.txt LOCALLY ,链接地址: Get cookies.txt LOCALLY
输入目标网站的url,点击export 导出json文件后复制到项目根目录,在自动化脚本使用时cookie: [刚刚导出的cookie文件路径及名称] -
config.yaml 文件内容:
# Example batch execution index YAML file
# This demonstrates how to use the multi-YAML file batch execution feature
# Concurrency settings (default: 1 for sequential execution)
concurrent: 4
# Continue execution even if one file fails (default: false)
continueOnError: true
# Summary output file
summary: "./output/custom-summary.json"
# Global web environment configuration (applied to all files)
web:
# All individual YAML files will inherit these settings
viewportWidth: 1280
viewportHeight: 720
# bridgeMode: "newTabWithUrl"
# Output directory for individual files (will be combined with file-specific paths)
# Global android environment configuration (if needed)
# android:
# deviceId: "emulator-5554"
# Execution order using glob patterns
files:
- "./script/*.yaml"
- 命令行运行用例
midscene --config ./config.yml --dotenv-override=true --share-browser-context
- 运行结果如下:
更多推荐
所有评论(0)