[ compare · mobile testing frameworks ]
e2e vs maestro
Maestro and e2e both drive a mobile app through its accessibility tree, with nothing added to the build. Maestro runs YAML flows on iOS and Android, with a free CLI and a paid cloud. e2e runs TypeScript or JavaScript tests that mix exact locators with agent goals, on iOS, Android, and web.
npx e2e@latest init[ at a glance ]
what each tool is.
| dimension | [ e2e ] | [ maestro ] |
|---|---|---|
| made by, license | e2e, Apache-2.0 | mobile.dev. The CLI is Apache-2.0, Maestro Cloud is paid. |
| platforms | iOS simulators, Android emulators, connected phones; Chromium, Firefox, WebKit | iOS, Android, React Native, Flutter; web in beta, Chromium only |
| test format | TypeScript or JavaScript | YAML flows, JavaScript through runScript |
| finding elements | Role, label, text, and test id queries. A string must match the whole name, and an action needs exactly one match. | Text and id as patterns that ignore case, first match. Spatial selectors such as below and rightOf. |
| when ai is used | At run time, when a step needs it. Verified goals replay without model calls. Locator steps never call a model. | While you write flows, through Maestro MCP, which writes YAML. Three experimental AI commands at run time, optional by default. |
| hosted devices | Any provider: Limrun, EAS Simulators, TestMu AI, BrowserStack, or your own CI machines | Maestro Cloud, $250 per device per month; BrowserStack, TestingBot, EAS Workflows, or your own CI machines with the open source CLI |
| tooling | CLI, an e2e mcp session for coding agents, a trace.md page per failed test, a video per attempt | Maestro Studio desktop app, Maestro Viewer, maestro record |
| changes to the app | None; your normal build | None; black box through the accessibility tree |
made by, license
[ e2e ]
e2e, Apache-2.0
[ maestro ]
mobile.dev. The CLI is Apache-2.0, Maestro Cloud is paid.
platforms
[ e2e ]
iOS simulators, Android emulators, connected phones; Chromium, Firefox, WebKit
[ maestro ]
iOS, Android, React Native, Flutter; web in beta, Chromium only
test format
[ e2e ]
TypeScript or JavaScript
[ maestro ]
YAML flows, JavaScript through
runScriptfinding elements
[ e2e ]
Role, label, text, and test id queries. A string must match the whole name, and an action needs exactly one match.
[ maestro ]
Text and id as patterns that ignore case, first match. Spatial selectors such as
belowandrightOf.when ai is used
[ e2e ]
At run time, when a step needs it. Verified goals replay without model calls. Locator steps never call a model.
[ maestro ]
While you write flows, through Maestro MCP, which writes YAML. Three experimental AI commands at run time, optional by default.
hosted devices
[ e2e ]
Any provider: Limrun, EAS Simulators, TestMu AI, BrowserStack, or your own CI machines
[ maestro ]
Maestro Cloud, $250 per device per month; BrowserStack, TestingBot, EAS Workflows, or your own CI machines with the open source CLI
tooling
[ e2e ]
CLI, an
e2e mcpsession for coding agents, atrace.mdpage per failed test, a video per attempt[ maestro ]
Maestro Studio desktop app, Maestro Viewer,
maestro recordchanges to the app
[ e2e ]
None; your normal build
[ maestro ]
None; black box through the accessibility tree
[ the same test ]
the same test,written both ways.
appId: com.example.app
---
- launchApp:
clearState: true
- tapOn: "Get started"
- tapOn:
id: "email"
- inputText: "ada@example.test"
- tapOn: "Continue"
- assertVisible: "Check your inbox"
- scrollUntilVisible:
element: "Resend"
- assertVisible:
id: "resend"import { test } from '@e2e-dev/mobile';
import { expect } from 'e2e';
test('asks for the email', async ({ app, agent, screen }) => {
await app.clearState();
await agent.act('get started with the email {email}', { params: { email: 'ada@example.test' } });
await expect(screen.getByText('Check your inbox')).toBeVisible();
await screen.scrollUntilVisible(screen.getByTestId('resend'));
await expect(screen.getByTestId('resend')).toBeVisible();
});One goal covers the three taps and the typed email. The launch, the scroll, and the assertions stay exact. When every step should be scripted, a tapOn becomes screen.getByText('...').tap().
[ differences ]
the five main differences.
01 / 05
[ side by side ]
feature by feature.
Maestro leads for teams where people who do not code read the flows: YAML is easier to follow than test code, and Maestro Studio is a desktop app. e2e leads where one suite covers web and mobile, where the UI changes often, and where a check is a question in plain language rather than a selector.
| dimension | [ e2e ] | [ maestro ] | leads |
|---|---|---|---|
| platforms | iOS, Android, connected phones; Chromium, Firefox, WebKit | iOS, Android, React Native, Flutter; web in beta, Chromium | [ e2e ] |
| writing a test | One agent.act goal in plain language, checked by an exact assertion, or one screen line per command | One YAML command per step; optional steps and runFlow: { when } branches cover the variants | [ e2e ] |
| when the ui changes | The agent finishes the goal from the changed screen; the runner saves a new recording after a passing check | The flow fails; fix the YAML by hand or regenerate it with the MCP agent; the Local plan lists self-healing with local agents | [ e2e ] |
| ai during a run | act, assert, waitFor, extract; the model never sees Secret values | assertWithAI, assertNoDefectsWithAI, extractTextWithAI; experimental, optional by default | [ e2e ] |
| exploratory testing | e2e explore runs from a goal and reports findings; a bug bash turns findings into failing repro tests | Maestro Studio and the MCP session let a person or an agent drive the device; no exploration command | [ e2e ] |
| how a test reads | TypeScript or JavaScript; the goals are plain language | YAML, one command per line, easier to follow for people who do not write code | [ maestro ] |
| finding elements | Whole string, one match, role, label, and test id; no spatial selectors | Pattern that ignores case, first match, spatial selectors | [ even ] |
| coding agents | e2e skill, an e2e mcp session that writes test lines, plugins for Claude Code, Codex, and Cursor, explore, bug bash | Maestro MCP with device tools, documented for Claude Code, Codex, Cursor, Copilot, Gemini CLI, Windsurf, JetBrains, VS Code | [ even ] |
| desktop app | None; CLI, trace.md, video per attempt | Maestro Studio, Maestro Viewer, maestro record | [ maestro ] |
| hosted devices | Limrun, EAS Simulators, TestMu AI, BrowserStack providers, or your own CI | Maestro Cloud with parallel runs and PR integration, $250 per device per month; BrowserStack, TestingBot, EAS Workflows, or your own CI with the open source CLI | [ even ] |
| getting started | npx e2e init in a Node.js project (22.22.3 or 24.8 and newer) | A standalone CLI and one YAML file, no project setup | [ maestro ] |
platforms
[ e2e ][ e2e ]
iOS, Android, connected phones; Chromium, Firefox, WebKit
[ maestro ]
iOS, Android, React Native, Flutter; web in beta, Chromium
writing a test
[ e2e ][ e2e ]
One
agent.actgoal in plain language, checked by an exact assertion, or onescreenline per command[ maestro ]
One YAML command per step;
optionalsteps andrunFlow: { when }branches cover the variantswhen the ui changes
[ e2e ][ e2e ]
The agent finishes the goal from the changed screen; the runner saves a new recording after a passing check
[ maestro ]
The flow fails; fix the YAML by hand or regenerate it with the MCP agent; the Local plan lists self-healing with local agents
ai during a run
[ e2e ][ e2e ]
act,assert,waitFor,extract; the model never seesSecretvalues[ maestro ]
assertWithAI,assertNoDefectsWithAI,extractTextWithAI; experimental, optional by defaultexploratory testing
[ e2e ][ e2e ]
e2e exploreruns from a goal and reports findings; a bug bash turns findings into failing repro tests[ maestro ]
Maestro Studio and the MCP session let a person or an agent drive the device; no exploration command
how a test reads
[ maestro ][ e2e ]
TypeScript or JavaScript; the goals are plain language
[ maestro ]
YAML, one command per line, easier to follow for people who do not write code
finding elements
[ even ][ e2e ]
Whole string, one match, role, label, and test id; no spatial selectors
[ maestro ]
Pattern that ignores case, first match, spatial selectors
coding agents
[ even ][ e2e ]
e2e skill, an
e2e mcpsession that writes test lines, plugins for Claude Code, Codex, and Cursor, explore, bug bash[ maestro ]
Maestro MCP with device tools, documented for Claude Code, Codex, Cursor, Copilot, Gemini CLI, Windsurf, JetBrains, VS Code
desktop app
[ maestro ][ e2e ]
None; CLI,
trace.md, video per attempt[ maestro ]
Maestro Studio, Maestro Viewer,
maestro recordhosted devices
[ even ][ e2e ]
Limrun, EAS Simulators, TestMu AI, BrowserStack providers, or your own CI
[ maestro ]
Maestro Cloud with parallel runs and PR integration, $250 per device per month; BrowserStack, TestingBot, EAS Workflows, or your own CI with the open source CLI
getting started
[ maestro ][ e2e ]
npx e2e initin a Node.js project (22.22.3 or 24.8 and newer)[ maestro ]
A standalone CLI and one YAML file, no project setup
[ which one ]
which one to pick.
pick by the job in front of you: first the jobs where e2e is the better choice, then the jobs where maestro is the better choice.
| the job | pick | why |
|---|---|---|
| One suite for iOS, Android, and the web | [ e2e ] | Firefox and WebKit included; Maestro's web support is in beta and Chromium only. |
| Tests that already live in TypeScript or JavaScript | [ e2e ] | Fixtures, page objects, and typed params, with goals in plain language beside them. |
| A coding agent that writes and fixes tests | [ e2e ] | It works against the app while it runs on a simulator or device, and verified goals replay without model calls. |
| Your own model and device providers | [ e2e ] | Any AI SDK model or subscription, your own CI or any device provider, with no per-device plan. |
| Flows the team prefers to read and review in YAML | [ maestro ] | One command per line, easier to follow for people who do not write code. |
| Maestro Studio and Maestro Cloud from one vendor | [ maestro ] | The desktop app, hosted devices, and parallel runs come from the same place. |
| Trying a flow with no Node project around the app | [ maestro ] | Maestro is a standalone CLI and one YAML file; e2e needs a Node.js project (22.22.3 or 24.8 and newer) and npx e2e init. |
| Selecting elements by position, such as the field below a label | [ maestro ] | Maestro's below, above, leftOf, and rightOf selectors; e2e has none, so a label, a test id, or a goal stands in. |
One suite for iOS, Android, and the web
[ e2e ]Firefox and WebKit included; Maestro's web support is in beta and Chromium only.
Tests that already live in TypeScript or JavaScript
[ e2e ]Fixtures, page objects, and typed params, with goals in plain language beside them.
A coding agent that writes and fixes tests
[ e2e ]It works against the app while it runs on a simulator or device, and verified goals replay without model calls.
Your own model and device providers
[ e2e ]Any AI SDK model or subscription, your own CI or any device provider, with no per-device plan.
Flows the team prefers to read and review in YAML
[ maestro ]One command per line, easier to follow for people who do not write code.
Maestro Studio and Maestro Cloud from one vendor
[ maestro ]The desktop app, hosted devices, and parallel runs come from the same place.
Trying a flow with no Node project around the app
[ maestro ]Maestro is a standalone CLI and one YAML file; e2e needs a Node.js project (22.22.3 or 24.8 and newer) and
npx e2e init.Selecting elements by position, such as the field below a label
[ maestro ]Maestro's
below,above,leftOf, andrightOfselectors; e2e has none, so a label, a test id, or a goal stands in.
[ switching ]
run both, move one flow at a time.
[step 1]
Run
npx e2e initand choose the mobile engine, thennpx agent-device doctor. Point the target at yourbundleId. Both runners can use the same simulator or emulator.[step 2]
Port
appId, theconfig.yamltags, andenvintoe2e.config.ts, and move passwords and tokens intocredentialsorsecrets.[step 3]
Rewrite one flow, starting with one whose
optionalsteps andrunFlow: { when }branches change often. Run it on each platform withnpx e2e run <file>, and keep the YAML until you trust the test. The agent prompt at the top of the guide does the rewrite, and themigrate-to-e2eskill tracks a migration across sessions.
The migration guide maps every API. Rolling e2e out across a larger team? Book a call and the e2e team sets it up with you.
[ faq ]
questions.
what people on maestro ask before they add e2e.
[001]does e2e run my maestro yaml flows?
No. Flows are rewritten as TypeScript or JavaScript tests, one awaited call per command or one goal for several. The migration guide maps every command, and the agent prompt does the rewrite one flow at a time.
[002]is e2e deterministic?
Yes, when you want it to be. A test with only locator steps never calls a model. A verified goal replays as recorded actions with no model call, and the agent runs only when a recording no longer matches. --strict-cache turns that into a failure in CI.
[003]what does e2e need on the machine?
Xcode with a simulator runtime or the Android SDK with an emulator, and Node.js 24.8 or newer (22.22.3 or newer on Node.js 22). agent-device drives the device. Nothing is added to the app.
[004]does e2e work with expo?
Yes. Development builds open the dev server through launch arguments and app.command, CI runs release builds, there is an EAS Workflows guide, and EAS Simulators work as a hosted device provider.
[005]can people who do not code read e2e tests?
The goals, yes: agent.act('get started with the email {email}'). The surrounding test is TypeScript or JavaScript, so a reviewer who prefers YAML will find Maestro flows easier.
[006]what's the difference between e2e and maestro?
Maestro runs YAML flows on iOS and Android, with AI used while you write the flow and three optional AI commands at run time. e2e runs TypeScript or JavaScript tests that mix exact locators with goals an agent completes during the run, replays verified goals without a model, and covers the web too.
facts checked 30 october 2026 against docs.maestro.dev, maestro.dev/pricing, maestro cli 2.12.0, and the e2e docs. something out of date? open an issue on github.
