Source profileQuality 86/100

PramodDutta/qaskills/seed-skills/maestro-mobile/SKILL.md

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.

Source repository stars
195
Declared platforms
4
Static risk flags
1
Last source update
2026-08-04
Source checked
2026-08-04

Decision brief

What it does—and where it fits

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/ director…

Best for

    Not for

    • Sprinkling - waitForAnimationToEnd and long extendedWaitUntil timeouts 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.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexDeclaredSource recordInstall path and trigger
    Claude CodeDeclaredSource recordInstall path and trigger
    CursorDeclaredSource recordInstall path and trigger
    Gemini CLIDeclaredSource recordInstall path and trigger
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/PramodDutta/qaskills --skill "seed-skills/maestro-mobile"
    Safe inspection promptEditorial

    Inspect the Agent Skill "Maestro Mobile Testing" from https://github.com/PramodDutta/qaskills/blob/c924c5f7fee5fa410f267031061e492eb051757a/seed-skills/maestro-mobile/SKILL.md at commit c924c5f7fee5fa410f267031061e492eb051757a. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Setup

      Review the “Setup” section in the pinned source before continuing.

      Review and apply the “Setup” source section.
    2. 02

      Core Principles

      1. Maestro waits by default; do not teach it to sleep. Every tapOn and assertVisible polls until the element appears or a timeout expires. Reach for extendedWaitUntil for slow screens; never add fixed delays as a first resort. 2. One flow per user-visible behavior. A flow named…

      Maestro waits by default; do not teach it to sleep. Every tapOn and assertVisible polls until the element appears or a timeout expires. Reach for extendedWaitUntil for slow screens; never add fixed delays as a first res…One flow per user-visible behavior. A flow named checkout-with-saved-card.yaml that does exactly that is debuggable. A 200-line regression.yaml is not. Compose bigger journeys from subflows with runFlow.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.
    3. 03

      Install the Maestro CLI

      curl -fsSL "https://get.maestro.mobile.dev" | bash export PATH="$PATH:$HOME/.maestro/bin" maestro --version

      curl -fsSL "https://get.maestro.mobile.dev" | bash export PATH="$PATH:$HOME/.maestro/bin" maestro --version
    4. 04

      Run one flow against the booted simulator/emulator

      maestro test .maestro/login.yaml

      maestro test .maestro/login.yaml
    5. 05

      Run the whole suite with JUnit output for CI

      maestro test .maestro/ --format junit --output maestro-report.xml

      maestro test .maestro/ --format junit --output maestro-report.xml

    Permission review

    Static risk signals and limitations

    Network access

    medium · line 19

    The documentation includes network, browsing, or remote request actions.

    curl -fsSL "https://get.maestro.mobile.dev" | bash

    Network access

    medium · line 169

    The documentation includes network, browsing, or remote request actions.

    curl -fsSL "https://get.maestro.mobile.dev" | bash

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score86/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars195SourceRepository attention, not individual Skill quality
    Compatibility4 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    PramodDutta/qaskills
    Skill path
    seed-skills/maestro-mobile/SKILL.md
    Commit
    c924c5f7fee5fa410f267031061e492eb051757a
    License
    MIT
    Collected
    2026-08-04
    Default branch
    main
    View the original 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

    1. Maestro waits by default; do not teach it to sleep. Every tapOn and assertVisible polls until the element appears or a timeout expires. Reach for extendedWaitUntil for slow screens; never add fixed delays as a first resort.
    2. One flow per user-visible behavior. A flow named checkout-with-saved-card.yaml that does exactly that is debuggable. A 200-line regression.yaml is not. Compose bigger journeys from subflows with runFlow.
    3. 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.
    4. Start from a clean, deterministic state. launchApp with clearState: true resets the app between flows; tests that inherit the previous flow's logged-in session fail in random orders.
    5. Parameterize with env, not copies. Credentials and hosts go in env: blocks or -e KEY=value CLI arguments so the same flow runs against dev, staging, and CI builds.
    6. 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: [email protected]
      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: [email protected]
      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 protected] -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 studio to discover ids and text before writing selectors by hand; it shows exactly what the accessibility tree exposes.
    • Add accessibility identifiers in app code (testID in React Native, accessibilityIdentifier on iOS, contentDescription/resource-id on 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 run maestro test --include-tags smoke on every PR, the full suite nightly.
    • Capture takeScreenshot at 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 - waitForAnimationToEnd and long extendedWaitUntil timeouts 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 with appId:, or maestro commands 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.

    Alternatives

    Compare before choosing