使用 YAML 格式的自动化脚本

在大多数情况下,开发者编写自动化脚本只是为了执行一些简单流程,比如检查某些内容是否出现,或者验证某个关键用户路径是否可用。此时维护一个大型测试项目会显得毫无必要。

⁠Midscene 提供了一种基于 .yaml 文件的自动化测试方法,这有助于你专注于编写流程,而不是测试框架。

这里有一个示例,通过阅读它的内容,你应该已经理解了它的工作原理。

web:
  url: https://www.bing.com

tasks:
  - name: 搜索天气
    flow:
      - ai: 搜索 "今日天气"
      - sleep: 3000

  - name: 检查结果
    flow:
      - aiAssert: 结果中展示了天气信息
样例项目

你可以在这里找到使用 YAML 脚本做自动化的样例项目

配置 AI 模型服务

将你的模型配置写入环境变量,可参考 模型策略 了解更多细节。

export MIDSCENE_MODEL_BASE_URL="https://替换为你的模型服务地址/v1"
export MIDSCENE_MODEL_API_KEY="替换为你的 API Key"
export MIDSCENE_MODEL_NAME="替换为你的模型名称"
export MIDSCENE_MODEL_FAMILY="替换为你的模型系列"

更多配置信息请参考 模型策略模型配置

如果需要通过命令行执行 YAML 工作流,请查看 命令行工具,了解安装、.env 支持以及 midscene 命令的用法。

脚本文件结构

脚本文件使用 YAML 格式来描述自动化任务。它定义了要操作的目标(如网页或安卓应用)以及一系列要执行的步骤。

一个标准的 .yaml 脚本文件包含 webandroidios 部分配置环境,可选的 agent 部分配置 AI Agent 行为,以及一个 tasks 部分来定义自动化任务。

web:
  url: https://www.bing.com

# tasks 部分定义了要执行的一系列步骤
tasks:
  - name: 搜索天气
    flow:
      - ai: 搜索 "今日天气"
      - sleep: 3000
      - aiAssert: 结果显示天气信息

agent 部分

agent 部分用于配置 AI Agent 的行为和测试报告相关选项。所有字段都是可选的。

# AI agent 配置
agent:
  # 测试标识符,用于报告和缓存识别,可选
  testId: <string>

  # 报告组名称,可选
  groupName: <string>

  # 报告组描述,可选
  groupDescription: <string>

  # 是否生成测试报告,可选,默认 true
  generateReport: <boolean>

  # 是否自动打印报告消息,可选,默认 true
  autoPrintReportMsg: <boolean>

  # 自定义报告文件名,可选
  reportFileName: <string>

  # AI 最大重规划循环次数,可选,默认 20(UI-TARS 模型为 40)
  replanningCycleLimit: <number>

  # 在调用 aiAct 时发送给 AI 模型的背景知识,可选
  aiActContext: <string>
  # 兼容的旧字段(aiActionContext)仍可使用,但不推荐

  # 缓存配置,可选
  cache:
    # 缓存策略,可选,可选值:'read-only' | 'read-write' | 'write-only'
    strategy: <string>
    # 缓存 ID,必填
    id: <string>
Agent 配置说明
  • 适用环境:Web、iOS 和 Android 环境都支持 agent 配置
  • testId 优先级:CLI 参数 > YAML agent.testId > 文件名
  • aiActContext:为 AI 模型提供背景知识,例如处理弹窗、业务介绍等常见场景。兼容旧字段(见注释),但不建议新脚本继续使用。
  • 缓存配置:详细用法请参考 缓存功能文档

使用示例

# agent 配置,适用于所有环境
agent:
  testId: "checkout-test"
  groupName: "E2E 测试套件"
  groupDescription: "完整的购物流程测试"
  generateReport: true
  autoPrintReportMsg: false
  reportFileName: "checkout-report"
  replanningCycleLimit: 30
  aiActContext: "如果出现弹窗,点击同意。如果出现登录页面,跳过它。"
  cache:
    id: "checkout-cache"
    strategy: "read-write"

# iOS 环境配置
ios:
  launch: https://www.bing.com
  wdaPort: 8100

# 或 Android 环境配置
android:
  deviceId: s4ey59
  launch: https://www.bing.com

tasks:
  - name: 搜索天气
    flow:
      - ai: 搜索 "今日天气"
      - 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>

  # 自定义 Chrome 启动参数(仅 Puppeteer 模式,不支持桥接模式),可选
  # 用于自定义 Chrome 浏览器行为,例如禁用第三方 Cookie 阻止
  # ⚠️ 安全警告:某些参数(如 --no-sandbox、--disable-web-security)可能降低浏览器安全性
  # 仅在受控的测试环境中使用
  chromeArgs:
    - '--disable-features=ThirdPartyCookiePhaseout'
    - '--disable-features=SameSiteByDefaultCookies'
    - '--window-size=1920,1080'

android 部分

