Plans, generates, runs, and heals end-to-end tests for Expo and React Native mobile apps using Maestro (the 2026 standard for RN E2E, adopted by Meta, Microsoft, and DoorDash, and integrated with Expo via EAS Workflows). Drives a spec-first YAML-flow loop, proposes `testID` source diffs (never `accessibilityLabel` reuse), runs Maestro Cloud as an EAS job, and stays token-aware via `--shards`, `--retries`, and failure-only healing. Use for native flows in Expo / RN apps. Triggers on "test this RN flow", "add mobile e2e", "maestro flow", "expo e2e", "e2e for react native", "test the native app", "/e2e-testing-mobile". Defer to [`e2e-testing`](../e2e-testing/SKILL.md) for web flows and the WebView portion of hybrid apps.
69
87%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Drive native mobile end-to-end tests through Maestro and Maestro MCP. The user writes (or approves) a Markdown feature spec; an agent emits a Maestro YAML flow, runs it against a simulator or Maestro Cloud, and self-heals when locators drift.
This is the mobile counterpart to e2e-testing.
Anything orthogonal to native (web flows, WebViews inside a hybrid app)
defers to that skill.
The two skills compose; they do not overlap.
This
SKILL.mdis a thin index. Decision rules live inrules/*.mdand load on demand. Worked references (Maestro CLI surface, MCP tool catalog, EAS Workflow wiring, Detox legacy notes, mobile pyramid math) live inreferences/*.md. Literal boilerplate the skill emits lives intemplates/*.md. Do not preload everything — load only what the current phase asks for.
Reach for this skill when any of the following is true:
.maestro/ flows or EAS E2E build profile yet and
needs Phase 0 setup.Do not reach for this skill when:
tdd and the layer rule in
rules/layer-decision.md.e2e-testing.e2e-testing, which automates the WebView
via Playwright while Maestro handles native chrome around it.Before any agent loop, verify the repo is wired for Maestro on Expo / RN. Halt and ask the user before installing anything or producing builds.
Run these checks (read-only):
# 1. Maestro CLI installed?
maestro --version 2>/dev/null
# 2. Flow directory present?
ls -d .maestro 2>/dev/null
# 3. EAS build profile for E2E exists?
jq '.build | has("e2e")' eas.json 2>/dev/null
# 4. Simulator / emulator available?
xcrun simctl list devices available 2>/dev/null | grep -E 'iPhone'
adb devices 2>/dev/null
# 5. Existing Detox install (legacy escape hatch)?
jq '.devDependencies | has("detox")' package.json 2>/dev/nullDecision table:
| State | Action |
|---|---|
Maestro CLI present + .maestro/ exists + eas.json e2e profile | Proceed to Phase 1. |
| Maestro CLI missing | Halt. Print install plan (templates/install-plan.md). Ask permission. |
.maestro/ missing | Halt. Propose creating .maestro/ with the templates/flow.yaml starter. Ask first. |
eas.json e2e build profile missing | Halt. Propose templates/eas-build-profile.json. Ask first. |
| No simulator / emulator running | Halt. Ask the user to boot one, or proceed with Maestro Cloud only. |
| Existing Detox suite detected | Note it. Read references/detox-legacy.md before proposing migration. |
Bare RN project (no expo / no eas.json) | Skip EAS-specific checks. Use Maestro CLI directly against a local build. |
Print the exact commands; do not run them silently.
The full install plan template is in templates/install-plan.md.
The agent loop is spec → emit-flow → run → heal.
The spec is human-readable Markdown; the executable artefact is a
Maestro YAML flow.
Full rules: rules/spec-first-flow.md.
specs/<flow>.md ─┐
├─→ emit ─→ .maestro/<flow>.yaml ─→ run ─→ pass?
│ │ no
│ ▼
└───────────────── heal ←────────────── failing flow + trace
│
▼
patched flow or `testID` source-diff proposalTwo entry points:
specs/<flow>.md.specs/<flow>.md.
The user reviews the Markdown before flow emission.Use the Markdown template in
../e2e-testing/templates/spec.md.
The spec format is identical across web and mobile — share it.
The Maestro flow walks the platform accessibility tree. Pick locators in this order — never skip a rung:
id: <testID> — the source-of-truth selector for E2E.
Mapped to accessibilityIdentifier on iOS and resource-id on
Android (RN 0.64+). Stable across i18n and refactors.text: <visible string> — only when the text is short, unique on
screen, and not localised.accessibilityText: <label> — last resort, with caveats.
See rules/locator-strategy.md for
why accessibilityLabel should not double as a test selector.testID is the standard fix, not an escape hatch.
When the Healer cannot find a stable element at rung 1, propose a
source diff that adds testID to the component (use the
setTestId helper in
templates/testid-helper.tsx to keep
iOS and Android consistent), and offer the diff for user approval
before patching the flow.
Full rules: rules/locator-strategy.md.
Maestro flows are YAML, not pixel snapshots — the per-step token cost
is already an order of magnitude below screenshot-driven runners.
Defaults the skill prescribes
(full rules: rules/token-budget.md):
maestro test .maestro/<flow>.yaml.--shards only on Maestro Cloud, never on local iteration.record_screen: false by default; flip to true only when chasing a
visual race.retries: 1 for local, retries: 2 for Maestro Cloud.app.app / app.apk from the EAS E2E
build profile — never rebuild on every flow run.After the agent emits a flow:
test-provenance-guard on
any TypeScript helpers the flow imports (e.g. fixture builders) to
ensure they call production code instead of a private re-implementation..github/workflows/eas-e2e.yml (or the EAS Workflow YAML) and
confirm the maestro-cloud job is wired with retries: 2 and
record_screen: false per
templates/eas-workflow.yaml.If the heal loop fails to converge:
confidence(analysis) on the flow failure.| Signal | Do |
|---|---|
| Bug fixable by a unit or component test | Use tdd, not this skill. |
| Flow is browser-only or pure web | Use e2e-testing, not this skill. |
| Flow lives inside a WebView in a hybrid RN app | Pair with e2e-testing for the WebView; Maestro for the native chrome. |
| Multi-screen native flow, deep links, permissions, or push | Spec-first feature flow (Phase 1). |
| Flaky existing flow | Healer pass only; do not rewrite without spec context. |
Locator unstable, no stable testID | Propose testID diff via the setTestId helper. |
Repo missing Maestro CLI or .maestro/ or eas.json E2E profile | Phase 0 halt + ask permission. |
| Heal loop > 3 attempts | Stop, run confidence(analysis), escalate. |
| Flow passes on first run, never seen failing | Verify any imported helpers via test-provenance-guard before declaring done. |
| Existing Detox suite is green and stable | Keep it; see references/detox-legacy.md. |
| Detox suite is brittle through RN upgrades | Migrate flow-by-flow to Maestro; do not rewrite the whole suite at once. |
e2e-testing — owns web E2E and the
WebView half of hybrid mobile apps. This skill defers to it for
anything browser-shaped.tdd — owns the unit and component layers
(Jest + React Native Testing Library). This skill defers for
anything below E2E.test-provenance-guard — runs
on TypeScript helpers imported by flows to catch tests-by-construction.confidence — gate when the heal loop fails.holistic-analysis — if a flow is
failing for reasons no flow rewrite can fix, step back instead of
patching.ux — review accessibility labels separately from
test IDs (the two should never share a value).references/maestro-cli.md — CLI surface
(launchApp, tapOn, assertVisible, runFlow, Studio, doctor).references/maestro-mcp.md — Maestro
MCP tools for agent-driven flow generation and healing.references/eas-workflows.md —
eas.json E2E profile, .maestro/ layout, maestro-cloud job
parameters (build_id, flow_path, shards, retries,
record_screen, device_identifier).references/detox-legacy.md — when
to keep an existing Detox suite vs. migrate.references/pyramid-mobile.md —
pyramid math for Expo / RN with Jest, React Native Testing Library,
and Maestro.templates/install-plan.md — Phase 0
halt message with the exact commands to install Maestro + EAS CLI
and scaffold .maestro/.templates/flow.yaml — sample Maestro flow
with launchApp, tapOn (id: and text: forms), assertVisible,
and runFlow includes.templates/eas-workflow.yaml — EAS
Workflow with a build job and a maestro-cloud job.templates/eas-build-profile.json
— eas.json snippet for an e2e profile producing .apk and .app.templates/testid-helper.tsx —
setTestId helper that maps testID and accessibilityLabel
correctly per platform without conflating the two.rules/anti-patterns.md)accessibilityLabel as the test selector (it is for screen
readers; doubling its purpose breaks accessibility).tapOn: { point: "50%, 80%" })
instead of proposing a testID diff..app / .apk on every flow run.specs/<flow>.md exists and the user reviewed it..maestro/<flow>.yaml passes against a real build.test-provenance-guard.maestro-cloud job runs the flow on Cloud with
retries: 2 and record_screen: false.testID was added, it is in the source diff and committed,
with no accessibilityLabel reuse.39b3f44
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.