> For AI agents: the complete documentation index is available at /zh/llms.txt, the full documentation bundle is available at /zh/llms-full.txt.

# 迁移到 Midscene Test

旧版 YAML 与原生 Midscene Test 共用底层执行内核和报告页面，但用户入口相互独立。`midscene` 负责旧版 `tasks/flow` 文件、YAML 批配置和旧 CLI 参数；`midscene-test` 负责原生 `cases/steps` 文件、TypeScript 或 JavaScript 项目配置、生命周期和 Node。

:::info 什么是“旧版 YAML”
本文所说的“旧版 YAML”，特指 `@midscene/cli` 的 YAML 自动化协议，而不是所有 YAML 文件。它通常具有以下特征：工作流顶层是 `tasks`，用 `tasks[].flow` 编排动作；平台、Agent 和输出配置直接写在工作流 YAML 中；批量运行使用包含 `files`、`setup`、`concurrent`、`retry` 等字段的 YAML 配置；执行入口是 `midscene`。顶层使用 `cases/steps` 和生命周期钩子、由 `midscene-test` 执行的文件属于原生 Test，不属于旧版 YAML。

旧链路只做兼容维护和必要的问题修复，不再新增语法、能力、配置项或 CLI 参数。新项目、新增用例和后续能力建设应采用原生 Midscene Test；现有旧项目可以继续运行，并按业务节奏逐步迁移。
:::

本文把迁移分为两条路径：

- **原地升级**：旧用例、批配置、目录结构和 `midscene` 命令均保持不变，先获得共享执行内核和新报告，不改变输入契约。
- **原生迁移**：按完整文件把旧字段改写为 Test 的文档、Case 和 Step，用项目配置替换 YAML 批配置，再把这些文件切换到 `midscene-test`。

旧版字段的完整参考仍保留在 [YAML 脚本运行器](/zh/yaml-script-runner.md)和 [YAML 格式的工作流](/zh/automate-with-scripts-in-yaml.md)中，供现有项目维护和迁移时查阅。

## 路径一：原地升级旧链路

如果项目已经安装 `@midscene/cli`，升级后继续使用原命令。`midscene` 会保留旧输入语义，通过共享内核执行，并生成新的报告页面：

```bash
pnpm exec midscene ./flow.yaml
pnpm exec midscene --config ./batch.yaml
```

原来的平台配置、`agent`、环境变量插值、task continuation、整文件重试、输出文件和 summary 仍按旧语义处理；报告切换为新 Test 页面，旧 HTML 文件无需转换，重新运行即可生成。旧 `agent.generateReport: false` 仍生效。

旧 `--files`、`--setup`、`--concurrent`、`--retry`、`--continue-on-error`、`--summary`、`--headed`、`--keep-window`、`--share-browser-context`、`--dotenv-override`、`--dotenv-debug`、`--<target>.<field>` 和 `--no-<target>.<field>` 继续由 `midscene` 接受。它们不是 `midscene-test` 参数，也不出现在 Test 主帮助中。

:::info 命令与文件边界

- `midscene` 只接受旧版 `tasks/flow` 工作流文件和 YAML 批配置。
- `midscene-test` 只接受原生 `cases/steps` 工作流文件和 TypeScript 或 JavaScript 项目配置。
- 单个 YAML 文件不能同时声明旧版 `tasks` 与原生 `cases` 或生命周期钩子。
- 同一次命令不能选择两种格式。渐进迁移时，应放在不同目录或文件选择范围，并分别执行两条命令。
- `--project`、`--result-dir` 和 `midscene-test nodes` 只属于原生 Test；旧调度和平台参数继续属于 `midscene`。

两条命令都会在创建浏览器、设备或 Agent 资源前检查边界。遇到错误格式时，会列出文件并提示正确命令，不会静默转发。
:::

## 路径二：迁移为原生 Test 项目

建议按下面的顺序迁移，保证每一步都可以独立运行和对比结果：

1. 先使用 `midscene` 运行原项目，保存退出状态、summary 和新报告作为基线。
2. 使用 `pnpm dlx @midscene/test create` 创建对应平台的 Test 项目，从生成的 `midscene.config.ts` 和 setup 开始配置运行环境。
3. 将旧批配置映射到执行项目：共享资源放入 `setup`，每份文件独立使用的页面、设备和 Agent 放入 `fileSetup`；业务前置步骤放入 YAML 的 `beforeAll` 或 `beforeEach`。
4. 每次完整地把一个 `tasks/flow` 文件改为 `cases/steps`，移入原生文件选择范围，再用 `midscene-test` 运行；未转换文件继续交给 `midscene`。
5. 运行 `pnpm exec midscene-test nodes --project <name>` 生成当前项目的 Node 说明书，根据说明书校验动作名称、参数和字符串简写。
6. 全部转换后，移除旧批配置、旧命令和旧链路专用参数。

