Maestro Mobile Testing
Black-box mobile UI testing with Maestro YAML flows - launchApp, tapOn, inputText, assertVisible, reusable runFlow subflows, environment parameters, JUnit reporting, and emulator-based CI pipelines.
- License 许可
- MIT
- 最近更新
- 2026-11-04
- Stars
- ★ 0
- Forks
- 0
01 前言 Front Matter
- name
- Maestro Mobile Testing
- tags
- [ "maestro", "mobile", "e2e", "ios", "android", "yaml", "flows", "ui-testing", "flutter", "react-native" ]
- agents
- [ "claude-code", "cursor", "github-copilot", "windsurf", "codex", "aider", "continue", "cline", "zed", "bolt", "gemini-cli", "amp" ]
- author
- thetestingacademy
- domains
- [ "mobile" ]
- license
- MIT
- version
- 1.0.0
- languages
- [ "typescript" ]
- frameworks
- [ "appium" ]
- description
- Black-box mobile UI testing with Maestro YAML flows - launchApp, tapOn, inputText, assertVisible, reusable runFlow subflows, environment parameters, JUnit reporting, and emulator-based CI pipelines.
- testingTypes
- [ "mobile", "e2e" ]
03 SKILL.md 正文
Maestro Mobile Testing
This skill makes an AI agent write Maestro flows - declarative YAML files that drive iOS and Android apps black-box style with built-in waiting, no test harness compiled into the app, and no WebDriver session management. Trigger it when a repository contains a .maestro/ directory or *.yaml flows with appId: headers, or when the user wants fast, low-maintenance smoke tests for a native, React Native, or Flutter app without the weight of Appium.
Core Principles
- Maestro waits by default; do not teach it to sleep. Every
tapOnandassertVisiblepolls until the element appears or a timeout expires. Reach forextendedWaitUntilfor slow screens; never add fixed delays as a first resort. - One flow per user-visible behavior. A flow named
checkout-with-saved-card.yamlthat does exactly that is debuggable. A 200-lineregression.yamlis not. Compose bigger journeys from subflows withrunFlow. - Select by accessibility id first, visible text second.
tapOn: id: "submit-button"survives copy changes and localization; text selectors are acceptable for stable, single-language labels only. - Start from a clean, deterministic state.
launchAppwithclearState: trueresets the app between flows; tests that inherit the previous flow's logged-in session fail in random orders. - Parameterize with env, not copies. Credentials and hosts go in
env:blocks or-e KEY=valueCLI arguments so the same flow runs against dev, staging, and CI builds. - Treat flows as code. They live in the repo next to the app, run on every PR via emulator CI, and produce JUnit XML that the pipeline understands.
Setup
# Install the Maestro CLI
curl -fsSL "https://get.maestro.mobile.dev" | bash
export PATH="$PATH:$HOME/.maestro/bin"
maestro --version
# Run one flow against the booted simulator/emulator
maestro test .maestro/login.yaml
# Run the whole suite with JUnit output for CI
maestro test .maestro/ --format junit --output maestro-report.xml
# Interactive selector explorer while authoring
maestro studio
Patterns
1. A complete login flow
# .maestro/login.yaml
appId: com.example.shop
env:
EMAIL: qa@example.com
PASSWORD: Str0ngPass!
---
- launchApp:
clearState: true
- tapOn: 'Log in'
- tapOn:
id: 'email-input'
- inputText: ${EMAIL}
- tapOn:
id: 'password-input'
- inputText: ${PASSWORD}
- hideKeyboard
- tapOn:
id: 'login-submit'
- assertVisible: 'Welcome back'
- assertNotVisible: 'Invalid email or password'
- takeScreenshot: logged-in-home
2. Subflows with runFlow: compose journeys, handle one-off dialogs
# .maestro/subflows/login.yaml -- reusable building block
appId: com.example.shop
---
- launchApp:
clearState: true
- tapOn: 'Log in'
- tapOn:
id: 'email-input'
- inputText: ${EMAIL}
- tapOn:
id: 'password-input'
- inputText: ${PASSWORD}
- tapOn:
id: 'login-submit'
- assertVisible:
id: 'home-screen'
# .maestro/checkout.yaml -- the journey composes the subflow
appId: com.example.shop
env:
EMAIL: qa@example.com
PASSWORD: Str0ngPass!
---
- runFlow: subflows/login.yaml
# Dismiss the push-permission prompt only if it appears
- runFlow:
when:
visible: 'Allow notifications?'
commands:
- tapOn: 'Allow'
- tapOn: 'Deals'
- scrollUntilVisible:
element:
text: 'Wireless Headphones'
direction: DOWN
timeout: 20000
- tapOn: 'Wireless Headphones'
- tapOn:
id: 'add-to-cart'
- tapOn:
id: 'cart-icon'
- assertVisible: 'Wireless Headphones'
- assertVisible:
text: 'Checkout'
enabled: true
3. Waiting, repeats, and assertions with conditions
# .maestro/order-status.yaml
appId: com.example.shop
---
- launchApp
- tapOn:
id: 'tab-orders'
# Wait up to 15s for async content instead of a blind sleep
- extendedWaitUntil:
visible:
id: 'orders-list'
timeout: 15000
# Pull-to-refresh until the order flips to Shipped, max 5 tries
- repeat:
while:
notVisible: 'Shipped'
times: 5
commands:
- swipe:
direction: DOWN
duration: 400
- assertVisible:
text: 'Shipped'
- copyTextFrom:
id: 'order-number'
- assertTrue: ${maestro.copiedText != ''}
4. CI: Android emulator on GitHub Actions
# .github/workflows/maestro-android.yml
name: maestro-android
on: [pull_request]
jobs:
flows:
runs-on: ubuntu-latest
timeout-minutes: 40
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Build debug APK
run: ./gradlew assembleDebug
- name: Install Maestro
run: |
curl -fsSL "https://get.maestro.mobile.dev" | bash
echo "$HOME/.maestro/bin" >> "$GITHUB_PATH"
- name: Run flows on emulator
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 34
arch: x86_64
profile: pixel_7
script: |
adb install app/build/outputs/apk/debug/app-debug.apk
maestro test .maestro/ --format junit --output maestro-report.xml \
-e EMAIL=ci-bot@example.com -e PASSWORD="${{ secrets.TEST_USER_PASSWORD }}"
- name: Publish report
if: always()
uses: actions/upload-artifact@v4
with:
name: maestro-report
path: |
maestro-report.xml
~/.maestro/tests
For hosted device execution, the same suite uploads unchanged: maestro cloud --api-key "$MAESTRO_CLOUD_API_KEY" app-debug.apk .maestro/ runs every flow on cloud devices and returns a pass/fail exit code CI can gate on.
Best Practices
- Use
maestro studioto discover ids and text before writing selectors by hand; it shows exactly what the accessibility tree exposes. - Add accessibility identifiers in app code (
testIDin React Native,accessibilityIdentifieron iOS,contentDescription/resource-idon Android) as part of feature work. - Keep shared steps in
subflows/and one top-level flow per journey; flows read top to bottom like a manual test script, keep them that readable. - Tag smoke flows with YAML
tags: [smoke]and runmaestro test --include-tags smokeon every PR, the full suite nightly. - Capture
takeScreenshotat journey milestones; screenshots plus the JUnit report make CI failures diagnosable without a local repro. - Pin the emulator API level and profile in CI; device drift is the top source of "passes locally" mysteries.
Anti-Patterns
- Sprinkling
- waitForAnimationToEndand longextendedWaitUntiltimeouts everywhere to paper over an app that never settles; fix the spinner, not the test. - Selecting by index (
tapOn: point: 50%,30%or index-based taps) for elements that have ids; coordinate taps break on every screen size. - One giant flow covering login, browse, checkout, refunds, and settings: a failure at step 40 costs a full re-run to debug.
- Hardcoding production credentials in flow files; use
env:plus CI secrets. - Running flows only on a developer's personal device before release instead of an emulator on every PR.
- Re-implementing Appium-style page objects in JavaScript wrappers around Maestro; the YAML is the abstraction, keep logic out of it.
When to Trigger This Skill
- A repository contains a
.maestro/directory, YAML files starting withappId:, ormaestrocommands in CI workflows. - The user wants mobile UI smoke tests with minimal setup, or asks to test a React Native, Flutter, or native app without Appium infrastructure.
- An existing Appium suite is too slow or flaky for PR-level smoke coverage and the team wants a lighter black-box layer on top.
- Mobile onboarding, login, or checkout journeys need regression coverage that designers and QA can read and edit.
- Choose Maestro for declarative cross-platform flows; recommend Detox when the team needs gray-box React Native synchronization, or Appium when tests must script complex logic in a full programming language.
04 同仓库更多 Skills
nemoclaw-user-reference
Describes the NemoClaw integration layer and blueprint architecture and how they orchestrate compatible agent sandboxes. Use when looking up architecture, agent integration, plugin structure, or blueprint design. Trigger keywords - nemoclaw architecture, nemoclaw agent architecture, nemoclaw plugin blueprint structure, nemoclaw vs openshell, which cli, nemoclaw cli, openshell cli, sandbox commands, nemoclaw cli commands, nemoclaw command reference, nemoclaw network policy, sandbox egress control operator approval, nemoclaw troubleshooting, nemoclaw debug sandbox issues.
nemoclaw-user-overview
Explains how OpenClaw, OpenShell, and NemoClaw form the ecosystem, NemoClaw's position in the stack, what NemoClaw adds beyond the community sandbox, and when to prefer NemoClaw versus integrating OpenShell and OpenClaw directly. Use when users ask about the relationship between OpenClaw, OpenShell, and NemoClaw, or when to use NemoClaw versus OpenShell. Trigger keywords - nemoclaw ecosystem, openclaw openshell, nemoclaw vs openshell, sandboxed openclaw, how nemoclaw works, nemoclaw sandbox lifecycle blueprint, nemoclaw overview, openclaw always-on assistants, nvidia openshell, nvidia nemotron, nemoclaw release notes, nemoclaw changelog.
nemoclaw-user-monitor-sandbox
Inspects sandbox health, traces agent behavior, and diagnoses problems. Use when monitoring a running sandbox, debugging agent issues, or checking sandbox logs. Trigger keywords - monitor nemoclaw sandbox, debug nemoclaw agent issues.
nemoclaw-user-manage-sandboxes
Explains operational tasks after the quickstart: listing sandboxes, status and health checks, logs, diagnostics, port forwards, multiple sandboxes, credential reset, rebuilds, network presets, upgrades, and uninstall. Trigger keywords - manage nemoclaw sandboxes, nemoclaw status, nemoclaw list, nemoclaw dashboard port, nemoclaw rebuild, nemoclaw upgrade sandboxes, nemoclaw uninstall, sandbox mutability, sandbox runtime configuration, sandbox rebuild, nemoclaw backup, nemoclaw restore, workspace backup, openshell sandbox download upload, nemoclaw messaging channels, nemoclaw telegram, nemoclaw discord, nemoclaw slack, nemoclaw wechat, nemoclaw whatsapp, openshell channel messaging, nemoclaw workspace files, soul.md, user.md, identity.md, agents.md, sandbox persistence.
nemoclaw-user-manage-policy
Adds, removes, or modifies allowed endpoints in the sandbox policy. Use when customizing network policy, changing egress rules, or configuring sandbox endpoint access. Trigger keywords - customize nemoclaw network policy, sandbox egress policy configuration, nemoclaw integration policy examples, post-install policy setup, openshell approval workflow, policy preset, nemoclaw approve network requests, sandbox egress approval tui.
nemoclaw-user-get-started
Installs NemoClaw, launches a sandbox, and runs the first agent prompt. Use when onboarding, installing, or launching a NemoClaw sandbox for the first time. Trigger keywords - nemoclaw quickstart, install nemoclaw openclaw sandbox, nemohermes quickstart, hermes agent nemoclaw, run hermes openshell sandbox, nemoclaw prerequisites, nemoclaw supported platforms, nemoclaw hardware software, nemoclaw windows wsl2 setup, nemoclaw install windows docker desktop.