android:
  # 设备 ID,可选,默认使用第一个连接的设备
  deviceId: <device-id>

  # 启动 URL,可选,默认使用设备当前页面
  launch: <url>

  # 输出 aiQuery/aiAssert 结果的 JSON 文件路径,可选
  output: <path-to-output-file>

  # 其他 AndroidDevice 构造函数支持的所有选项
  # 例如:androidAdbPath, remoteAdbHost, remoteAdbPort,
  # imeStrategy, displayId, autoDismissKeyboard, keyboardDismissStrategy,
  # screenshotResizeScale, alwaysRefreshScreenInfo 等
  # 完整配置项请参考 AndroidDevice 的构造函数文档
查看完整的 Android 配置项

YAML 脚本现在支持 AndroidDevice 构造函数的所有配置选项。完整的配置项列表请参考 Android 集成文档中的 AndroidDevice 构造函数

Android 平台特定动作

Android 平台提供了一些特定的动作,可以在 YAML 脚本的 flow 中使用:

runAdbShell - 执行 ADB Shell 命令

在 Android 设备上执行 ADB shell 命令。

android:
  deviceId: 'test-device'

tasks:
  - name: 清除应用数据
    flow:
      - runAdbShell: 'pm clear com.example.app'

  - name: 获取电池信息
    flow:
      - runAdbShell: 'dumpsys battery'

常用 ADB Shell 命令:

  • pm clear <package> - 清除应用数据
  • dumpsys battery - 获取电池信息
  • dumpsys window - 获取窗口信息
  • settings get secure android_id - 获取设备 ID
  • input keyevent <keycode> - 发送按键事件

launch - 启动应用或 URL

启动 Android 应用或打开 URL。

android:
  deviceId: 'test-device'

tasks:
  - name: 启动设置应用
    flow:
      - launch: com.android.settings

  - name: 打开网页
    flow:
      - launch: https://www.example.com

ios 部分

ios:
  # WebDriverAgent 端口,可选,默认 8100
  wdaPort: <port>

  # WebDriverAgent 主机地址,可选,默认 localhost
  wdaHost: <host>

  # 是否自动关闭键盘,可选,默认 false
  autoDismissKeyboard: <boolean>

  # 启动 URL 或应用包名,可选,默认使用设备当前页面
  launch: <url-or-bundle-id>

  # 输出 aiQuery/aiAssert 结果的 JSON 文件路径,可选
  output: <path-to-output-file>

  # 是否保存日志内容到 JSON 文件,可选,默认 `false`。如果为 true,保存到 `unstableLogContent.json` 文件中。如果为字符串,则保存到该字符串指定的路径中。日志内容的结构可能会在未来发生变化。
  unstableLogContent: <boolean | path-to-unstable-log-file>

  # 其他 IOSDevice 构造函数支持的所有选项
  # 完整配置项请参考 IOSDevice 的构造函数文档
查看完整的 iOS 配置项

YAML 脚本现在支持 IOSDevice 构造函数的所有配置选项。完整的配置项列表请参考 iOS 集成文档中的 IOSDevice 构造函数

iOS 平台特定动作

iOS 平台提供了一些特定的动作,可以在 YAML 脚本的 flow 中使用:

runWdaRequest - 执行 WebDriverAgent API 请求

在 iOS 设备上直接执行 WebDriverAgent API 请求。

ios:
  launch: 'com.apple.mobilesafari'

tasks:
  - name: 通过 WDA 按下主屏幕按钮
    flow:
      - runWdaRequest:
          method: POST
          endpoint: /session/test/wda/pressButton
          data:
            name: home

  - name: 获取设备信息
    flow:
      - runWdaRequest:
          method: GET
          endpoint: /wda/device/info

参数:

  • method(字符串,必需):HTTP 方法(GET、POST、DELETE 等)
  • endpoint(字符串,必需):WebDriverAgent API 端点
  • data(任意类型,可选):请求体数据

常用 WebDriverAgent 端点:

  • /wda/screen - 获取屏幕信息
  • /wda/device/info - 获取设备信息
  • /session/{sessionId}/wda/pressButton - 按硬件按钮
  • /session/{sessionId}/wda/apps/launch - 启动应用
  • /session/{sessionId}/wda/apps/activate - 激活应用

launch - 启动应用或 URL

启动 iOS 应用或打开 URL。

ios:
  wdaPort: 8100

tasks:
  - name: 启动设置应用
    flow:
      - launch: com.apple.Preferences

  - name: 打开网页
    flow:
      - launch: https://www.example.com

tasks 部分

tasks 部分是一个数组,定义了脚本执行的步骤。记得在每个步骤前添加 - 符号,表明这些步骤是个数组。

flow 部分的接口与 API 几乎相同,除了一些参数的嵌套层级。

