0Pricing
React Native Academy · Lesson

Installing Maestro and Running Your First Flow

Install the Maestro CLI, write a YAML flow file that launches the app and taps a button, run it against a running simulator, and read the test report.

Installing Maestro and Running Your First Flow is a free React Native Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the React Native Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is Maestro?

Maestro is an open-source mobile UI testing framework by mobile.dev. It drives real iOS Simulators and Android Emulators by simulating actual user gestures — taps, swipes, typing — on the native UI. Because it tests the real app binary, it catches bugs that unit and component tests miss, like incorrect navigation wiring or platform-specific rendering issues.

Maestro tests are written in simple YAML files, making them accessible to developers who are not experts in testing frameworks. Each YAML file describes a flow: a sequence of commands that the Maestro CLI executes against a running app.

Installing the Maestro CLI

Install Maestro via a shell script on macOS and Linux. It downloads the CLI binary and adds it to your PATH. On Windows, Maestro runs inside WSL2 with an Android emulator. Verify the installation by running maestro --version.

Maestro requires Java 11 or higher on macOS (for the underlying test runner). If you do not have Java, Maestro's installer suggests installing it via Homebrew. iOS testing requires Xcode and the Simulator app — standard requirements for any iOS development.

# Install Maestro (macOS / Linux)
curl -Ls 'https://get.maestro.mobile.dev' | bash

# Reload your shell profile
source ~/.zshrc  # or ~/.bashrc

# Verify installation
maestro --version
# Expected: Maestro CLI v1.x.x

# Optional: install the Maestro Studio (visual test recorder)
maestro studio

Writing Your First Flow File

A Maestro flow is a YAML file. The top-level appId specifies which app to test — use the bundle identifier for iOS (e.g., com.example.myapp) or the package name for Android. The --- separator begins the command list.

Start with the launchApp command to open the app fresh. Then add assertions and actions. The simplest first flow just launches the app and verifies the welcome screen appears.

# maestro/flows/welcome.yaml
appId: com.example.myapp
---
- launchApp
- assertVisible:
    text: 'Welcome to MyApp'
- tapOn:
    text: 'Get Started'
- assertVisible:
    text: 'Sign In'

Running a Flow

Run a Maestro flow with maestro test path/to/flow.yaml. Make sure a simulator or emulator is running and the app is installed on it before executing the command. Maestro connects to the running simulator automatically — no device selection needed when there is only one.

Maestro prints each command as it executes. On success, each step shows a green checkmark. On failure, it shows the failing command, a screenshot of the UI at the point of failure, and an error message. The screenshot is invaluable for debugging why an assertion failed.

# Run a single flow file
maestro test maestro/flows/welcome.yaml

# Run all flows in a directory
maestro test maestro/flows/

# Run with verbose output
maestro test --format junit maestro/flows/login.yaml

# Generate an HTML test report
maestro test --format html --output test-results.html maestro/flows/

The tapOn Command

