Migrate from Maestro to TesterArmyYour Maestro flows,
minus the matching layer
Maestro flows already read like instructions, so this is close to a one-to-one conversion. Paste one prompt into Claude Code, Cursor, or Codex and it reads your flow files, converts them, and verifies every test on cloud simulators.
Takes less than 2 minutes. No credit card required.
The YAML is declarative,
but the matching still drifts
Maestro got the format right - flows are declarative YAML instead of imperative code. The friction that remains is the matching layer: flows still reference text, IDs, and indexes that drift as your UI changes.
Text, IDs, and indexes drift as the UI changes
A relabeled button, a renamed accessibility id, a list that gains one more entry - tapOn matchers reference all of them. The app still works after each of those changes, but the flow goes red, and getting it green again means editing YAML.
Wait commands patch flakiness one timeout at a time
Every animation or slow screen gets a waitForAnimationToEnd or an extendedWaitUntil with a hand-picked timeout. Over time the flows accumulate arbitrary timeouts that nobody dares to remove, because deleting the wrong one brings the flakiness back.
You maintain a tree of .yaml files plus the runtime
Shared behavior spreads across runFlow sub-flows and env config, so one login change touches several files. On top of the flows themselves, the local Maestro runtime has to be installed and kept working wherever they run.
Running flows means running the infrastructure
Flows execute on local simulators and emulators you keep configured, or on Maestro Cloud. Either way the devices, the app builds, and the runtime are yours to operate alongside the tests.
What your suite reads like
after the conversion
The intent in your YAML commands becomes act and assert steps, and the matching details are dropped. This is the same checkout flow in both languages.
appId: com.example.shop
---
- launchApp
- tapOn: "Search"
- inputText: "desk lamp"
- tapOn:
id: "search_result_0"
- tapOn: "Add to cart"
- tapOn:
id: "cart_button"
- waitForAnimationToEnd
- tapOn: "Checkout"
- extendedWaitUntil:
visible: "Order summary"
timeout: 10000
- tapOn: "Place order"
- assertVisible: "Order confirmed"The id matchers, the waitForAnimationToEnd, and the hand-picked timeout are dropped in conversion. The agent sees the screen, so a relabeled button or a renamed id does not break anything.
The whole migration
is one prompt
Paste this into your coding agent in the repository that contains your Maestro flows. It discovers your flow files and sub-flows, creates a mobile project, uploads your app build, converts each flow, and verifies every test on cloud simulators.
Migrate this repository's Maestro flows to TesterArmy using the TesterArmy
CLI (`ta`). Verify auth first with `ta status --json`, and use `ta --help`
plus subcommand help to discover commands. Prefer --json output.
1. Discover: find all Maestro flow files (.maestro/ or *.yaml flows with an
appId and commands). Read shared sub-flows referenced by runFlow and any
env config. Note whether flows target iOS, Android, or both.
2. Create a TesterArmy mobile project (skip if one exists in
`ta projects list`):
echo '{"name":"<app name>","url":"","projectType":"mobile"}' | ta projects create --json
3. Build and upload the app artifact. For iOS use an iOS Simulator `.app`
build; for Android use a release `.apk` or `.apks`. Do not use .ipa,
.aab, or .xapk. Upload it:
ta upload-app --app-path <path-to-build> --project <projectId> --json
Report the uploaded app ID.
4. Convert each reusable Maestro sub-flow (runFlow) into a project memory
so every test run knows about it (category site_structure, importance
high), e.g. "Login sub-flow: tap Sign in, enter email and password,
land on the home feed."
echo '{"category":"site_structure","title":"...","content":"...","importance":"high"}' | ta memories create --project <projectId> --json
5. Convert each Maestro flow into a TesterArmy mobile test:
- tapOn / inputText / scroll / launchApp -> steps with type "act"
- assertVisible / assertNotVisible -> steps with type "assert"
- login sub-flows -> one step with type "login"
- Where env variables or parameters supplied values, write the
representative case in plain English.
- Drop all selector details (text matchers, id, index, point) and wait
commands - the agent finds elements visually and waits on its own.
- Keep tests focused: 3-10 steps. Split flows covering multiple journeys
into separate tests.
Create each test with platform "mobile":
echo '{"title":"<flow name>","description":"Migrated from <flow file>","platform":"mobile","steps":[{"title":"Tap Sign in","type":"act"},{"title":"The home feed is visible","type":"assert"}]}' | ta tests create --project <projectId> --json
Step types: act, assert, login, screenshot.
6. Never hardcode passwords in test steps. If flows read credentials from
env config, tell me which credentials to add and I will run:
echo '{"kind":"login","label":"...","username":"...","password":"..."}' | ta projects credentials-create <projectId> --json
7. Tell me each created test ID, then run each one to verify with
`ta tests run <testId> --wait --json`. Runs target the most recent
uploaded app automatically.
8. Report a summary table: Maestro flow file -> TesterArmy test ID, the
uploaded app ID, plus anything you intentionally skipped and why.Everything you built
has a place to land
Maestro is the closest starting point of any tool - each YAML command maps almost directly onto a TesterArmy step, and the matching layer maps to nothing at all.
Maestro and TesterArmy,
row by row
Maestro earned its place: the license is free, the declarative YAML is pleasant to write, and iterating on a flow against your own simulator gives you a fast local loop. This table is about what owning the flows and the runtime costs, and where each side wins.
- Who maintains the testsTesterArmyThe agent works from the intent of each step, so nobody owns a matching layer of text matchers, ids, and indexes.AdvantageMaestroYour team owns the tree of .yaml flows, the runFlow sub-flows, and every matcher inside them.
- What breaks on a UI changeTesterArmyUsually nothing - a relabeled button or a renamed accessibility id is invisible to a vision agent.AdvantageMaestroEvery flow whose text, id, or index matcher touched the change, and getting them green again means editing YAML by hand.
- Writing a new testTesterArmy3-10 plain-English steps at the same level of intent your YAML already captures, and anyone on the team can write and review them.MaestroA declarative YAML flow that is pleasant to write - the closest authoring model to plain English in the open-source world.
- Flaky failuresTesterArmyThe agent waits on its own instead of relying on hand-picked timeouts, and every failure comes with a recording and a step trace.AdvantageMaestroHandled with waitForAnimationToEnd and extendedWaitUntil timeouts that accumulate inside the flows.
- Run verdictsTesterArmyThree verdicts - passed, failed, or blocked. Environment and setup stops land in blocked with the reason attached, so the failure count only holds real product failures.AdvantageMaestroTwo verdicts. An emulator stall, a broken deep link, and a real bug all end the flow with the same failure.
- License and infrastructureTesterArmyA paid service - the agent, the simulators, and the infrastructure are included.MaestroThe runner is free and open source; you install and maintain the runtime and your own simulators, or move runs to Maestro Cloud.Advantage
- Local YAML iterationTesterArmyRuns execute on managed cloud simulators, so a run is queued and reported rather than instant on your own machine.MaestroIterating on a flow against your own simulator is fast, and that local loop is an advantage of running the runtime yourself.Advantage
- Pull request workflowTesterArmyPR testing is built in - runs trigger from GitHub Actions or Expo EAS and report back on the pull request.AdvantageMaestroYou wire maestro test into CI yourself and keep the runtime working on the workers that run it.
- Web coverageTesterArmyThe same plain-English tests cover web apps and native mobile apps in one suite.MaestroMaestro is built for mobile UI flows first - each flow targets an appId and runs against a simulator or emulator.
- Entry priceTesterArmyFree trial without a credit card; Hobby is $99 per month with 250 test runs included.Maestro$0 for the open-source runner - the cost is the runtime you operate and the matcher maintenance in the rows above, with Maestro Cloud priced separately.
Facts checked August 2026. Spotted something out of date? Tell us and we will fix it.
From YAML flows to green runs in four steps
Install the CLI, hand the prompt to your coding agent, and review what comes back. Your Maestro flows keep running until every migrated test is green.
Create a mobile project and upload your build
Install the TesterArmy CLI and authenticate, then paste the migration prompt into Claude Code, Cursor, or Codex. The agent creates a mobile project and uploads your app build - an iOS Simulator .app or an Android .apk or .apks, never .ipa or .aab.
The agent converts every flow
tapOn, inputText, and scroll become act steps, assertVisible and assertNotVisible become assert steps, and login sub-flows become a single login step backed by encrypted credentials. Reusable runFlow sub-flows are saved as project memories so every run knows about them.
Every migrated test runs in the cloud
The agent queues each test with ta tests run --wait against managed cloud simulators and emulators. Runs target your most recent uploaded build automatically, and the agent reports every result plus anything it intentionally skipped and why.
Wire the suite into CI
Replace your maestro test job with GitHub Actions or ta ci, or run migrated tests from Expo EAS workflows. Retire the .maestro flow files and the local runtime once the TesterArmy runs are green.
What comes with you,
what stays behind
This is the easiest mobile migration - each YAML command maps almost directly onto a TesterArmy step - and the guide is explicit about what stays behind.
When Maestro is still the right call
- Your flows depend on physical-device-only features like the camera, Face ID, or Touch ID - TesterArmy runs on managed cloud simulators and emulators, where those are not available.
- Your builds cannot leave your own infrastructure - TesterArmy runs upload an app build to cloud simulators, so fully local or air-gapped pipelines are a reason to stay.
- Your flows lean heavily on low-level commands like pressKey, tapOn by point, or runScript JavaScript that encode more than user-visible intent.
- Your team genuinely enjoys the YAML plus local-simulator loop and your app's labels and accessibility ids rarely churn.
Nothing forces the choice on day one. Migrated tests run alongside your .maestro flows and the local runtime, and the guide's own advice is to retire both only once the TesterArmy runs are green.
Frequently Asked Questions
A relabeled button
should never turn a flow red
Your Maestro flows already read like instructions, which is why this is close to a one-to-one conversion. The migration keeps that intent and retires the matching layer, the wait commands, and the local runtime, so the tests run on managed cloud simulators and stop drifting with your UI.