midscene-test 实战:用 Test Project 搭建 YAML 驱动的 GUI 端到端测试
midscene-test 实战用 Test Project 搭建 YAML 驱动的 GUI 端到端测试【免费下载链接】midsceneGUI Agent for E2E Testing项目地址: https://gitcode.com/GitHub_Trending/mid/midscene本文基于 midscene 仓库的 Test Project 示例 展开讲清midscene/test的 Test Project 模型如何组织「一个配置 若干 YAML 用例」的独立测试项目、如何用midscene-test命令行运行、如何用自定义 Node 与生命周期管理浏览器资源以及运行结果summary、fact、报告落盘在哪里。读完本文你可以照着示例复制出一套可运行的 Playwright Midscene GUI 测试工程并理解其配置校验、并发/重试/bail、标签过滤与输出目录等底层机制。一、Test Project 是什么一个目录就是一个测试项目示例目录 的核心约定是每个子目录都是一个独立的 Test Project拥有自己的项目配置和 YAML 文件。目前仓库内置的示例是web-midscene使用 Playwright 和 Midscene Web 检查 Midscene 文档页是否跟随 UA 语言显示英文或中文该示例包含自定义节点、生命周期和 AI 断言三类要素恰好覆盖 Test Project 的核心能力面。Test Project 的承载包是midscene/testpackages/test其package.json声明了可执行入口midscene-test指向./bin/midscene-test并对外暴露三个子模块导出作用midscene/test引擎与 Node SDKdefineNode、错误类型、报告工具等见 src/index.tsmidscene/test/config项目配置 APIdefineTestProject、defineProjectSetupmidscene/test/midsceneMidscene Agent 节点工厂createMidsceneNodes及各 input schema该包要求 Node^20.19.0 || ^22.12.0 || 24.0.0。二、运行 web-midscene 示例在仓库根目录安装依赖并完成构建后可以运行指定的子项目packages/test/bin/midscene-test packages/test/example/web-midscene命令行会实时输出 Project、文档、用例、attempt、生命周期和 Step 的执行进度进度行形如[project 1/1] web、→ step 1/3: aiAct、✓ attempt 1/1: 用例名。运行完成后公开 summary 保存在子项目的.midscene/test-results/runId/summary.json各 Project 的 fact 保存在同一 run 目录下的project-index/子目录中报告仍保存在子项目的midscene_run目录中默认./midscene_run/report。2.1 这个示例在测什么web-midscene 用例 的流程是先把 UA 语言设为英文进入文档页并断言页面是英文文档再把 UA 语言切换为中文断言页面变为中文文档。完整 YAML 如下cases: - name: Midscene 文档语言跟随 UA 切换 tags: [smoke] steps: - browser.setLanguage: language: en - aiAct: prompt: 点击页面中的 Documentation 按钮进入 Midscene 文档页 $: timeout: 60_000 - aiAssert: prompt: 当前页面是 Midscene 的英文文档页。页面主体和导航使用英文例如可见 “Introduction” 和 “Quick start”并且不是中文文档页。 message: Midscene 文档页没有显示为英文 $: timeout: 60_000 - browser.setLanguage: language: zh - aiAssert: prompt: 当前页面是 Midscene 的中文文档页。页面主体和导航使用中文例如可见“介绍”和“快速开始”并且不是英文文档页。 message: Midscene 文档页没有显示为中文 $: timeout: 60_000 afterEach: - page.recordState: {} afterAll: - recordToReport: title: Midscene 文档语言切换测试完成 options: content: 已验证文档页会根据 UA 语言显示英文或中文。几个要点tags: [smoke]给用例打标签供 Project 的tags.include/exclude过滤步骤中的$字段是步骤级元数据引擎内部归一化为NormalizedStepMeta这里用它为 AI 步骤单独设置timeout: 60_00060 秒覆盖全局默认超时afterEach在每个用例结束后记录页面状态afterAll在文档级生命周期结束时向报告追加一条recordToReport记录模型配置从当前进程的环境变量读取默认无头模式设置HEADLESSfalse可显示浏览器窗口。三、项目配置 midscene.config.ts 逐项拆解示例的 midscene.config.ts 是理解整个框架的关键。先给出完整结构含注释import { defineNode } from midscene/test; import { defineProjectSetup, defineTestProject } from midscene/test/config; import { createMidsceneNodes } from midscene/test/midscene; import { PlaywrightAgent } from midscene/web/playwright/agent; import { type Browser, type Page, chromium } from playwright; interface ProjectContext { browser: Browser; page: Page; agent?: PlaywrightAgent; } const playwrightSetup defineProjectSetupProjectContext({ name: playwright, async setup({ onTeardown }) { const browser await chromium.launch({ headless: process.env.HEADLESS ! false, // 默认无头 args: [--no-sandbox, --disable-setuid-sandbox], }); onTeardown(() browser.close()); const browserContext await browser.newContext({ viewport: VIEWPORT }); const page await browserContext.newPage(); const context: ProjectContext { browser, page }; onTeardown(() context.page.context().close()); await openPage(page, https://midscenejs.com); return context; // 返回值作为本项目所有 Node 的共享 context }, }); export default defineTestProjectProjectContext({ projects: [ { name: web, files: { include: [midscene.yaml] }, setup: playwrightSetup, }, ], nodes: [setUserAgentLanguage, recordPageState, ...midsceneNodes], });结合 配置加载与校验源码各字段的实际约束与默认值如下。3.1 根级字段defineTestProject只接受setup、projects、test、output、nodes五个键出现其他键包括已废弃的setupWorkflow、setupDocument、root、files、testRunner会直接抛出TypeError。nodes全局 Node 注册表本项目内所有 Project 默认可用setup根级 setup 与projects不能同时使用——源码中显式抛出setup cannot be used together with projects。若只写根setup而不声明projects框架会构造一个隐式的defaultProjectprojectId为project-0把根 setup 作为它的 setuptest执行选项见 第五节;output目前仅支持reportDir默认./midscene_run/report。配置只支持.ts扩展名由 tsx 加载ESM 加载失败且属于 TypeScript 语法类错误时回退到 CJS 加载器且必须默认导出一个对象。3.2projects[]字段每个 Execution Project 接受name、setup、nodes、files、tags、retry、variables校验规则源码字段默认值说明name必填项目名必须唯一setup无defineProjectSetup产物{ name, setup(ctx) }ctx提供project、env冻结副本、signal与onTeardownnodes无Project 局部 Node 会覆盖同名的全局 Nodefilesinclude: [**/*.{yaml,yml}]glob 文件选择模式必须相对项目根、POSIX 分隔符、不允许..include中不允许取反模式应改用files.excludetags全量放行{ include, exclude }排除规则优先命中任一exclude即过滤include为空表示不限retry0用例失败后的额外重试次数attempt 总数为retry 1variables{}必须是 JSON 兼容值无循环引用加载后深度冻结可被 YAML 用例引用setup 的返回值即ProjectContext会在执行期通过NodeExecutionContext.context传给所有 Node。示例中browser.setLanguage节点正是通过context.page拿到当前页面、创建新 Context 后把context.page指向新页面并置空context.agent让后续 Agent 使用新页面——这就是「切换 UA 语言时创建新的 Playwright Context」的实现方式。3.3 生命周期与资源释放setup 内调用onTeardown(fn)注册的清理函数保存在栈中project-runtime示例文档说明资源在 Project 结束时按逆序释放并且即使 setup 部分失败已注册的 teardown 也会执行teardown 期间抛出的错误会被记录为teardownErrors使 Project 生命周期状态记为failed。onTeardown只在 setup 运行期间允许注册否则抛出WorkflowLifecycleError。四、自定义 NodedefineNode 与 createMidsceneNodes4.1 defineNode 的契约define-node.ts 中的defineNode对定义做严格校验name必须非空字符串title/description若提供必须是非空字符串inputSchema若是 Zod 对象不得声明名为$的输入属性$是步骤元数据的保留键stringInputKey若提供必须指向inputSchema中存在的字段。Node 的execute(execution)接收 NodeExecutionContext关键字段input经 schema 校验后的输入不含$$本步骤的归一化元数据如timeoutsignal本步骤的超时/取消AbortSignalcontextProject 共享上下文示例中的ProjectContextonTeardown注册用例 attempt 或文档级的资源清理report向当前 Step 结果附加报告引用如 Midscene 执行记录scopecase或document决定 Node 运行在用例级还是文档级生命周期中并给出对应的case/document标识信息。返回值NodeResult包含summary报告中的人类可读摘要与data结构化数据。示例的page.recordState返回{ language, title, url }browser.setLanguage返回切换后的 locale 与 URL这些都会进入步骤结果供报告展示。4.2 createMidsceneNodes把 Agent 能力注册成 YAML 节点midscene/index.ts 的createMidsceneNodes接受const midsceneNodes createMidsceneNodesProjectContext({ agentClass: PlaywrightAgent, getAgent: ({ context }) { context.agent ?? new PlaywrightAgent(context.page); // 惰性创建 return context.agent; }, });agentClass必须实现getTestRunnerNodeDefinitions()工厂据此注册aiAct、aiAssert、aiTap、recordToReport、reportScreenshot、insight等由 Agent 驱动的节点并额外注册一个wait节点支持durationunit: ms|s|min也可以传agentProvidergetAgent/releaseAgent/dispose以获得按 runId 的 Agent 生命周期管理和报告路径回收工厂内部用WeakMap防止同一 Agent 实例并发执行重叠的 Test Step并通过addDumpUpdateListener把每次 Midscene 执行 id 作为midscene-executiontrace 附加到 Step 报告上。这也印证了示例文档所说的「Agent 会在首次运行 Midscene Node 时创建」getAgent中context.agent ?? ...是典型的惰性初始化browser.setLanguage把context.agent置undefined后下一个 AI 步骤会用新页面的 Page 重新创建 Agent。五、test 选项与 YAML 文件选择validateTestOptions 给出了默认值选项类型默认值含义test.maxConcurrency正整数1并发执行的 Project 数实际取min(maxConcurrency, Project 数)test.bail非负整数0累计失败用例数达到该值后停止调度剩余用例标记not-run: bailtest.testTimeout正整数毫秒120_000用例/步骤的默认超时可被 YAML 步骤的$: { timeout }覆盖文件发现逻辑test-project-runner.ts默认选择**/*.{yaml,yml}可用files.include/exclude覆盖恒定忽略.git、.midscene、midscene_run、node_modules命中不到任何 YAML 文件会作为 collection error 记入本次 run而不是静默通过。六、运行流程与产物runTestProjecttest-project-runner.ts的执行主流程定位配置优先--config否则在项目根查找目录下只允许midscene.config.ts这一个配置文件名出现其他midscene.config.*变体会直接报错生成 runId格式为YYYYMMDDHHmmss- 8 位 UUID 片段createTestRunId预检与调度preflighted N projects, M documents, K cases, E collection errors按并发度启动 worker每个 Project 依次经历 setup 生命周期 → 逐文档执行beforeAll→ 每个 case 的beforeEach/steps/afterEach retry attempts →afterAll→ teardown产物项目根/.midscene/test-results/runId/summary.json整体 summarytotal/passed/failed/notRun/filtered/collectionErrors/documentFailures/projectFailures与全部用例、文档结果project-index/子目录各 Project 的 fact用例 attempt、文档结果、collection errormidscene_run/下由TestRunReportAssembler生成的 HTML 报告文件名为test-run-runId退出码只要有 failed、not-run、collection error、document failure 或 project failureexitCode为 1否则为 0可直接用于 CI 判定。CLI 层test-command.ts支持的参数# 基本用法项目目录 只能是单个位置参数 midscene-test project-dir [--config path] [--result-dir dir] [--project name...] # 生成 Node 参考文档输出到 搜索根/midscene-node-reference.md并打印已注册 Node 清单 midscene-test nodes [--project name] [--config path] # 脚手架命令 midscene-test create--project可按名字只运行指定 Project名字必须唯一出现一次且真实存在nodes命令把当前 Test Project 注册的全部 Node 渲染成 Markdown 参考文档——当 Project 局部 Node 与全局 Node 产生同名覆盖时多 Project 的nodes输出会提示你用--project指定其一。七、小结与延伸路径回到示例目录 packages/test/example 的定位它是「一个目录即一个 Test Project」约定的最小样板web-midscene则演示了完整能力闭环——defineProjectSetup管理浏览器生命周期、defineNode扩展自定义步骤、createMidsceneNodes接入 AI 能力、YAML 组合aiAct/aiAssert与$超时、afterEach/afterAll记录状态并写入报告。如果要继续深入当前仓库建议按以下顺序阅读packages/test/example/web-midscene/midscene.yaml 与 midscene.config.ts示例本体packages/test/src/cli/test-project.ts配置校验的全部约束与默认值packages/test/src/midscene/index.tsAgent 节点工厂与报告 trace 机制packages/test/src/node/types.tsNodeExecutionContext完整类型定义packages/test/tests/e2e/fixtures/test-project多文档、多 Project 的端到端测试夹具以及 tests/test-project.test.ts、tests/test-project-runner.test.ts 等对配置与调度行为的单元测试。【免费下载链接】midsceneGUI Agent for E2E Testing项目地址: https://gitcode.com/GitHub_Trending/mid/midscene创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考