• 简体中文
  • 创建和使用测试项目

    本文从创建项目开始,介绍如何运行示例、了解可用的测试操作、编写 YAML 用例和查看运行结果。已有项目的读者可以直接从了解可用的测试操作开始。

    整体设计见 Midscene Test 概览。业务操作的实现方式见编写自定义 Node,运行环境和执行参数见配置测试项目

    创建项目

    1. 生成项目文件并安装依赖

    准备 Node.js ^20.19.0 || ^22.12.0 || >=24.0.0 和 pnpm,然后创建 Web 测试项目:

    pnpm dlx @midscene/test create my-tests --platform web --package-manager pnpm
    cd my-tests

    按提示安装依赖。命令会生成平台配置、示例用例和 Node 说明书,主要文件如下:

    my-tests/
    ├── cases/example.yaml          # 示例用例
    ├── midscene.config.ts          # 平台配置与 Node 注册
    ├── midscene-node-reference.md  # 安装后自动生成的 Node 说明书
    ├── package.json
    ├── tsconfig.json
    ├── .env.example
    └── README.md

    创建项目和生成说明书不会运行测试,因此这一步不需要模型 API Key、浏览器或设备。完整参数可通过 pnpm dlx @midscene/test create --help 查看。

    安装恢复

    如果跳过安装或安装失败,可以进入项目目录执行 pnpm install。需要重新生成 Node 说明书时,执行 pnpm run nodes

    2. 配置模型与运行环境

    .env.example 复制为 .env,按照模型配置填写模型名称、服务地址和 API Key。

    Web 项目还需要安装 Chromium:

    pnpm exec playwright install chromium

    其他平台在创建时修改 --platform,并完成对应准备:

    平台参数值运行前准备环境配置指南
    Androidandroid连接设备,可用 ANDROID_DEVICE_ID 选择设备。配置指南
    iOSios启动 WebDriverAgent,配置 WDA_HOSTWDA_PORT配置指南
    HarmonyOSharmonyhdc list targets 检查连接,可用 HARMONY_DEVICE_ID 选择设备;PATH 中没有 HDC 时设置 HDC_HOME配置指南
    桌面端computer安装依赖并授予权限,可用 COMPUTER_DISPLAY_ID 选择显示器。无界面 Linux 还需安装 Xvfb 并启用 MIDSCENE_COMPUTER_HEADLESS_LINUX配置指南

    3. 运行生成的示例

    pnpm test

    Web 示例打开 example.com 并检查页面标题。桌面端示例通过 aiAsk 查看当前屏幕;移动端示例先执行 home,再执行 aiAsk

    运行结束后,可以查看用例运行报告,了解各用例及步骤的执行结果。随后可以修改 cases/example.yaml,编写自己的用例。

    了解可用的测试操作

    内置操作与按需扩展

    Midscene Test 将每一种可在 YAML 中调用的能力称为 Node(节点)

    Node 既可以在用例的 steps 中调用,也可以在 beforeEachafterEach生命周期钩子中调用,写法相同。

    所有平台都提供以下常用能力:aiAct 根据自然语言操作界面,aiAssert 检查预期结果,wait 等待指定时长。

    在这些通用能力之外,Midscene 还为各个平台预置了专用操作。例如:

    • WebgotoUrl 打开网页、setCookies 设置 Cookie、setViewportSize 调整浏览器视口大小。
    • Androidlaunch 启动应用、back 返回上一页、home 返回主屏幕、runAdbShell 执行 ADB 命令。

    创建项目时,脚手架会根据选择的平台注册相应的 Node。开发者也可以按需扩展,例如通过业务接口准备测试订单,详见注册自定义业务 Node

    查看项目的操作说明书

    打开项目中的 midscene-node-reference.md,可以查看当前可用的 Node、各自的用途和参数写法。这份说明书在安装时自动生成,人类和 AI Agent 都可以根据它编写 YAML 用例。

    修改 Node 注册配置后,重新生成说明书:

    pnpm run nodes

    编写 YAML 测试用例

    一个典型的 YAML 文件

    一个 YAML 文件可以包含多个测试用例,以及用例执行前后的准备和清理步骤。下面以商城搜索为例:每次运行用例前打开首页,再搜索商品并检查结果。请将网址和商品名称替换为你的业务内容。

    beforeEach:
      - gotoUrl: https://your-shop.example
    
    cases:
      - name: 搜索商品
        steps:
          - aiAct: 在搜索框输入“马克杯”,点击搜索按钮
          - aiAssert: 搜索结果中包含马克杯

    文件中各部分的含义如下:

    • beforeEach:每个用例执行前运行的步骤。它是可选的,适合打开页面、重置状态等准备操作。其他钩子见执行生命周期
    • cases:测试用例列表,至少包含一个用例。需要增加用例时,在列表中添加新的 namesteps
    • name:用例名称,用于在运行结果中识别这个用例。
    • steps:按顺序执行的步骤,至少包含一个步骤。每个步骤只能调用一个 Node,冒号后填写调用参数。

    文档中把整个 YAML 文件称为 Workflow Document(工作流文档),把一个用例称为 Case,把一次 Node 调用称为 Step(步骤)。

    示例使用字符串简写:gotoUrl 后的文本作为 urlaiActaiAssert 后的文本作为 prompt。需要传入更多参数时,可以使用下文的对象写法。是否支持简写,以项目的 Node 说明书为准。

    关键 Node:操作与断言

    日常用例主要通过 aiAct 描述操作,通过 aiAssert 检查结果:

    Node用途编写方式
    aiAct根据自然语言完成界面操作,可以包含多个动作。描述要做什么,例如“搜索马克杯,将第一个商品加入购物车”。
    aiAssert检查界面是否满足预期;不满足时,步骤失败。描述可观察的结果,例如“购物车中有一件马克杯”。
    aiTap点击一个指定目标。描述要点击的元素,例如“页面右上角的购物车图标”。

    操作完成不代表测试通过,应使用 aiAssert 明确检查预期结果。需要自定义断言失败信息时,可以展开参数:

    steps:
      - aiAct: 搜索马克杯,将第一个商品加入购物车
      - aiTap: 页面右上角的购物车图标
      - aiAssert:
          prompt: 购物车中有一件马克杯
          message: 加购后购物车内容不符合预期

    其他 Node 的调用模式

    平台操作和自定义业务 Node 使用相同的调用结构:Node 名称下面填写参数。下面展示多参数和无参数两种常见形式,这些片段可以放入用例的 steps 中:

    steps:
      - setViewportSize:
          width: 1440
          height: 900
      - clearCookies: {}

    setViewportSize 接收一个参数对象;clearCookies 无需参数,使用 {}。这两个 Node 由 Web 项目提供。移动端、桌面端以及团队自定义 Node 的可用范围和参数,以当前项目的说明书为准。

    例如,如果团队注册了创建订单的 order.create,就可以这样调用。该 Node 是业务扩展示例,使用前需要在项目中实现和注册:

    steps:
      - order.create:
          sku: midscene-mug
          quantity: 2

    参数还可以包含嵌套对象或数组。比如给 aiAct 传入参考图时,文字和图片共同组成 promptoptions 则单独填写:

    steps:
      - aiAct:
          prompt:
            prompt: 按照参考图完成设置
            images:
              - name: 目标状态
                url: ./fixtures/target.png
          options:
            deepLocate: true

    设置超时和错误处理

    $ 用于设置由 Midscene Test 控制的 Step 参数。Midscene Test 不会将这些参数传入 Node 的 input

    steps:
      - order.create:
          sku: midscene-mug
          quantity: 1
          $:
            timeout: 30000
            continue-on-error: true

    支持以下两个字段:

    • timeout:Step 的超时时间,单位为毫秒。
    • continue-on-error:设为 true 后,即使 Step 失败,Midscene Test 也会继续执行当前阶段的后续 Step。默认值为 false

    continue-on-error 只控制 Midscene Test 是否继续执行。只要有 Step 失败,Case 的最终状态就是 failed

    使用 Project 变量与环境变量

    Midscene Test 会在执行前递归解析 Node input:

    steps:
      - launch:
          uri: ${appUri}
      - api.createOrder:
          baseURL: ${{TEST_API_BASE_URL}}
          payload:
            count: ${orderCount}
    • ${name} 读取当前 Execution Project 的 variables;独占整个标量时保留原始 JSON 类型。
    • ${{ENV_NAME}} 读取环境变量,结果始终是字符串。
    • 对象或数组变量可以作为完整值使用,但不能嵌入更长的字符串。
    • 未定义变量会在收集阶段失败。变量只解析 Node input,不解析 $

    Workflow YAML 不提供 setsaveAs 或 Step 输出表达式。每个 Step 独立运行,不会自动接收前序 Step 的结果。如需共享必要信息,请通过 Execution Project 的 context 显式提供。

    使用 tags 筛选 Case

    cases:
      - name: Android 冒烟下单
        tags: [smoke, android]
        steps:
          - aiAct: 完成下单

    框架维护者在每个 Execution Project 中配置 tags.includetags.exclude。exclude 始终优先;include 非空时,Case 命中任意一个 include tag 即会被选中。

    定义执行生命周期

    准备与清理步骤

    生命周期钩子用于在用例执行前后准备环境、重置状态或清理数据。四个钩子都是可选的,与 cases 同级;其中的步骤和用例 steps 使用相同的 Node 调用写法。

    钩子执行时机常见用途
    beforeAll当前 YAML 文件的所有用例开始前,执行一次准备本文件共用的测试数据
    beforeEach每个用例的每次执行开始前,包括重试打开页面、重置用例状态
    afterEach每个用例的每次执行结束后,包括失败和重试清理本次用例创建的数据
    afterAll当前 YAML 文件的所有用例结束后,执行一次清理本文件共用的测试数据

    下面的 Web 示例在每个用例开始前打开商城首页,结束后清除 Cookie。data.preparedata.cleanup 是需要由项目实现和注册的自定义 Node,分别准备和清理测试商品;gotoUrlclearCookiesaiActaiAssert 是内置 Node。请替换示例网址和商品名称。

    beforeAll:
      - data.prepare: 准备马克杯和水壶两种测试商品
    
    beforeEach:
      - gotoUrl: https://your-shop.example
    
    cases:
      - name: 搜索马克杯
        steps:
          - aiAct: 搜索马克杯
          - aiAssert: 搜索结果中包含马克杯
    
      - name: 搜索水壶
        steps:
          - aiAct: 搜索水壶
          - aiAssert: 搜索结果中包含水壶
    
    afterEach:
      - clearCookies: {}
    
    afterAll:
      - data.cleanup: 删除本文件准备的测试商品

    执行顺序与重试

    没有失败或重试时,上面文件的执行顺序为:

    beforeAll
      用例 1:beforeEach → steps → afterEach
      用例 2:beforeEach → steps → afterEach
    afterAll

    配置重试后,失败的用例会在重试次数范围内重新执行 beforeEach → steps → afterEach,再继续后续用例。重试不会重新执行 beforeAllafterAll 仍在文件结束时运行一次。

    失败时如何执行

    • beforeEach 失败:跳过当前用例的 steps,仍执行 afterEach
    • 用例的 steps 失败:仍执行 afterEach
    • beforeAll 失败:当前文件的用例标记为 not-run,仍执行 afterAll
    • afterEachafterAll 失败:记录为失败,不会因为它是清理步骤而忽略错误。

    默认情况下,一个阶段中的步骤失败后,该阶段的剩余步骤不再执行。需要继续执行同阶段的后续步骤时,可设置 continue-on-error;这不会把失败结果改为成功。清理 Node 应能处理准备步骤只完成了一部分的情况。

    项目 setup 管理浏览器和 Agent 等资源,详见管理项目资源。Node 内部创建的资源,见资源的生命周期与清理

    运行测试

    在项目根目录下,使用以下命令运行 YAML 测试用例:

    pnpm exec midscene-test

    指定用例目录或文件

    生成的项目通过 files.include 选择 cases/ 下的 .yaml.yml 文件。未配置 files 时,Midscene Test 会递归查找测试目录下的 YAML 文件,自动忽略 node_modules.git

    如果你只想执行特定目录或特定用例文件,可以将其作为参数传入:

    # 运行指定目录下的所有用例
    pnpm exec midscene-test ./cases/smoke
    
    # 运行单个指定的用例文件
    pnpm exec midscene-test ./cases/order.yaml

    过滤运行目标与配置文件

    如果项目配置了多个运行平台或环境,你可以指定仅运行特定的 Execution Project,或者通过命令行指定自定义配置文件:

    # 只运行名为 android-smoke 和 ios-regression 的 Execution Project
    pnpm exec midscene-test --project android-smoke --project ios-regression
    
    # 使用指定的配置文件运行测试
    pnpm exec midscene-test --config ./config/midscene.config.ts

    查看某个 Execution Project(执行项目)的操作说明书时,也可以指定 --project

    pnpm exec midscene-test nodes --project android-smoke

    当发生用例运行失败、文档解析失败或收集阶段发生错误时,CLI 会返回退出码 1

    查看测试结果

    每次运行结束后,CLI 会打印执行结果和 Report: 路径。打开 HTML 报告,即可查看 Project、Case、重试记录、截图、Step 输入输出、错误及关联的 Agent 执行详情。

    报告默认保存在:

    midscene_run/report/test-run-<runId>.html

    使用外置截图时,报告是包含 index.htmlscreenshots/ 的目录,复制或上传时需保留整个目录。

    通过 midscene.config.ts 中的 output.reportDir 可以修改报告目录。

    用例设计约定

    Midscene Test 通过顺序执行和显式共享状态,让每个 Node 的输入、执行上下文和依赖关系更清晰。YAML 用例遵循以下设计:

    • 按声明顺序执行:YAML 描述线性的测试步骤,不引入 DAG、分支或循环语法。对于需要复杂编排的场景,建议在更上层构建 YAML 脚本生成能力,将编排结果生成为明确的步骤序列,再交给 Midscene Test 执行。
    • 每个节点是无状态的:每次 Node 调用依赖当前声明的输入和项目显式提供的上下文,不会自动继承前序 Step 的输出。YAML 不提供跨步骤或跨用例的输出引用语法;需要共享业务状态时,应在自定义 Node 中读取和更新项目 context,并实现相应的业务逻辑。

    例如,下面的断言使用“上一步的图标”指代目标,依赖前一步的指令上下文,是错误的写法:

    steps:
      - aiAct: 点击商品详情页的收藏星标,将其点亮
      # 错误:断言不会继承前一步的指令上下文,无法通过“上一步的图标”明确识别目标。
      - aiAssert: 上一步的图标已经点亮

    应在断言中明确写出检查对象和预期状态,让这条断言本身就能表达完整的检查条件:

    steps:
      - aiAct: 点击商品详情页的收藏星标,将其点亮
      - aiAssert: 商品详情页的收藏星标处于点亮状态

    界面状态会保留前一步操作的结果,但后续 Node 的指令应独立描述目标,不依赖“上一步”“刚才那个”等指代。

    接下来

    添加业务 Node 和共享运行数据,见编写自定义 Node。平台接入和多执行项目管理,见配置测试项目