一、使用 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 脚本文件包含 webandroid 部分配置环境,以及一个 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 
  • 运行结果如下:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