### 用例结构映射

旧版：

```yaml
web:
  url: https://example.com

tasks:
  - name: 搜索商品
    continueOnError: true
    flow:
      - ai: 搜索马克杯
      - aiAssert: 搜索结果中包含马克杯
        errorMessage: 未找到目标商品
```

原生 Test：

```yaml
beforeEach:
  - gotoUrl: https://example.com

cases:
  - name: 搜索商品
    steps:
      - aiAct: 搜索马克杯
      - aiAssert:
          prompt: 搜索结果中包含马克杯
          message: 未找到目标商品
```

| 旧版字段                            | 原生 Test 字段或机制                                   | 说明                                                                              |
| ------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------- |
| `tasks`                         | `cases`                                         | 一个旧 task 对应一个 Case。                                                             |
| `tasks[].name`                  | `cases[].name`                                  | 名称直接保留。                                                                         |
| `tasks[].flow`                  | `cases[].steps`                                 | 一个 flow item 对应一个 Step。                                                         |
| `tasks[].continueOnError: true` | 原生 Case 的默认继续行为                                 | `midscene` 保留旧 task continuation；原生 Test 默认继续下一个 Case。                          |
| 未设置 `continueOnError`           | 旧链路的失败策略                                        | `midscene` 停止当前旧文件。原生没有 `onFailure` 参数；公共前置条件放在 `beforeAll`，有依赖关系的步骤放在同一个 Case。 |
| 顶层平台字段中的初始页面或应用                 | `setup` / `fileSetup` 加生命周期 Node                | 按共享范围创建资源；每个 Case 都应重新进入初始状态时，使用 `beforeEach` 的 `gotoUrl`、`launch` 等 Node。      |
| 旧版没有对应字段                        | `beforeAll`、`beforeEach`、`afterEach`、`afterAll` | 原生 Test 提供的文件和 Case 生命周期。                                                       |
| 旧版没有对应字段                        | `cases[].tags`                                  | 用于按项目选择 Case。                                                                   |

保留旧文件即可保留旧失败策略；手写原生 Case 则采用原生语义，不保证调度行为一一等价。Step 的 `$: { continue-on-error: true }` 只让同阶段后续 Step 继续，不控制旧 task 之间的调度，也不会把失败 Case 改为成功。

### flow 动作映射

旧 runtime 会继续接受左侧字段，并在内部适配到共享内核；这种内部转换不是原生 Test 的输入契约。迁移文件时应改写为右侧的原生形式，并以 `midscene-node-spec.md` 中当前项目实际注册的 Node 为准。

| 旧版 flow 字段                                                     | 原生 Test Node / 输入                      | 迁移说明                                                                           |
| -------------------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------ |
| `ai`、`aiAction`、`aiAct`、`instruction`                          | `aiAct.prompt`                         | 统一使用 `aiAct`。其余选项放入 `options`。                                                 |
| `aiAssert`                                                     | `aiAssert.prompt`                      | `errorMessage` 改为 `message`，其余提取选项放入 `options`。                                |
| `aiQuery`、`aiNumber`、`aiString`、`aiBoolean`、`aiAsk`、`aiLocate` | 同名 Node 的 `prompt`                     | 图片与提取选项按 Node 说明书放入 `prompt` 或 `options`。                                      |
| `aiWaitFor`                                                    | `aiWaitFor.prompt`                     | 旧 `timeout` 对应 Node 输入中的 `options.timeoutMs`。                                  |
| `aiTap`                                                        | `aiTap.prompt`                         | 旧的 `locate`、图片和定位选项整理到 `prompt`、`options`。                                     |
| `aiScroll`                                                     | `aiScroll`                             | 定位描述作为 `prompt`，滚动参数放入 `options`。                                              |
| `aiInput`                                                      | `aiInput.value` 和 `aiInput.prompt`     | 输入值放入 `value`，定位描述放入 `prompt`。                                                 |
| `aiKeyboardPress`                                              | `aiKeyboardPress.keyName` 和可选 `prompt` | 具体输入以项目 Node 说明书为准。                                                            |
| `sleep`                                                        | `sleep.ms`                             | 例如 `sleep: 1000` 改为 `sleep: { ms: 1000 }`。新用例也可以使用通用 `wait` Node。              |
| `javascript`                                                   | `javascript.script`                    | 返回值会记录在 Step 结果中。                                                              |
| `recordToReport`、`logScreenshot`                               | `recordToReport`                       | 标题映射到 `title`，`content` 放入 `options.content`。                                  |
| `runGherkinScenario`                                           | `runGherkinScenario.scenario`          | 旧链路会关闭该动作的缓存。                                                                  |
| `runAdbShell`                                                  | `runAdbShell`                          | 命令映射到 `command`，旧 `timeout` 保留为 Node 输入。                                       |
| `Finalize`                                                     | 旧链路专用规划标记                              | 旧 runtime 仍接受；原生 Case 中省略，不作为公开 Node。                                          |
| 其他平台动作和自定义动作                                                   | 已注册的同名 Node，或通用 `action` Node          | 先运行 `midscene-test nodes`，根据目标平台的 Node 说明书改写参数。                                |
| flow item 的 `name`                                             | Node 的结构化结果                            | `midscene` 仍按旧名称写入输出；原生 Test 不提供跨 Step 的命名结果表达式，数据共享应使用自定义 Node 和项目 `context`。 |