tasks:
  - name: <name>
    continueOnError: <boolean> # 可选,错误时是否继续执行下一个任务,默认 false
    flow:
      # 自动规划(Auto Planning, .ai)
      # ----------------

      # 执行一个交互,`ai` 是 `aiAct` 的简写方式
      - ai: <prompt>
        cacheable: <boolean> # 可选,当启用 [缓存功能](./caching.mdx) 时,是否允许缓存当前 API 调用结果。默认值为 True
        deepThink: <boolean> # 可选,当模型支持时(取决于 MIDSCENE_MODEL_FAMILY),开启规划阶段的深度思考能力。默认值为 undefined,跟随模型服务商的默认策略。

      # 这种用法与 `ai` 相同
      # 注意:在之前版本中也被写作 `aiAction`,当前版本兼容两种写法
      - aiAct: <prompt>
        cacheable: <boolean> # 可选,当启用 [缓存功能](./caching.mdx) 时,是否允许缓存当前 API 调用结果。默认值为 True
        deepThink: <boolean> # 可选,当模型支持时(取决于 MIDSCENE_MODEL_FAMILY),开启规划阶段的深度思考能力。默认值为 undefined,跟随模型服务商的默认策略。

      # 即时操作(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: <prompt> # 要输入文本的元素
        value: <输入框的最终文本内容>
        deepThink: <boolean> # 可选,是否使用深度思考(deepThink)来精确定位元素。默认值为 False
        xpath: <xpath> # 可选,目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空
        cacheable: <boolean> # 可选,当启用 [缓存功能](./caching.mdx) 时,是否允许缓存当前 API 调用结果。默认值为 True

      # 在元素上按下某个按键(如 Enter,Tab,Escape 等),用 prompt 描述元素位置
      - aiKeyboardPress: <prompt> # 要按键的目标元素
        keyName: <按键>
        deepThink: <boolean> # 可选,是否使用深度思考(deepThink)来精确定位元素。默认值为 False
        xpath: <xpath> # 可选,目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空

        cacheable: <boolean> # 可选,当启用 [缓存功能](./caching.mdx) 时,是否允许缓存当前 API 调用结果。默认值为 True

      # 全局滚动,或滚动 prompt 描述的元素
      - aiScroll: <prompt> # 可选,执行滚动的元素
        scrollType: 'singleAction' # 或 'scrollToBottom' | 'scrollToTop' | 'scrollToRight' | 'scrollToLeft',默认值为 'singleAction'
        direction: 'down' # 或 'up' | 'left' | 'right',默认值为 'down'。仅在 scrollType 为 singleAction 时生效
        distance: <number> # 可选,滚动距离,单位为像素。设置为 null 表示由 Midscene 自动决定。
        deepThink: <boolean> # 可选,是否使用深度思考(deepThink)来精确定位元素。默认值为 False
        xpath: <xpath> # 可选,目标元素的 xpath 路径,用于执行当前操作。如果提供了这个 xpath,Midscene 会优先使用该 xpath 来找到元素,然后依次使用缓存和 AI 模型。默认值为空

        cacheable: <boolean> # 可选,当启用 [缓存功能](./caching.mdx) 时,是否允许缓存当前 API 调用结果。默认值为 True

      # 在报告文件中记录当前截图,并添加描述
      - recordToReport: <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:
      # ...

使用图像提示

对于支持在提示词中附带图像的步骤(参见 API 参考),可以把提示词改写为对象,并通过设置 images 字段(一个包含 nameurl 的对象数组)来附加图像。该对象包含以下字段:

  • prompt:发送给模型的文本描述。
  • images(可选):提示词引用的参考图像,每一项需要提供 nameurl
  • convertHttpImage2Base64(可选):在图片链接无法公开访问时,将 HTTP 链接转换为 Base64 再发送给模型。

图片 URL 可以是本地路径、Base64 字符串或远程链接。如果图片链接无法被模型访问,请设置 convertHttpImage2Base64: true,Midscene 会将图像下载后以 Base64 字符串的形式发送给模型。

对于 aiTapaiHoveraiDoubleClickaiRightClick 等交互操作,请把文本和图像配置写在 locate 字段中。

tasks:
  - name: 校验品牌一致性
    flow:
      - aiHover:
          locate:
            prompt: 将鼠标移动到包含 GitHub 标志的区域。
            images:
              - name: GitHub 标志
                url: https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png
            convertHttpImage2Base64: true

      - aiTap:
          locate:
            prompt: 点击包含 GitHub 标志的区域。
            images:
              - name: GitHub 标志
                url: https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png
            convertHttpImage2Base64: true

对于视觉问答类步骤,例如 aiAskaiQueryaiBooleanaiNumberaiStringaiAssert,可以直接设置 promptimages 字段。

tasks:
  - name: 校验品牌一致性
    flow:
      - aiAssert:
          prompt: 判断页面上是否出现该图像。
          images:
            - name: 目标标志
              url: https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png
          convertHttpImage2Base64: true

注意事项

agent.runYaml 只会解析 tasks 字段

当使用 agent.runYaml() api 时,YAML 文件中只有 tasks 字段会被解析和执行。

因为此时 agent 已经在 js 脚本中完成初始化,无法根据 YAML 中的 agent 配置再次初始化。