Maestro Usage
Quick reference for writing Maestro E2E flows. For the full command API, see resources/api-reference.md. For testing patterns and pitfalls, see resources/best-practices.md.
Flow File Structure
Every Maestro flow is a YAML file with an optional header section separated from commands by ---:
appId: com.example.app
name: "My Test Flow"
env:
USERNAME: "test@example.com"
PASSWORD: "password123"
tags:
- smoke
- regression
---
- launchApp:
clearState: true
- tapOn: "Login"
- inputText: "test@example.com"
Header Fields
| Field | Required | Description |
|-------|----------|-------------|
| appId | Yes | Bundle ID (iOS) or package name (Android) |
| name | No | Custom display name for the flow |
| env | No | Environment variables accessible via ${VAR_NAME} |
| tags | No | Tags for filtering (maestro test --include-tags smoke) |
| jsEngine | No | rhino (default) or graaljs |
| onFlowStart | No | Commands to run before the flow starts |
| onFlowComplete | No | Commands to run after the flow ends (pass or fail) |
Command Quick Reference
Interaction
| Command | Simple Form | Purpose |
|---------|-------------|---------|
| tapOn | - tapOn: "Text" | Tap an element |
| doubleTapOn | - doubleTapOn: "Text" | Double-tap |
| longPressOn | - longPressOn: "Text" | Long press |
| inputText | - inputText: "hello" | Type text into focused field |
| eraseText | - eraseText: 5 | Erase N characters (or all) |
| pressKey | - pressKey: Enter | Press a key (Enter, home, back, etc.) |
| swipe | - swipe: { direction: LEFT } | Swipe gesture |
| scroll | - scroll | Simple scroll down |
| scrollUntilVisible | see API ref | Scroll until element appears |
| hideKeyboard | - hideKeyboard | Dismiss keyboard |
Navigation & App Lifecycle
| Command | Simple Form | Purpose |
|---------|-------------|---------|
| launchApp | - launchApp | Launch app (with optional clearState, permissions) |
| stopApp | - stopApp | Stop current app |
| killApp | - killApp | Force kill (Android: process death) |
| openLink | - openLink: "https://..." | Open URL or deep link |
| back | - back | Press back (Android only) |
| clearState | - clearState | Clear app data |
Assertions
| Command | Simple Form | Purpose |
|---------|-------------|---------|
| assertVisible | - assertVisible: "Text" | Assert element is visible |
| assertNotVisible | - assertNotVisible: "Text" | Assert element is not visible |
| assertTrue | - assertTrue: "1 + 1 === 2" | Assert JS expression is truthy |
Waiting
| Command | Purpose |
|---------|---------|
| extendedWaitUntil | Wait for element to appear/disappear with timeout |
| waitForAnimationToEnd | Wait until animations settle |
Flow Control
| Command | Purpose |
|---------|---------|
| runFlow | Run a subflow from a file or inline, optionally conditional |
| runScript | Execute a JavaScript file |
| repeat | Repeat commands N times or while a condition is true |
| retry | Retry commands up to N times (max 3) on failure |
Clipboard & Text
| Command | Purpose |
|---------|---------|
| copyTextFrom | Copy text from a UI element into maestro.copiedText |
| setClipboard | Set arbitrary text to clipboard |
| pasteText | Paste clipboard into focused field |
Device & Media
| Command | Purpose |
|---------|---------|
| setLocation | Spoof GPS coordinates |
| setOrientation | Set portrait/landscape |
| addMedia | Add images/videos to device gallery |
| toggleAirplaneMode | Toggle airplane mode |
| travel | Simulate movement between GPS points |
Recording & Screenshots
| Command | Purpose |
|---------|---------|
| takeScreenshot | Capture screenshot to file |
| startRecording | Begin video recording |
| stopRecording | End video recording |
AI-Powered (Experimental)
| Command | Purpose |
|---------|---------|
| assertWithAI | AI-based visual assertion |
| assertNoDefectsWithAI | AI-based defect detection |
| extractTextWithAI | AI-based text extraction from screen |
Selectors
Selectors identify which UI element a command targets. Combine them for precision.
Core
text: Visible text or accessibility label (regex).- tapOn: "Login"is shorthand fortext: "Login".id: Accessibility identifier / resource ID (regex).index: 0-based index when multiple elements match.point: Screen coordinates ("50%, 50%"or"100, 250").css: CSS selector (web only).
Relational
above/below/leftOf/rightOf: Position relative to an anchor element.containsChild: Parent with a direct child matching criteria.childOf: Element that is a direct child of a parent.containsDescendants: Parent with specific descendants at any depth.
State
enabled:true/false— interactive state.checked:true/false— checkbox/switch state.focused:true/false— has keyboard focus.selected:true/false— selected tab/segment.
Traits
traits: text: Any element containing text.traits: long-text: Element with 200+ characters.traits: square: Element with ~1:1 aspect ratio.
Common Arguments
Every command supports these optional fields:
label: Custom display name for the step in output.optional: Iftrue, flow continues even if the command fails (logged as warning).
Conditions (when)
runFlow and runScript support conditional execution:
- runFlow:
when:
visible: "Some Element" # element is visible
# notVisible: "Other" # element is NOT visible
# platform: iOS # platform check (Android|iOS|Web)
# true: ${MY_VAR == 'yes'} # JavaScript expression
commands:
- tapOn: "Some Element"
Multiple conditions are ANDed together.
Environment Variables
Access env vars with ${VAR_NAME} syntax anywhere in YAML values:
env:
USERNAME: "default_user"
---
- inputText: ${USERNAME}
Override at runtime: maestro test -e USERNAME=other_user flow.yaml
JavaScript Integration
Use runScript to execute JS files. Access env vars directly. Use output object to pass data back to the flow:
// scripts/setup.js
var name = "User_" + Date.now();
output.generatedName = name;
- runScript: scripts/setup.js
- inputText: ${output.generatedName}
HTTP Requests in JS
var response = http.get("https://api.example.com/data");
var data = json(response.body);
output.userId = data.id;
Methods: http.get(), http.post(), http.put(), http.delete(), http.request().
CLI Commands
| Command | Purpose |
|---------|---------|
| maestro test flow.yaml | Run a single flow |
| maestro test dir/ | Run all flows in a directory |
| maestro test --format junit dir/ | Generate JUnit report |
| maestro test --format html dir/ | Generate HTML report |
| maestro test -e KEY=VAL flow.yaml | Pass env vars at runtime |
| maestro test --include-tags smoke dir/ | Run only flows with tag |
| maestro studio | Launch interactive browser IDE |
| maestro cloud | Run tests in Maestro Cloud |
Additional Resources
- Full command API with all options: resources/api-reference.md
- JavaScript & HTTP reference: resources/javascript-reference.md
- CLI commands & flags: resources/cli-reference.md
- Best practices and patterns: resources/best-practices.md
- Maestro MCP tool reference: resources/mcp-reference.md
- Annotated examples: examples/ (utilities, test flows, advanced patterns, project structure)
- Official docs: https://maestro.mobile.dev
微信扫一扫