Skip to content

Maestro setup

Run Maestro flows on Android and iOS devices in Marathon Cloud.

Marathon Cloud supports executing Maestro flows on both Android and iOS. The platform handles device provisioning and parallel execution of your YAML-defined flows.

Terminal window
marathon-cloud run maestro android \
--api-key $MARATHON_CLOUD_API_KEY \
--application app-debug.apk \
--test-application flows/

Each Maestro flow is a separate YAML file and becomes one test that can run in parallel with the others. Marathon Cloud discovers flows the same way maestro test does, so an existing workspace works unchanged.

appId: com.example.app
tags:
- smoke
---
- launchApp
- tapOn: "Login"
- inputText: "[email protected]"
- tapOn: "Password"
- inputText: "password123"
- tapOn: "Submit"
- assertVisible: "Welcome"

Flow discovery follows Maestro’s workspace rules:

  • By default only YAML files directly inside --test-application are flows. Files in subdirectories are ignored unless a config.yaml at the root of the flows directory lists them.
  • Flows referenced by runFlow (subflows) should live outside the matched patterns so they are not run on their own.
  • includeTags / excludeTags in config.yaml are applied at parse time, before Marathon Cloud’s own filtering.
  • executionOrder is not supported; a workspace that defines it is rejected. Flows always run independently.

A typical layout:

flows/
├── config.yaml
├── login.yaml
├── checkout/
│ └── happy_path.yaml
└── subflows/
└── sign_in.yaml # used via runFlow, not run directly
flows/config.yaml
flows:
- "*.yaml"
- "checkout/**"

A flow’s name: field is not used for test identity; the file name is. Two files with the same name in different directories are distinct tests.

Marathon Cloud provides separate subcommands for Android and iOS Maestro execution.

Command

Terminal window
marathon-cloud run maestro android \
--api-key YOUR_API_KEY \
--application path/to/your-app.apk \
--test-application path/to/flows/

Point the --test-application parameter to the directory containing your YAML flows.

Parameter Description
--application Application binary: APK on Android; .app, .zip, or .ipa on iOS.
--test-application Directory containing Maestro YAML flows.
--os-version, --device Device selection, same values as run android / run ios.
--arch Android only: amd64 (default) or arm64. arm64 needs Android 9 or later.
--maestro-env Environment variable for flows (KEY=VALUE). Repeatable.
--concurrency-limit Cap parallel devices if your backend cannot handle many flows at once. See limiting concurrency.
FLOW... Positional flow files or directories to run; everything runs when omitted.

Maestro runs always use google_apis Android images; --system-image and --flavor are not available.

Design each flow to be independent. Avoid relying on the state left by a previous flow, as Marathon Cloud executes flows in parallel across different devices.

Aim for flows that take between 40 and 80 seconds to complete. Very short flows increase the relative overhead of device provisioning, while very long flows reduce the benefits of parallelization.

Place one flow per YAML file and keep shared steps in subflows invoked with runFlow. Marathon Cloud does not support executionOrder; if one flow depends on another, merge them or make each self-contained.

Use the --maestro-env flag to pass variables to your flows. These can be accessed in your YAML files using the ${VARIABLE_NAME} syntax.

Terminal window
marathon-cloud run maestro android \
--application app.apk \
--test-application flows/ \
--maestro-env "[email protected]" \
--maestro-env "API_URL=https://staging.api.com"

Pass flow files or directories as positional arguments after the flags to run a subset. Paths are relative to the working directory, inside --test-application.

Terminal window
marathon-cloud run maestro android \
--application app.apk \
--test-application flows/ \
flows/login.yaml flows/onboarding/

--filter-file works on Maestro runs. Each flow file becomes a test: the directory is the package, the class is always MaestroTest, the method is the file name without extension, and the flow’s tags: become annotations.

Flow file package method fully-qualified-test-name annotation
flows/login.yaml (empty) login MaestroTest#login its tags:
flows/auth/login.yaml auth login auth.MaestroTest#login its tags:
flows/checkout/cart/add.yaml checkout.cart add checkout.cart.MaestroTest#add its tags:

Paths are relative to --test-application. Flows in subdirectories must be included by config.yaml (see workspace layout) or they are never parsed, regardless of the filter file.

Because every flow shares the class name, the useful filter types are annotation, package, method, and fully-qualified-test-name. simple-class-name and fully-qualified-class-name select whole directories at best.

Run only flows tagged smoke, excluding the experimental directory:

flows/config.yaml
flows:
- "**"
flows/login.yaml
appId: com.example.app
tags:
- smoke
---
- launchApp
smoke.yaml
filteringConfiguration:
allowlist:
- type: "annotation"
values: ["smoke"]
blocklist:
- type: "package"
values: ["experimental"]
Terminal window
marathon-cloud run maestro android \
--application app.apk \
--test-application flows/ \
--filter-file smoke.yaml

See filtering for the full schema. For a one-off subset, positional arguments are simpler.

Always use Linux-style forward slashes (/) for file paths in your Maestro flows, even if you are developing on Windows. Marathon Cloud executes tests in a Linux-based environment.

Ensure the appId defined in your YAML flows matches the package name (Android) or bundle identifier (iOS) of the application you upload. Mismatching IDs will prevent Maestro from launching the application.