- 测试
- 移动开发
- 开发工具
- CLI
【免费下载链接】Maestro
Painless E2E Automation for Mobile and Web
导读
本文面向在 CI(如 GitHub Actions)上运行 Maestrotest-android流程并希望快速定位失败根因的工程师与 Agent。它围绕仓库中 diagnose-maestro-failure.md 定义的诊断方法论展开:从本地 artifact 目录或 GitHub Actions URL 出发,通过commands-*.json、截图与maestro.log三者交叉验证,将每条新失败流程分类为「测试流程问题 / Maestro 驱动缺口 / App 侧问题 / 框架缺陷」,并识别级联失败组,最终输出结构化诊断报告。读完本文,你将掌握一套可复用的、低上下文开销的 CI 失败归因流程,并理解其背后的 artifact 生成原理。
一、诊断的输入与前提
诊断 Agent 接收两种输入中的一种:
- 本地 artifact 目录:例如
/Users/.../maestro-root-dir-android或/tmp/maestro-android-<run_id>,目录下必须包含tests/子树。 - GitHub Actions URL:形如
https://github.com/mobile-dev-inc/Maestro/actions/runs/<run_id>或.../runs/<run_id>/job/<job_id>。
若传入的是 URL,先提取run_id,再用gh命令将对应的 artifact 下载到本地:
RUN_ID=<extracted> DEST=/tmp/maestro-android-$RUN_ID gh run download "$RUN_ID" --repo mobile-dev-inc/Maestro \ --name maestro-root-dir-android -D "$DEST"前置校验:如果目录下没有tests/demo_app/passing/子树(例如拿到的是 iOS artifact,或者任务在测试运行前就失败了),则直接报告该情况并停止——不存在可诊断的信号。
一个关键前提:passing/ 才是信号,failing/ 必须忽略
artifact 中同时存在passing/与failing/两套套件,但只有前者是信号源。failing/是「负路径」套件——其中命令的预期结果就是失败(例如断言元素不存在),因此它们的 FAILED 状态不构成回归证据,必须整体忽略。
cd <artifact_root>/tests/demo_app/passing grep -l '"FAILED"' commands-*.json这条 grep 是唯一的候选流筛选器:它会返回所有在 JSON 中存在终结性FAILED状态的流程。
二、权威数据源:commands-*.json 的元数据结构
诊断的核心事实来源是commands-*.json,而非带 ❌ 标记的截图文件。每个 JSON 条目包含:
- command:命令类型(command 对象下的单一键,如
tapOn、assertVisible); - metadata.status:可选值
COMPLETED(成功)与FAILED(终结性失败); - metadata.timestamp:毫秒级 epoch 时间戳;
- metadata.sequenceNumber:命令在流程内的序号;
- metadata.duration:命令执行耗时。
关于duration有一个高价值判读技巧:约 17000 ms 的耗时等于默认等待超时时间,这通常表明 UI 被阻塞(例如系统对话框挡住了元素查找),而不是崩溃——崩溃通常表现为快速失败或堆栈信息。
从源码看,这些字段由 CommandDebugMetadata 定义,状态枚举完整包含PENDING / RUNNING / COMPLETED / FAILED / WARNED / SKIPPED(见 CommandStatus.kt)。序列化写入由 TestOutputWriter.saveCommands() 完成——它逐条将「执行过的步骤」写入 JSON,并为每个步骤附带 metadata 包装;错误对象只序列化message与debugMessage两个字段,完整堆栈保留在maestro.log中。
元数据中的 depth 与「每次执行一条记录」
值得注意的实现细节是:executedSteps采用每次执行一条记录(per-execution)的语义,depth字段记录嵌套层级——顶层为 0,每进入一次runFlow/repeat/retry递增 1。这意味着同一个命令在一次流程中被重复执行时,会生成多条 JSON 记录,这也直接支撑了下文关于 retry 恢复场景的判读。
三、retry 恢复场景:为什么 ❌ 截图不一定是失败证据
文档以commands-(retry).json为典型范例,展示了retryCommand指令下的行为。该流程中:一次 tap 失败 → Maestro 自动重试 → 重试成功 → 流程整体通过。对应的 artifact 表现为:
- 所有条目(包括最终恢复成功的
tapOnElement)的metadata.status均为COMPLETED——Maestro 对恢复成功的命令只写入最终结果,不写入失败的尝试; - 仍存在一张
screenshot-❌-<ts>-(retry).png,它拍摄于失败尝试发生、但重试尚未成功的那一刻; - 因此上述 grep(
grep -l '"FAILED"')不会匹配该文件——JSON 中没有任何"FAILED"字符串。
从实现上验证:retryCommand的执行逻辑位于 Orchestra.kt,maxRetries默认取 YAML 中配置的值(缺省为 1,见 YamlFluentCommand.kt),并封顶MAX_RETRIES_ALLOWED。重试针对的失败类型是MaestroException(元素找不到、断言失败等测试级 flaky 问题),而驱动传输失败、JS 求值 bug、CancellationException等会直接向上传播,不做重试。
结论:不要把 ❌ 截图单独当作失败证据。若某个流程的 JSON 中没有任何FAILED条目,它内部的 ❌ 截图来自被恢复的重试,与回归无关,无需调查。
四、逐流程调查的标准步骤
对 grep 返回的每个候选流程:
- 打开
commands-(<flow>).json,定位metadata.status == "FAILED"的条目——这就是终结性失败。记录:命令类型、错误消息、metadata.timestamp、metadata.sequenceNumber、metadata.duration。 - 打开时间戳与该 FAILED 条目匹配的
screenshot-❌-<timestamp>-(<flow>).png。这是信号最强的 artifact——当系统对话框对 JSON 和日志不可见时,只有截图能暴露真相,必须始终读取。同一文件内其他时间戳的 ❌ 截图是恢复的重试,忽略。 - 在
maestro.log中 grep 流程名与时间窗,寻找周边的 driver 活动、gRPC 错误与堆栈信息。
截图与流程的配对关系在 ArtifactsGenerator.kt 中建立:每个执行的步骤在开始时记录 metadata,若命令「可见」(即对屏幕产生操作,见 StepArtifactNaming.capturesScreenshot())则抓取步骤截图;命令结束时回写最终状态与耗时。截图文件命名规则为step-<NNN>-<slug>,NNN 为 1 基的序号(最小宽度 3),slug 由命令类型与关键参数(如 appId、选择器、坐标)生成,保证截图与层级文件在「截图叠层级」视图中成对出现。
五、失败分类表与修复落点
| 失败时的屏幕 | 分类 | 修复落点 |
|---|---|---|
| 预期的 App 界面,但选择器匹配不到 | 测试流程问题(Test flow issue) | e2e/demo_app/.maestro/**/*.yaml |
| Android / GMS 系统对话框挡住了 App | Maestro 驱动缺口(缺少 auto-grant / auto-dismiss) | maestro-client/src/main/java/maestro/drivers/AndroidDriver.kt或.github/workflows/test-e2e.yaml(模拟器预配置) |
| Pixel 启动器出现在系统对话框后面 | 同左——对话框在launchApp/clearState/stopApp之间抢占了焦点 | 同左 |
| App 崩溃对话框 / 空白屏幕 | App 侧问题 | 超出范围——仅报告 |
maestro.log中出现来自maestro.*的堆栈 | Maestro 框架缺陷 | maestro-client//maestro-orchestra//maestro-android/ |
分类为driver gap或framework bug时,应派遣Explore子代理进入相应模块定位有问题的代码路径,在提出行号之前必须验证,禁止猜测。例如 Android 侧驱动实现位于 AndroidDriver.kt,测试流程 YAML 位于 e2e/demo_app/.maestro,CI 工作流配置可参考仓库中的.github/workflows/test-e2e.yaml(本文仅列出路径,行号以 Explore 验证结果为准)。
六、级联失败检测:一次根因,一个修复
级联检测是诊断的关键环节:单个系统对话框可能让其后许多流程接连失败,因为clearState/launchApp/stopApp并不会自动关闭系统级浮层。
操作方法:按时间戳升序列出所有 FAILED 条目;若下游流程的截图显示同一个浮层,则将它们归入根触发点(最早弹出对话框的那个流程)的分组之下。修复时对每个根只提一个修复方案,而不是为级联中的每个流程各提一个修复。
时间轴(示意) 流程 A FAILED —— 弹出 GMS 对话框(根触发) 流程 B FAILED —— 同一对话框仍挡在界面上(级联成员) 流程 C FAILED —— 同一对话框(级联成员) → 只针对流程 A 提出一个修复七、结构化输出格式
诊断完成后必须返回可被调用方解析的固定结构,逐字保留以下框架:
## Summary <一行:多少流程失败、多少个根因、多少个级联组> ## Root causes (caller acts on each) ### 1. <flow-or-group-label> — <classification> - **Trigger:** <什么引发了该问题> - **Affected flows:** <flow1>, <flow2>, ... (N flows) - **Cascade?** yes/no - **Proposed fix:** - File: `<exact path>:<line range>` - What it does: <一句话> - Diff (unified or pseudo): ``` - old line + new line ``` - Side effects: <若有则写,否则 none> - Verified via Explore? <yes — line numbers confirmed | no — fix is in CI yaml or test flow yaml, line numbers from direct read> ### 2. ... ## Out of scope - `<flow>` — <原因,例如 app crash、环境问题> ## Notes <调用方应知道但不属于修复建议的内容>约束清单
- 只诊断,不改动:不得编辑、写入或提交任何文件。
- 不逐成员提修复:级联组成员共享一个根因修复。
- 不猜测行号:Kotlin 行号必须经 Explore 子代理验证后才写入报告。
- 不把 failing/ 当失败:负路径套件的 FAILED 不是回归。
- 不单独信任 ❌ 截图:grep(
grep -l '"FAILED"' commands-*.json)才是判断哪个流程存在终结性失败的唯一权威;JSON 无FAILED条目的流程内的 ❌ 截图来自被恢复的重试(典型范例即commands-(retry).json)。 - 始终读截图:即使 JSON + 日志看起来已指向明确原因,也要读截图——系统浮层只有截图能暴露。
八、何时结束并交还控制权
只要满足以下条件就立即交还,不做循环、重试或尝试应用修复:passing 套件中的每条终结性 FAILED 命令,要么已被分类并附上修复建议,要么已被归类为带原因的 out-of-scope。诊断 Agent 的职责边界是产出结构化报告,修复的同意权与应用动作归调用方。
结语
这套诊断方法论的根基是 Maestro 的 artifact 生成机制:commands-*.json记录每次执行的命令与 metadata(TestOutputWriter.kt、FlowDebugOutput.kt),截图与流程序号一一配对(ArtifactsGenerator.kt、StepArtifactNaming.kt),retry 的最终结果写入由 Orchestra.kt 保证。理解了这些底层规则,你就能在 CI 失败洪流中快速分清「真失败」「恢复的重试」与「级联噪音」,把每条失败归因到正确的修复落点。
- 测试
- 移动开发
- 开发工具
- CLI
【免费下载链接】Maestro
Painless E2E Automation for Mobile and Web
相关推荐
loop-engineering CI 故障分诊技能(ci-triage)实战指南:从失败分类到最小修复的 Agent 循环
loop engineering CI 故障分诊技能(ci triage)实战指南:从失败分类到最小修复的 Agent 循环 本指南以 loop enginee
人工智能AI AgentAgent 工作流CLI研发协作AI 技能MCP 服务如何用Electron打造终极番茄工作法应用:Pomolectron完整指南 🍅
如何用Electron打造终极番茄工作法应用:Pomolectron完整指南 🍅 在当今快节奏的工作环境中,专注力已成为最稀缺的资源之一。番茄工作法作为一种经
桌面应用Agent QA 失败结果分类(Triage):基于证据的 Agent QA 运行故障研判指南
Agent QA 失败结果分类(Triage):基于证据的 Agent QA 运行故障研判指南 在 Agentic Awesome Skills(AAS)仓库的
AI 技能AI 插件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考