• 简体中文
  • 编写与设计 YAML 用例

    一个典型的 YAML 文件

    一份 YAML 文件可以包含多个测试用例,以及用例执行前后的准备和清理步骤。

    下面以商城搜索为例:每次运行用例前先打开首页,再搜索商品并验证结果(实际使用时请将网址和商品名称替换为你的业务内容):

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

    在 Midscene Test 中,我们遵循以下术语定义:

    • Workflow Document(工作流文档):整份 YAML 文件。
    • Case(用例):cases 列表下的单条测试用例。
    • Step(步骤):steps 列表下(或生命周期钩子内)的单次 Node 调用,每个步骤只调用一个 Node。
    • Hook(生命周期钩子):在用例执行前后运行的准备与清理步骤(如 beforeAll、beforeEach、afterEach、afterAll)。

    上面的示例使用了字符串简写形式:gotoUrl 后的字符串会作为 url 参数传入,aiAct 和 aiAssert 后的字符串会作为 prompt 参数传入。如果需要传入更多参数,可以使用下文介绍的对象写法。某个 Node 是否支持字符串简写,以项目的 Node Spec 为准。

    用例设计约定

    Midscene Test 采用顺序执行与显式状态共享的设计,使每个 Node 的输入参数、执行上下文和依赖关系保持清晰:

    • 按声明顺序线性执行:YAML 仅描述线性的测试步骤,不引入 DAG、条件分支或循环语法。如果遇到需要复杂动态编排的场景,建议在外部通过代码生成确定的线性 YAML 步骤序列,再交由 Midscene Test 执行。
    • 每一个语句(步骤)都是无状态且独立的:每一个步骤都是一次完全独立的 Node 语句调用,步骤之间不存在隐式的状态和数据传递(不支持跨步骤输出引用语法)。每次调用仅依赖当前步骤显式声明的输入参数以及项目级别的 context。如果你需要在步骤之间显式共享数据,请通过自定义 Node 读写执行项目共享的 context。

    基于这一约定,每个 AI 步骤的自然语言指令也应当独立完整。例如,下面的断言使用“上一步的图标”来指代检查目标,依赖前一步的指令文本,属于错误写法:

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

    正确的做法是在断言中直接写明检查对象与预期状态,使该步骤本身就能表达完整的检查条件:

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

    简言之,虽然界面本身会保留前一步操作后的画面,但每条自然语言指令都应明确写出目标元素,避免使用“上一步”“刚才那个”等指代词。

    使用 Node

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

    Node 既可以在用例的 steps 中调用,也可以在 beforeEach、afterEach 等生命周期钩子中调用,语法完全一致。

    Midscene Test 注入了 Midscene GUI Agent 上的能力:aiAct 根据自然语言操作界面,aiAssert 验证预期结果,aiWaitFor 等待界面出现指定状态;同时提供了框架内置的 wait 等待指定时长。

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

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

    使用脚手架创建项目时,模板会根据所选平台显式注册对应的官方 Node。如果从零手写 midscene.config.ts,框架不会默认注册任何 Node,需要手动引入并配置。各平台支持的官方预置 Node 列表与参数说明,请参阅各平台预置 Node。此外,你也可以按需扩展自定义能力(例如调用业务接口准备测试订单),详见注册自定义业务 Node。

    常用 Node

    日常编写用例时,主要使用 aiAct 描述操作,使用 aiAssert 验证结果:

    Node用途编写方式
    aiAct根据自然语言完成界面操作,可包含连续的多个动作。描述要执行的操作,例如“搜索马克杯,将第一个商品加入购物车”。
    aiAssert检查界面是否符合预期;若不符合,则该步骤失败。描述界面上可观察到的预期结果,例如“购物车中有一件马克杯”。

    界面操作执行完成并不代表测试通过,应在关键节点使用 aiAssert 明确验证预期结果。如果需要自定义断言失败时的报错提示,可以将参数展开为对象形式:

    steps:
      - aiAct: 搜索马克杯,将第一个商品加入购物车
      - aiAssert:
          prompt: 购物车中有一件马克杯
          message: 加购后购物车内容不符合预期

    若需要为后续 AI 操作补充业务背景知识或通用规则(如测试账号约定或弹窗处理),也可以调用 setAIContext 设置或清除上下文。

    其他 Node 的调用模式

    平台内置操作与自定义业务 Node 采用相同的调用结构:在 Node 名称下方以键值对形式填写参数。下面展示含多个参数与无参数两种常见写法:

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

    其中 setViewportSize 接收一个参数对象,而 clearCookies 不需要参数,传入空对象 {} 即可。这两个 Node 均由 Web 平台预设提供;移动端、桌面端及团队自定义 Node 的可用列表与参数结构,请查阅当前项目的 Node Spec。

    例如,当团队在项目中实现并注册了用于创建测试订单的自定义 Node order.create 后,即可在 YAML 中这样调用:

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

    参数值同样支持嵌套对象或数组。例如向 aiAct 传入参考图片时,文本和图片列表共同构成 prompt 对象,而 options 作为同级字段单独配置:

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

    生成当前项目的 Node Spec

    不同平台、执行项目(Project)和依赖版本实际注册的 Node 可能有所不同。编写用例时,请勿仅凭其他项目的示例推测当前项目的可用能力。

    运行 midscene-test nodes 可以根据项目最终生效的注册结果生成 Node Spec(节点规格说明)——它列出可用 Node、输入参数结构(由 Zod 转换为 JSON Schema)、字符串简写规则及匹配的用例文件路径,是人和 AI Agent 编写 YAML 用例的依据。

    查看生成的 Node Spec 示例片段
    # Midscene Test Node Spec
    
    ## Available Nodes
    
    | Node | Description |
    | --- | --- |
    | aiAct | Perform interface operations from natural language. |
    | aiAssert | Check whether the interface matches an expectation. |
    | gotoUrl | Navigate the current browser Page to an absolute HTTP(S) URL or a relative path. |
    
    ## Node Details
    
    ### `gotoUrl`
    
    Navigate the current browser Page to an absolute HTTP(S) URL or a path relative to testRunner.baseURL or the current page URL.
    
    **String shorthand:** Maps to `{ url: value }`.
    
    #### Input Schema
    
    ```json
    {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "type": "object",
      "properties": {
        "url": {
          "type": "string",
          "description": "Navigation URL target."
        }
      },
      "required": [
        "url"
      ]
    }
    ```

    脚手架在安装依赖后会自动生成 Node Spec。当你修改了 agentClass、顶层 nodes、projects[].nodes、Node 的参数 Schema,或升级了 Midscene 相关依赖包后,都应重新运行以下命令更新 Spec:

    pnpm run nodes

    你也可以直接调用 CLI 命令,并按需指定测试目录、配置文件或执行项目:

    pnpm exec midscene-test nodes ./e2e --config ../config/midscene.config.ts
    pnpm exec midscene-test nodes --project android-smoke

    生成命令仅加载项目配置与 Node 定义,不会执行 setup、测试用例或 getAgent,因此无需启动浏览器、连接设备或调用大模型。Node Spec 属于自动生成的文件,请勿手动编辑;配置变更后重新运行生成命令即可。

    控制参数与高级配置

    设置超时和错误处理

    步骤中的 $ 字段用于配置框架级的步骤控制参数(如超时时间与容错策略)。这些参数由 Midscene Test 处理,不会传递给 Node 的 input。

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

    $ 支持以下两个字段:

    • timeout:当前步骤的超时时间,单位为毫秒。
    • continue-on-error:设为 true 时,若当前步骤执行失败,允许继续执行当前阶段的后续步骤(默认值为 false)。但如果底层操作未能正常退出或资源清理出现异常,执行仍会中止。

    注意,continue-on-error 仅控制当前阶段是否继续往下走;只要用例中有任何一个步骤失败,该用例的最终状态仍为 failed。

    步骤超时并不意味着底层的异步操作已立即终止。在进入当前阶段的下一个步骤前,框架会等待已超时的操作彻底退出(默认最多等待 30 秒,独立计时,不占用下一步的超时时间);若等待超时后仍未退出,则会停止执行后续步骤。底层操作退出后虽然可以继续使用 Agent,但页面或业务状态可能已处于中间态,仍需在后续步骤中确认或重置,详见超时与取消机制。

    使用项目变量与环境变量

    Midscene Test 会在步骤执行前递归解析 Node 输入参数中的变量占位符:

    steps:
      - launch:
          uri: ${appUri}
      - api.createOrder:
          baseURL: ${{TEST_API_BASE_URL}}
          payload:
            count: ${orderCount}

    变量解析遵循以下规则:

    • ${name}:读取当前执行项目的 variables 配置。若整个字段值仅由 ${name} 构成(未与其他文本拼接),则会保留变量的原始 JSON 类型(如数字、布尔值、对象或数组);对象或数组变量只能作为完整字段值使用,不支持嵌入到字符串中拼接。
    • ${{ENV_NAME}}:读取环境变量,解析结果始终为字符串。
    • 引用未定义的变量会在用例收集阶段直接报错。变量替换仅作用于 Node 的输入参数,不作用于 $ 控制字段。

    关于用例中步骤执行的无状态设计,请参阅用例设计约定。

    使用 tags 筛选 Case

    你可以为用例添加 tags 标签,以便按场景或平台筛选运行:

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

    工程维护者可以在各个执行项目(Project)中配置 tags.include 与 tags.exclude:排除规则(exclude)始终优先;当包含规则(include)非空时,用例只需命中其中任意一个标签即会被选中执行。

    下一步