### 具体示例：迁移一个提交订单 Case

下面的旧用例填写收货人、等待提交按钮可用、提交订单并记录结果。它同时使用了 task 失败策略、动作别名、定位输入、动作超时、断言错误消息、固定等待和报告记录：

```yaml filename=flows/submit-order.yaml
web:
  url: https://shop.example.com/checkout

tasks:
  - name: 提交订单
    continueOnError: true
    flow:
      - aiInput: Alice
        locate: 收货人姓名输入框
      - aiWaitFor: 提交订单按钮已启用
        timeout: 10000
      - ai: 点击提交订单按钮
      - aiAssert: 页面显示订单提交成功
        errorMessage: 提交后没有出现成功提示
      - sleep: 500
      - recordToReport: 订单提交结果
        content: 已完成下单流程
```

迁移成原生 Test 后，同一个 Case 可以写成：

```yaml filename=cases/submit-order.yaml
beforeEach:
  - gotoUrl: https://shop.example.com/checkout

cases:
  - name: 提交订单
    steps:
      - aiInput:
          prompt: 收货人姓名输入框
          value: Alice
      - aiWaitFor:
          prompt: 提交订单按钮已启用
          options:
            timeoutMs: 10000
      - aiAct: 点击提交订单按钮
      - aiAssert:
          prompt: 页面显示订单提交成功
          message: 提交后没有出现成功提示
      - wait:
          duration: 500
          unit: ms
      - recordToReport:
          title: 订单提交结果
          options:
            content: 已完成下单流程
```

这里发生了几类转换：

1. `web.url` 不再和用例内容混在一起。浏览器和页面由项目配置中的准备函数创建，需要在每个 Case 开始时进入结算页，因此 URL 放到 `beforeEach` 的 `gotoUrl`。
2. task 变成 Case；原生 Test 默认在 Case 失败后继续，因此这个例子无需额外的继续参数。
3. `aiInput` 的值和定位描述从同级旧字段拆成 Node 的 `value` 与 `prompt`。
4. `aiWaitFor.timeout` 是动作自身的等待上限，所以放入 `options.timeoutMs`。如果要限制整个 Step，应另用 `$: { timeout: 10000 }`。
5. `ai` 统一为 `aiAct`，`aiAssert.errorMessage` 改为 `aiAssert.message`。
6. 固定等待改用原生通用 `wait` Node；报告标题与正文分别放入 `recordToReport.title` 和 `options.content`。

这个例子只调整输入结构，没有改变业务执行顺序。实际迁移时应先运行 `pnpm exec midscene-test nodes --project <name>`，生成当前项目的 `midscene-node-spec.<project-name>.md`。以这份 Node 说明书为准确认 `gotoUrl`、`aiInput`、`aiWaitFor` 等 Node 是否可用以及参数如何填写，不要根据其他平台的示例推测。

### 脚本和 Agent 配置映射

