• 简体中文
  • 配置测试工程

    midscene.config.ts 是 Midscene Test 的工程配置文件。你可以在其中定义浏览器或设备的初始化逻辑、注册供 YAML 调用的 Node,以及设置并发数、超时时间等运行参数。本文介绍配置文件的基本结构、Agent 与各平台接入方式、多执行项目(Project)管理,以及文件级资源隔离。

    配置文件结构

    测试工程通过 defineTestProject() 定义并导出配置。Midscene Test 支持以下配置文件格式与加载方式:

    配置文件的选择方式支持的文件加载方式
    未指定配置路径,由 Midscene Test 自动查找midscene.config.ts 或 midscene.config.mjs.ts 会先经过 TypeScript 转换;.mjs 由 Node.js 作为原生 ESM 直接加载
    通过 CLI 的 --config <路径> 或 loadTestProject(路径) 显式指定.ts 或 .mjs.ts 会先经过 TypeScript 转换;.mjs 由 Node.js 作为原生 ESM 直接加载

    默认情况下,Midscene Test 会在测试根目录下查找 midscene.config.ts 或 midscene.config.mjs。如果两个文件同时存在,框架会直接报错提示冲突,而不会静默选择其中一个;此时可通过 --config <路径> 明确指定要使用的配置文件。

    核心配置项如下:

    字段用途
    setup准备执行项目(Project)内共享的浏览器或设备资源。
    fileSetup为每份 YAML 文件准备独立的运行环境(串行与并发执行时均可使用)。
    nodes注册所有执行项目共享的全局 Node。
    projects声明一个或多个执行项目(Project),分别配置运行环境与用例匹配规则。声明 projects 后,setup 和 fileSetup 需配置在各项目内部;省略 projects 时,顶层配置将作为默认执行项目运行。
    test设置并发数、失败中止阈值(bail)和默认步骤超时时间。
    output设置 HTML 测试报告的输出目录。

    下文先以单个执行项目为例说明如何配置运行环境。如果需要管理多个执行项目,或为不同项目注册各自的 Node,请参阅配置多个执行项目。

    配置运行环境

    完整示例:Playwright

    下面是一个仅使用 setup 的串行配置示例:同一个执行项目中的所有 YAML 文件共用同一个浏览器页面。如果希望每份 YAML 文件使用相互隔离的浏览器上下文,可以配合使用 fileSetup(无需开启并发即可使用)。

    如果要在已有工程中手动接入 Web 测试,请先安装依赖:

    pnpm add -D @midscene/test @midscene/web playwright
    pnpm exec playwright install chromium

    运行测试前,还需按照使用模型 API Key配置模型环境变量。如果你将模型配置保存在 .env 文件中,手写 midscene.config.ts 时需要自行加载(例如安装 dotenv 并在配置文件顶部引入 import 'dotenv/config'),或者直接通过 Shell / CI 注入环境变量,详见加载环境变量。

    import {
      defineProjectSetup,
      defineTestProject,
    } from '@midscene/test/config';
    import { createMidsceneNodes } from '@midscene/test/midscene';
    import { PlaywrightAgent } from '@midscene/web/playwright/agent';
    import { chromium, type Browser, type Page } from 'playwright';
    
    interface ProjectContext {
      browser: Browser;
      page: Page;
      agent?: PlaywrightAgent;
    }
    
    const midsceneNodes = createMidsceneNodes<ProjectContext>({
      agentClass: PlaywrightAgent,
      getAgent: ({ context }) => {
        context.agent ??= new PlaywrightAgent(context.page);
        return context.agent;
      },
    });
    
    // 声明浏览器环境的启动与清理
    const playwrightSetup = defineProjectSetup<ProjectContext>({
      name: 'playwright',
      async setup({ onTeardown }) {
        const browser = await chromium.launch({ headless: true });
        onTeardown(() => browser.close());
        const browserContext = await browser.newContext();
        const page = await browserContext.newPage();
        const context: ProjectContext = { browser, page };
        onTeardown(async () => { await context.agent?.destroy(); });
        return context;
      },
    });
    
    // 导出项目配置
    export default defineTestProject<ProjectContext>({
      projects: [
        {
          name: 'chromium',
          setup: playwrightSetup,
          files: { include: ['cases/**/*.{yaml,yml}'] },
        },
      ],
      nodes: midsceneNodes,
    });

    在这个配置中,各部分的职责与协作关系如下:

    • setup:启动浏览器并创建页面,同时通过 onTeardown() 注册资源清理函数。
    • context:保存运行期上下文。Node 调用 getAgent 获取 Agent 实例——首次调用时创建 PlaywrightAgent 并缓存到 context.agent 中,后续步骤直接复用该实例及其关联的 page。
    • nodes:注册通用 AI 操作和 Playwright 平台操作,供 YAML 用例调用。
    • projects:声明名为 chromium 的执行项目,将 playwrightSetup 与 cases/ 目录下的 YAML 用例关联起来。

    完成上述配置后,即可开始编写 YAML 用例并运行测试。下面进一步说明如何管理资源的共享与隔离。

    使用 setup 创建和清理共享资源

    defineProjectSetup() 用于定义执行项目(Project)级别的初始化逻辑,并挂载到 setup 字段上。测试运行时,每个执行项目只会调用一次自身的 setup(),返回的对象将作为共享上下文供该项目内的步骤使用。

    如果你希望每个 YAML 文件拥有独立的运行环境,可以使用 defineFileSetup() 定义文件级初始化逻辑,并挂载到 fileSetup 字段上。fileSetup 会接收项目级 setup 的返回值,在此基础上为当前文件创建独立资源,详见下一节用 fileSetup 隔离资源。

    注意,setup 创建的共享资源不会在每条用例开始前自动重置。如需在用例间重置页面、Cookie 或业务状态,请在 YAML 的生命周期钩子中调用相应的 Node;自定义 Node 之间读写共享数据的方式请参阅跨 Node 共享上下文。

    创建 Browser、Agent 等资源后,应立即通过 onTeardown() 注册清理函数。即便 setup 过程或用例执行失败,框架也会在执行项目结束时逆序(后进先出)调用已注册的清理函数——例如在上面的 Playwright 示例中,会先销毁 agent,再关闭 browser。注意,在 setup 中注册的 onTeardown() 仅在整个执行项目结束时触发;而在自定义 Node 内部注册的 onTeardown() 则具有独立的清理时机。

    用 fileSetup 隔离资源

    当多个 YAML 文件需要隔离运行环境(或开启文件并发)时,可以用 setup 准备项目级共享资源,再用 fileSetup 为每个文件创建独占资源。例如在 Web 测试中,可以让整个项目共享同一个 Browser 进程,而为每个 YAML 文件单独创建 BrowserContext、Page 和 Agent,从而隔离各文件之间的 Cookie 与本地存储:

    import {
      defineFileSetup,
      defineProjectSetup,
      defineTestProject,
    } from '@midscene/test/config';
    import { createMidsceneNodes } from '@midscene/test/midscene';
    import { PlaywrightAgent } from '@midscene/web/playwright/agent';
    import { chromium, type Browser } from 'playwright';
    
    type SharedContext = { browser: Browser };
    type FileContext = { agent: PlaywrightAgent };
    
    const setup = defineProjectSetup<SharedContext>({
      name: 'browser',
      async setup({ onTeardown }) {
        const browser = await chromium.launch();
        onTeardown(() => browser.close());
        return { browser };
      },
    });
    
    const fileSetup = defineFileSetup<FileContext, SharedContext>({
      name: 'page',
      async setup({ projectContext, signal, onTeardown }) {
        if (!projectContext) throw new Error('Browser setup did not complete');
        const session = await projectContext.browser.newContext();
        onTeardown(() => session.close());
        signal.throwIfAborted();
        const page = await session.newPage();
        const agent = new PlaywrightAgent(page);
        onTeardown(() => agent.destroy());
        return { agent };
      },
    });
    
    export default defineTestProject<FileContext, SharedContext>({
      test: { maxConcurrentFiles: 3 },
      projects: [
        {
          name: 'web',
          setup,
          fileSetup,
          maxConcurrentFiles: 2,
          files: { include: ['cases/web/**/*.yaml'] },
        },
      ],
      nodes: createMidsceneNodes<FileContext>({
        agentClass: PlaywrightAgent,
        getAgent: ({ context }) => context.agent,
      }),
    });

    对应的 YAML 文件直接使用 fileSetup 准备好的 Agent,在 beforeAll 中设置视口大小,在 beforeEach 中为每条用例打开首页:

    beforeAll:
      - setViewportSize:
          width: 1280
          height: 720
    
    beforeEach:
      - gotoUrl: https://your-shop.example
    
    cases:
      - name: 搜索商品
        steps:
          - aiAct: 搜索马克杯
          - aiAssert: 搜索结果中包含马克杯

    在这个示例中,每个 YAML 文件执行完毕后会依次销毁自身的 Agent 并关闭 BrowserContext;当该项目的所有文件均清理完毕后,才会关闭项目级共享的 Browser。

    defineFileSetup<FileContext, SharedContext> 的两个泛型参数分别代表文件级 context 类型和项目级 projectContext 类型。注意:fileSetup 的返回值会直接作为该文件的完整 context 传给 Node,框架不会将它与 projectContext 自动合并;如果 Node 需要访问 projectContext 中的字段,请在 fileSetup 的返回对象中显式透传。

    fileSetup 的 setup 函数接收以下参数:

    参数用途
    projectContext项目级 setup 的返回值;未配置项目级 setup 时为 undefined。
    project、file当前执行项目的配置对象,以及当前文件的路径(sourcePath)与执行 ID。
    env、signal环境变量映射与取消信号(AbortSignal)。
    onTeardown()注册当前文件执行结束时的清理函数。

    如果工程只有一组环境配置,可以省略 projects 数组,直接将 setup 和 fileSetup 写在顶层配置中;如果每个文件能独立完成所有资源初始化,也可以只配置 fileSetup 而不配置 setup。

    对于 Android、iOS 等移动端或桌面端平台,若要开启文件并发,必须为每个并发文件分配独占的物理设备或模拟器,并分别创建独立的 Device 和 Agent。每个 Device 实例只能归属于一个 Agent,调用 Agent.destroy() 时会一并销毁其关联的 Device,因此设备归还逻辑应当排在 Agent 销毁之后。如果你手头只有一台测试手机或一个桌面环境,请将该项目的并发上限设为 1,否则多个 Agent 同时操作同一台设备会互相干扰。

    关于文件环境的共享范围与清理顺序,请参阅生命周期与并发;关于初始化失败后的调度行为,请参阅失败时如何执行。此外,如果项目级共享资源(如共享 Browser)在运行期间意外不可用,应在 fileSetup 或自定义 Node 中显式标记共享资源错误,框架不会仅凭浏览器关闭的报错文本自动推断,详见异步操作、错误与取消。

    注册官方 Node

    通用 AI 操作与 Agent 接入

    Midscene Test 内核不会隐式注册任何 Node。使用 midscene-test create 创建项目时,生成的配置文件会调用 @midscene/test/midscene 导出的 createMidsceneNodes() 来注册所选平台的官方 Node。如果你手写配置文件,需要将 createMidsceneNodes() 返回的数组显式传入顶层 nodes 或 projects[].nodes 中才会生效:

    import { createMidsceneNodes } from '@midscene/test/midscene';
    import { PlaywrightAgent } from '@midscene/web/playwright/agent';
    
    const midsceneNodes = createMidsceneNodes<ProjectContext>({
      agentClass: PlaywrightAgent,
      getAgent: ({ context }) => {
        context.agent ??= new PlaywrightAgent(context.page);
        return context.agent;
      },
    });

    调用 createMidsceneNodes() 时需传入两个核心参数:

    • agentClass:指定平台对应的 Midscene GUI Agent 类(必须实现 getTestRunnerNodeDefinitions(),否则会在注册阶段报错)。传入 PlaywrightAgent、PuppeteerAgent、AndroidAgent、IOSAgent 或 HarmonyAgent(及其 Page/Browser 变体)时,会同时导出通用 AI Node(如 aiAct、aiAssert、数据提取、视觉定位等)、内置 wait Node 以及该平台专属的操作 Node;而基础 Agent 和 ComputerAgent 则提供通用 AI Node 与 wait。
    • getAgent:声明在步骤执行期间如何从当前 context 中获取 Agent 实例(context 的具体字段结构由你自行定义)。

    在 Android、iOS 等移动端平台接入 Agent 时,请注意 Device 的生命周期约束:每个 Device 实例只能绑定给一个 Agent,调用 Agent.destroy() 时会自动销毁该 Device。因此,请为每个 Agent 创建独立的 Device 实例,切勿在 Agent 销毁后复用同一个 Device。

    注册完成后,即可在 YAML 用例中直接调用这些官方 Node。完整的可用 Node 名称与参数字段,请以当前项目生成的 Node 说明书为准。

    为多个 Midscene Agent 的 Node 命名

    同一个工作流使用多个 Midscene Agent 时,可以通过 namespace 为各组 Node 注册不同的名称。让 setup 在 context 中返回独立的 Midscene Agent 实例,再将两组 Node 注册到同一个 Project:

    import { Agent } from '@midscene/core/agent';
    import { createMidsceneNodes } from '@midscene/test/midscene';
    
    interface MultiAgentContext {
      mobile: Agent;
      web: Agent;
    }
    
    const nodes = [
      ...createMidsceneNodes<MultiAgentContext>({
        namespace: 'mobile',
        agentClass: Agent,
        getAgent: ({ context }) => context.mobile,
      }),
      ...createMidsceneNodes<MultiAgentContext>({
        namespace: 'web',
        agentClass: Agent,
        getAgent: ({ context }) => context.web,
      }),
    ];

    将 nodes 加入项目配置后,YAML 使用注册后的名称调用:

    cases:
      - name: 跨设备完成一个 Todo
        steps:
          - mobile.aiAct: 创建一个标题为“Buy milk”的 Todo。
          - web.aiWaitFor: 列表中显示标题为“Buy milk”的 Todo。
          - web.aiTap: “Buy milk”旁边的复选框

    namespace 会给返回的每个 Node 加上前缀,包括通用 AI 操作、平台操作和 wait。例如,上述注册提供 mobile.aiAct 和 mobile.wait,不会同时注册不带前缀的名称。不传 namespace 时保留原有名称。

    namespace 必须是非空字符串,不能包含空白字符、首尾的点或空的分段;支持 checkout.mobile 这样的嵌套名称。无效值会在注册阶段报错,此时尚未获取 Agent。

    namespace 只改变 Node 名称。运行时仍由 getAgent 或 agentProvider.getAgent 选择 Agent,执行记录仍关联到对应 Step。namespace 不创建资源,也不提供并发隔离。不同 Project 可以分别注册相同的 Node 名称,无需添加 namespace。

    Playwright

    通过 createMidsceneNodes({ agentClass: PlaywrightAgent, getAgent }) 会自动注册 Web 专属的 gotoUrl、setCookies、clearCookies 和 setViewportSize 四个 Node。使用前需在项目中安装同级依赖 playwright:

    pnpm add -D playwright

    安全设置 Cookie:调用 setCookies 时,不支持在 YAML 中直接明文填写 Cookie 值。这是因为 Midscene Test 会将 Node 的输入参数记录到运行结果文件中,明文填写会导致敏感凭证泄露。

    你必须在 cookiesEnv(环境变量名)、profile(预置配置名)或 storageStatePath(Playwright 状态文件路径)三者中任选其一,以引用方式传入 Cookie。setCookies 仅在执行瞬间读取真实 Cookie 并注入 BrowserContext,而在运行结果中只记录引用名称与 Cookie 条数,从而避免敏感信息进入测试报告或结果文件:

    beforeEach:
      - clearCookies: {}
      - setCookies:
          cookiesEnv: E2E_COOKIES
          url: https://example.com
      - setViewportSize:
          width: 1440
          height: 900
      - gotoUrl:
          url: https://example.com/chat
          waitUntil: domcontentloaded

    关于 Cookie 引用的补充说明:

    • 环境变量默认从 process.env 读取,内容可以是 Cookie 请求头字符串、Cookie JSON 数组或 Playwright storageState JSON。
    • 相对路径的 storageStatePath 默认相对于当前工作目录解析。如需自定义环境变量读取、Profile 映射或路径解析逻辑,可在实例化 Agent 时通过 testRunner 选项传入 getEnv、getCookieProfile 或 resolveStorageStatePath 回调(回调中的 context 为当前 Agent 实例)。
    • 引用机制仅用于防止 Cookie 被写入 Midscene Test 的持久化结果中;环境变量、Profile 和 storageState 文件本身仍需妥善保管,切勿将包含真实 Cookie 的文件提交到代码仓库。

    Puppeteer

    Puppeteer 同样提供同名的 gotoUrl、setCookies、clearCookies 和 setViewportSize Node,参数结构与 Cookie 脱敏规则与 Playwright 完全一致。使用时需安装 puppeteer 并将 PuppeteerAgent(或 PuppeteerBrowserAgent)传给 createMidsceneNodes():

    pnpm add -D puppeteer
    import { PuppeteerAgent } from '@midscene/web/puppeteer';
    import { createMidsceneNodes } from '@midscene/test/midscene';
    
    const midsceneNodes = createMidsceneNodes<ProjectContext>({
      agentClass: PuppeteerAgent,
      getAgent: ({ context }) => {
        context.agent ??= new PuppeteerAgent(context.page, {
          testRunner: { baseURL: 'https://example.com' },
        });
        return context.agent;
      },
    });

    为了方便同一份 YAML 用例在 Playwright 和 Puppeteer 之间平滑切换,gotoUrl.waitUntil 推荐使用跨浏览器通用的 domcontentloaded、load 或 networkidle(Puppeteer 适配层会自动将 networkidle 映射为 networkidle0)。两者的专有枚举值(Playwright 的 commit,Puppeteer 的 networkidle0 与 networkidle2)仍可在各自驱动下使用,但跨驱动混用时会直接报错。此外,调用 gotoUrl 传入相对路径时,会优先基于 testRunner.baseURL 解析;若未配置 baseURL,则基于当前页面的 HTTP(S) 地址解析。

    Android

    接入以下移动端平台时,请在 ProjectContext 中声明对应平台类型的 agent,并在 setup 返回的对象中提供该实例。

    使用 createMidsceneNodes({ agentClass: AndroidAgent, getAgent }) 会注册 Android 专属的 launch、terminate、runAdbShell、back、home 和 recentApps:

    import { AndroidAgent } from '@midscene/android';
    import { createMidsceneNodes } from '@midscene/test/midscene';
    
    const androidNodes = createMidsceneNodes<ProjectContext>({
      agentClass: AndroidAgent,
      getAgent: ({ context }) => context.agent,
    });
    beforeEach:
      - runAdbShell:
          command: pm clear com.example.app
          options:
            timeout: 5000
      - launch:
          uri: com.example.app

    runAdbShell 的完整命令输出会保存在该步骤的执行结果中。

    iOS

    使用 createMidsceneNodes({ agentClass: IOSAgent, getAgent }) 会注册 iOS 专属的 launch、terminate、runWdaRequest、home 和 appSwitcher:

    import { IOSAgent } from '@midscene/ios';
    import { createMidsceneNodes } from '@midscene/test/midscene';
    
    const iosNodes = createMidsceneNodes<ProjectContext>({
      agentClass: IOSAgent,
      getAgent: ({ context }) => context.agent,
    });
    steps:
      - launch:
          uri: com.example.app
      - runWdaRequest:
          request:
            method: GET
            endpoint: /status
      - terminate:
          uri: com.example.app

    runWdaRequest 的完整响应数据会保存在该步骤的执行结果中。

    HarmonyOS

    使用 createMidsceneNodes({ agentClass: HarmonyAgent, getAgent }) 会注册 HarmonyOS 专属的 launch、terminate、runHdcShell、back、home 和 recentApps:

    import { HarmonyAgent } from '@midscene/harmony';
    import { createMidsceneNodes } from '@midscene/test/midscene';
    
    const harmonyNodes = createMidsceneNodes<ProjectContext>({
      agentClass: HarmonyAgent,
      getAgent: ({ context }) => context.agent,
    });
    steps:
      - runHdcShell:
          command: bm dump -a
      - home: {}

    runHdcShell 的完整命令输出会保存在该步骤的执行结果中。

    配置执行项目

    执行项目(Project)用于将特定的运行环境与一组测试用例绑定。即便工程里只有一个执行项目,你也可以在其中配置用例筛选规则、项目变量和失败重试次数;当需要在不同浏览器、设备或环境上运行测试时,则可以在 projects 数组中声明多个执行项目。

    选择用例与控制执行

    配置项含义
    projects[].filesinclude 指定要包含的 YAML 文件,exclude 排除匹配的文件(路径相对于测试根目录)。
    projects[].tags按 include / exclude 标签规则筛选用例。
    projects[].variables定义项目变量,供 YAML 中的 ${variable} 占位符读取。
    projects[].retry用例执行失败后的最大重试次数,默认为 0。
    test.testTimeout单个步骤的默认超时时间(毫秒),默认为 120000。步骤内的 $.timeout 可覆盖该默认值。
    test.bail失败用例数达到该阈值后停止调度新任务;设为 0 表示不限制。
    output.reportDirHTML 报告的输出目录,默认为 ./midscene_run/report。
    output.reportFormat'single-html'(默认)将执行数据和图片打包在一个 HTML 中,可直接离线打开;'html-and-external-assets' 生成目录报告,按内容复用图片文件,需通过 HTTP 预览。最终报告格式独立于 Agent 源记录的保存格式。

    脚手架生成的配置默认匹配 cases/**/*.{yaml,yml};如果未配置 files,Midscene Test 会按 **/*.{yaml,yml} 在测试根目录下递归查找用例文件,自动去重并按路径排序。

    关于如何通过命令行筛选运行目标,请参阅运行测试;单个步骤的超时与容错配置请参阅设置超时和错误处理;执行顺序、重试与并发规则请参阅生命周期与并发。所有执行项目的运行结果最终都会汇总生成一份统一的 HTML 报告,查看与归档方式见运行测试。

    配置多个执行项目

    当需要在多个平台或设备上运行测试时,可以在 defineTestProject() 的 projects 数组中配置多个执行项目。

    在顶层 nodes 中注册的 Node 对所有执行项目全局生效(省略时默认为 [])。同时,每个执行项目也可以通过自身的 nodes 字段注册项目级 Node——项目级 Node 仅对当前项目生效,若与全局 Node 同名则会覆盖全局定义。注意,在同一层级内重复注册同名 Node 会直接报错。

    例如,同时配置 Android 和 iOS 两个执行项目时,可以将跨端通用的业务 Node 放在顶层 nodes,而在各自项目中分别注册对应平台的官方 Node:

    import { AndroidAgent } from '@midscene/android';
    import { IOSAgent } from '@midscene/ios';
    import { defineTestProject } from '@midscene/test/config';
    import { createMidsceneNodes, type MidsceneUIAgent } from '@midscene/test/midscene';
    import { sharedNodes } from './nodes';
    import { androidSetup, iosSetup } from './setup';
    
    interface ProjectContext {
      agent: MidsceneUIAgent;
    }
    
    export default defineTestProject<ProjectContext>({
      nodes: sharedNodes,
      projects: [
        {
          name: 'android-smoke',
          setup: androidSetup,
          nodes: createMidsceneNodes<ProjectContext>({
            agentClass: AndroidAgent,
            getAgent: ({ context }) => context.agent,
          }),
          files: {
            include: ['cases/**/*.{yaml,yml}'],
            exclude: ['cases/**/*.draft.yaml'],
          },
          tags: { include: ['smoke'], exclude: ['manual'] },
          retry: 1,
          variables: { appUri: 'com.example.app' },
        },
        {
          name: 'ios-smoke',
          setup: iosSetup,
          nodes: createMidsceneNodes<ProjectContext>({
            agentClass: IOSAgent,
            getAgent: ({ context }) => context.agent,
          }),
          files: { include: ['cases/**/*.{yaml,yml}'] },
          variables: { appUri: 'com.example.ios' },
        },
      ],
      test: {
        maxConcurrentProjects: 1, // 同时运行的执行项目数量上限
        bail: 0,                  // 大于 0 时,失败用例数达到此值后停止调度新任务
        testTimeout: 120_000,
      },
      output: {
        reportDir: './midscene_run/report',
      },
    });

    通过这种方式,两个执行项目可以复用同一份 YAML 用例文件:在收集用例、校验参数和实际执行时,launch 等同名平台 Node 会自动绑定到当前项目注册的实现上,互不干扰。

    为各项目生成 Node 说明书

    运行 midscene-test nodes 可以根据项目的注册配置生成 Node 说明书。传入 --project 参数时,生成的说明书会列出该执行项目合并全局与项目级 Node 后最终生效的完整列表:

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

    如果配置了 projects 且未传入 --project 参数,命令默认会为每个执行项目分别生成一份独立的说明书。关于文件命名规则与说明书结构,请参阅生成当前项目的 Node 说明书。

    编程式 API

    除了使用 CLI 运行测试外,你也可以通过编程式 API 将 Midscene Test 集成到自定义工具链(如内部测试平台或本地 GUI 面板)中:

    import { loadTestProject, runTestProject } from '@midscene/test/config';
    import {
      CaseRunner,
      createCaseRunner,
      runWorkflowDocument,
    } from '@midscene/test';
    • loadTestProject(path):异步加载指定路径的 .ts 或 .mjs 配置文件(不支持同步加载)。
    • runTestProject():异步发现、执行并汇总整个测试工程的运行结果。
    • runWorkflowDocument():执行单个工作流文档(包含其完整生命周期钩子与内部所有 Case)。
    • CaseRunner / createCaseRunner():直接执行纯对象形式的单条用例(不包含文件解析与文档级生命周期)。

    以下示例展示如何在代码中运行整个测试工程并传递退出码:

    import { runTestProject } from '@midscene/test/config';
    
    try {
      const result = await runTestProject({
        projectRoot: process.cwd(),
        configPath: './midscene.config.ts',
        resultDir: './test-results',
      });
      console.log(result.summaryPath, result.reportPath);
      process.exitCode = result.exitCode;
    } catch (error) {
      console.error(error);
      process.exitCode = 1;
    }

    下一步

    • 生命周期与并发:了解资源共享范围、重试机制、并发调度、超时与取消规则。
    • 运行测试:了解命令行参数、路径解析规则与加载环境变量方式。