The tapOn command simulates a finger tap. You can tap by text (the visible label), by id (the element's testID), or by a percentage-based point on the screen. Tapping by text is the most readable and resilient to layout changes.

If multiple elements have the same text, add an index to specify which one (0-indexed). Use optional: true to make the tap conditional — it skips without failing if the element is not present, which is useful for dismissing optional permission dialogs.

# Tap by visible text
- tapOn:
    text: 'Next'

# Tap by testID
- tapOn:
    id: 'submit-button'

# Tap by position (50% from left, 90% from top)
- tapOn:
    point: '50%,90%'

# Tap second element with the same text
- tapOn:
    text: 'Delete'
    index: 1

# Optional tap (skips if not found)
- tapOn:
    text: 'Allow'
    optional: true

The inputText Command

Use inputText to type text into the currently focused input field. First tap on the TextInput to focus it, then use inputText to type. Maestro types the full string at once rather than character by character.

For fields that require clearing existing text first, use clearText before inputText. Use hideKeyboard after typing to dismiss the software keyboard, which may be covering other elements you need to interact with.

# Type email address into the focused input
- tapOn:
    id: 'email-input'
- inputText: 'user@example.com'

# Clear and retype
- tapOn:
    id: 'search-input'
- clearText
- inputText: 'react native'

# Dismiss keyboard
- hideKeyboard

# Tap the search button after keyboard is hidden
- tapOn:
    text: 'Search'

Viewing the Test Report

Maestro generates test results in several formats: plain text in the terminal, JUnit XML (for CI systems like GitHub Actions), or an interactive HTML report. The HTML report includes screenshots for each step, making it easy to visually review what happened at each point in the flow.

When a test fails, Maestro saves a screenshot of the screen at the moment of failure. Look for the failure screenshot in the output to understand why an assertion failed — often the screen shows a loading spinner instead of the expected content, revealing a timing issue.

# Run all tests and save a JUnit XML report
maestro test \
  --format junit \
  --output results/test-results.xml \
  maestro/flows/

# The XML report contains:
# - Test suite name
# - Each test case with pass/fail status
# - Failure messages with screenshot paths
# - Total duration

Understanding Flow Execution Order

Commands in a Maestro flow execute sequentially. Maestro automatically waits for each command to complete before moving to the next. Taps wait for the element to be visible and stable before interacting, and assertions retry until the element appears (with a configurable timeout).

The default timeout for assertVisible is 5 seconds. If your app takes longer to load a screen (for example, it fetches data from a slow API), increase the timeout with the timeout option or add a waitForAnimationToEnd command.

# Increase timeout for a slow-loading screen
- assertVisible:
    text: 'Your Dashboard'
    timeout: 10000  # 10 seconds instead of default 5

# Wait for animations to finish before asserting
- waitForAnimationToEnd
- assertVisible:
    text: 'Profile Loaded'

# Scroll down before asserting an element below the fold
- scroll:
    direction: DOWN
- assertVisible:
    text: 'Footer'

Launching the App Fresh with clearState

By default, launchApp brings the app to the foreground if it is already running (warm start). For tests that must start with a clean state — no logged-in user, empty database cache — use clearState: true to delete all app data before launching.

This is equivalent to uninstalling and reinstalling the app. Use it in your most critical test flows to ensure they start from a predictable baseline and do not depend on data left by previous flows.

# maestro/flows/fresh-login.yaml
appId: com.example.myapp
---
# Clear ALL app data (like a fresh install)
- launchApp:
    clearState: true

- assertVisible:
    text: 'Welcome to MyApp'  # Onboarding screen appears

- tapOn:
    text: 'Sign In'

- tapOn:
    id: 'email-input'
- inputText: 'test@example.com'

- tapOn:
    id: 'password-input'
- inputText: 'testpassword'

- tapOn:
    text: 'Sign In'

- assertVisible:
    text: 'Home'

Organizing Flows with Subflows

For repetitive steps like logging in before every test, extract them into a subflow YAML file and reference it with runFlow. This keeps each test flow focused on its specific scenario and makes login setup a one-line reusable step.

Subflows work like function calls in code — they execute in-line with the parent flow. You can pass parameters to subflows using the env section to make them reusable with different data (different users, different input values).

# maestro/flows/subflows/login.yaml
appId: com.example.myapp
---
- tapOn:
    id: 'email-input'
- inputText: '${EMAIL}'
- tapOn:
    id: 'password-input'
- inputText: '${PASSWORD}'
- tapOn:
    text: 'Sign In'
- assertVisible:
    text: 'Home'

# maestro/flows/profile.yaml
appId: com.example.myapp
env:
  EMAIL: user@test.com
  PASSWORD: testpass
---
- launchApp:
    clearState: true
- runFlow: subflows/login.yaml
- tapOn:
    text: 'Profile'
- assertVisible:
    text: 'Edit Profile'

Maestro Studio for Visual Recording

Maestro Studio is an interactive web-based UI that streams your simulator screen and lets you record flows by clicking on elements. Run maestro studio and it opens a browser where you can click to generate YAML commands automatically.

This is the fastest way to create your first flows — record the happy path interactively, then review and edit the generated YAML to add assertions and handle edge cases. Studio also shows the element tree for each screen, helping you find the best testID or text to target.

# Start Maestro Studio
maestro studio
# Opens browser at http://localhost:9999
# - Left panel: live simulator view
# - Click any element to generate a tapOn command
# - Type in input fields to generate inputText commands
# - Right panel: generated YAML that you can copy

Quick Check

Test your understanding of React Native Mobile Development concepts from this lesson.

Lesson Recap

In this lesson you learned: how to install Maestro and write a YAML flow file that launches the app and asserts on visible content, how to use tapOn, inputText, and assertVisible to drive user interactions in flows, and how to use subflows to share repetitive steps like login across multiple test flows. Next up we write more advanced Maestro assertions and handle dynamic UI states.

Frequently asked questions

Is the “Installing Maestro and Running Your First Flow” lesson free?

Yes — the full text of “Installing Maestro and Running Your First Flow” is free to read here on the web, and the React Native Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the React Native Academy course, upgrade to CoddyKit PRO.

What will I learn in “Installing Maestro and Running Your First Flow”?

Install the Maestro CLI, write a YAML flow file that launches the app and taps a button, run it against a running simulator, and read the test report. You practise React Native Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start React Native Academy?

No prior experience is required. React Native Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Installing Maestro and Running Your First Flow” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this React Native Academy lesson?

Yes. Every React Native Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Installing Maestro and Running Your First Flow
  2. Assertions and Waiting for Elements
  3. Testing Multi-Screen User Journeys
  4. Maestro in CI with GitHub Actions
← Back to React Native Academy