`midscene` 会继续读取旧 YAML 顶层配置。迁移为原生 Test 时，这些字段不再放在 Case YAML 中，而是进入 `midscene.config.ts`、`setup` / `fileSetup` 或 Node。共享资源放入 `setup`，每份文件独立使用的资源放入 `fileSetup`，业务前置步骤放入 YAML 钩子。三者的区别见[setup、fileSetup 与 beforeAll](/zh/midscene-test/execution.md#setupfilesetup-与-beforeall)。

| 旧版脚本字段                                                                                                                                    | 原生 Test 配置或机制                                          | 说明                                                                                         |
| ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
| `target`                                                                                                                                  | Web 项目的 `setup` / `fileSetup`                          | 该字段已废弃；迁移时不要继续使用，按实际模式配置 Playwright、Puppeteer 或 bridge runtime。                            |
| `page`、`browser`、`web`                                                                                                                    | Web 项目的 `setup` / `fileSetup` + Web Node               | 共享 Browser 放入 `setup`，独立页面放入 `fileSetup`；进入页面、设置 Cookie 等可重复动作放入生命周期 Node。                 |
| `android`                                                                                                                                 | Android 项目的 `setup` / `fileSetup` + Android Node       | 设备 ID、截图和输入策略用于创建 Device/Agent；`launch` 等用例动作放入 `beforeEach` 或 `steps`。                    |
| `ios`                                                                                                                                     | iOS 项目的 `setup` / `fileSetup` + iOS Node               | WDA 连接和 Device/Agent 创建放入 `setup` 或 `fileSetup`；应用启动和交互使用已注册 Node。                         |
| `harmony`                                                                                                                                 | HarmonyOS 项目的 `setup` / `fileSetup` + HarmonyOS Node   | HDC 连接、设备参数和应用映射放入 `setup` 或 `fileSetup`；应用与 Shell 操作使用已注册 Node。                           |
| `computer`                                                                                                                                | Computer 项目的 `setup` / `fileSetup` + Computer Node     | display 等设备参数放入 `setup` 或 `fileSetup`；界面操作使用已注册 Node。                                      |
| `interface`                                                                                                                               | 自定义项目的 `setup` / `fileSetup` + `createMidsceneNodes()` | 在准备函数中导入并创建自定义 Interface、Device 和 Agent，再把 Agent 暴露给 Node。                                 |
| `agent.generateReport`                                                                                                                    | 旧链路的报告设置                                               | 旧 YAML 仍可关闭自身报告；原生 Test 始终生成统一总报告。                                                         |
| `agent.reportFileName`、`agent.testId`                                                                                                     | 旧链路的 Agent 产物设置                                        | 查看报告时，以 CLI 输出的路径或 summary 中的报告链接为准。`testId` 已废弃。                                          |
| `agent.groupName`、`agent.groupDescription`                                                                                                | 项目、Case 名称和报告结构                                        | 没有同名原生字段；将分组语义放入项目名称、Case 名称或 tags。                                                        |
| `agent.replanningCycleLimit`、`agent.aiContexts`、`agent.aiActContext`、`agent.aiActionContext`、`agent.cache`、`agent.screenshotShrinkFactor` | 创建 Agent 时的 options                                    | 创建 Agent 时继续传入相应选项，不再写在 Case YAML 中。                                                       |
| `agent.outputFormat`、`agent.persistExecutionDump`、`agent.autoPrintReportMsg`                                                              | Test 报告或 Agent options                                 | 优先采用 Test 的统一报告；只有仍需 Agent 自身行为时才在准备函数中保留对应选项。                                             |
| `config.output`，或平台字段中的 `output`                                                                                                          | Test 结构化结果                                             | `midscene` 继续写旧输出文件；原生 Test 使用 `--result-dir`、`summary.json` 和报告。业务数据应由自定义 Node 返回或写入外部存储。 |
| `config.unstableLogContent`                                                                                                               | Test 报告与结构化结果                                          | 没有同名原生字段；迁移消费方，不再依赖旧的实验性日志内容文件。                                                            |
| `tasks`                                                                                                                                   | 原生 Workflow Document                                   | 按前文映射为 `cases` 和生命周期钩子。                                                                    |

准备函数的完整写法和各平台 Node 注册方式见[配置运行环境](/zh/midscene-test/configuration.md#配置运行环境)。

### 批配置映射

旧版 `batch.yaml`：

```yaml
files:
  - flows/cases/**/*.yaml
setup: flows/setup.yaml
concurrent: 2
retry: 1
continueOnError: false
summary: result.json
headed: true
```

原生 Test 把执行参数放在 `midscene.config.ts`：

```ts filename=midscene.config.ts
import { defineTestProject } from '@midscene/test/config';
import { nodes, setup } from './test-runtime';

export default defineTestProject({
  nodes,
  projects: [
    {
      name: 'default',
      setup,
      files: {
        include: ['flows/cases/**/*.yaml'],
      },
      retry: 1,
    },
  ],
  test: {
    bail: 1,
  },
  output: {
    reportDir: './midscene_run/report',
  },
});
```

| 旧版批配置                                                  | 原生 Test 配置或机制                                | 说明                                                                          |
| ------------------------------------------------------ | -------------------------------------------- | --------------------------------------------------------------------------- |
| `files`                                                | `projects[].files.include`                   | `midscene` 保留旧顺序和重复调用；原生选择固定去重、排序，没有 `files.order` 开关。                      |
| `setup`                                                | `setup` / `fileSetup` / YAML `beforeAll`     | 旧版先执行前置 YAML；原生准备函数按共享范围创建资源，`beforeAll` 执行文件的前置步骤，不提供 `setupFile` 参数。      |
| `concurrent`                                           | `test.maxConcurrentFiles` + `fileSetup`      | 显式开启文件并发，并为每份文件准备独立环境。                                                      |
| `retry`                                                | 旧链路整文件重试；原生 `projects[].retry`               | 原生只重试失败 Case；确需整文件重放时继续使用 `midscene`，没有 `retryScope` 开关。                    |
| `continueOnError: false`                               | `test.bail: 1`                               | 失败达到阈值后停止调度新的文件或 Case。已经开始的并发任务仍会完成清理。                                      |
| `continueOnError: true`                                | `test.bail: 0`                               | 不因失败阈值触发全局停止；`midscene` 另行保留旧 task continuation，原生 Case 默认继续。               |
| `summary`                                              | Test `summary.json`、报告和编程式 API               | `midscene` 仍写旧 summary；原生 Test 没有同名配置，应迁移消费方。可用 `--result-dir` 指定结构化结果目录。   |
| `shareBrowserContext`                                  | 项目 `setup` 和 `fileSetup`                     | 原生可在 setup 中共享 Browser，在 fileSetup 中为每份文件创建独立 BrowserContext；这会改变旧版共享会话的行为。 |
| `headed`                                               | 浏览器或设备 setup 的启动参数                           | 例如 Playwright 使用 `chromium.launch({ headless: false })`。                    |
| `keepWindow`                                           | setup 的清理策略                                  | 仅建议本地调试使用；需要由项目决定是否延迟或跳过浏览器 teardown。                                       |
| `dotenvOverride`、`dotenvDebug`                         | 项目的加载环境变量方式                                  | 原生读取 `process.env`；依赖 `.env` 文件时，在配置文件或启动脚本中显式加载，并在那里设置优先级和调试行为。            |
| `web`、`android`、`ios`、`harmony`、`computer`、`interface` | `setup` / `fileSetup`、`variables` 和平台注册 Node | 按共享范围准备资源；可序列化的环境差异放入 `variables`。                                          |

上面的原生示例迁移了文件选择、用例重试和失败阈值，未保留旧版的前置文件和文件并发。需要并发时，按[文件并发配置](/zh/midscene-test/execution.md#使用-maxconcurrentfiles-开启文件并发)补充 `test.maxConcurrentFiles` 和 `fileSetup`。保留原用例和批配置时，继续使用 `midscene`；旧 `concurrent` / `--concurrent` 和前置文件行为不变。

`midscene` 保留旧输出命名规则：显式 flow `name`、未命名提取结果的数字键，以及重复名称的覆盖规则均保留。

## 验证迁移结果

同一个用例先用 `midscene` 运行旧版本，再用 `midscene-test` 运行转换后的版本，至少核对：

- 进程退出码和失败后是否继续执行。
- 重试单位是 Case 还是整个文件。
- 环境变量、平台连接参数和初始页面状态。
- AI 动作输入、超时和断言失败信息。
- 业务输出的消费方式，以及新 Test 报告中的 Step 结果。
- 并发执行时页面、Agent、设备和测试数据是否隔离。
- 失败、超时和 Ctrl+C 中断后，生命周期钩子与资源清理是否完成。

迁移完成后，新增用例应使用 `cases/steps`。只有尚未迁移的文件继续保留 `tasks/flow`，避免在新代码中继续扩大兼容格式的使用范围。
