UI testing your React Native apps using Maestro

Table of contents

    UI testing your React Native apps using Maestro
    TL;DR

    Maestro simplifies mobile user interface (UI) testing with its YAML-based approach that works seamlessly with React Native applications. This article covers everything from installation and setup, to writing test flows and implementing advanced testing strategies for production-ready React Native apps.

    Testing mobile applications is difficult, and even more so when using cross-platform frameworks like React Native. Traditional testing frameworks often require complex setup, extensive configuration, and preexisting knowledge of platform-specific testing tools. Enter Maestro — an easy-to-use mobile UI testing framework.

    Whether you’re building a simple productivity app or a complex document management system like those powered by Nutrient React Native SDK, reliable UI testing ensures your users have a consistent, bug-free experience across iOS and Android platforms.

    At Nutrient, we use Maestro to test our React Native SDK with end-to-end tests, ensuring document viewing, annotation, form filling, and other features work consistently across platforms.

    Get started with Nutrient React Native SDK

    Integrate document workflows and native functionality into your React Native app with ease.

    Why UI testing matters for React Native apps

    UI testing goes beyond unit tests by validating how users actually interact with your application. For React Native apps, this means ensuring:

    • Cross-platform consistency — Your app behaves the same on iOS and Android
    • User workflows function correctly — Complex interactions like form submissions, annotations, navigation flows, and data persistence work as expected

    The limitations of traditional React Native testing

    Traditional React Native testing tools like Jest and React Native Testing Library can only test the JavaScript layer of your application; they cannot execute or validate native code functionality. This creates significant testing gaps when using React Native libraries that are built on native SDKs such as Nutrient React Native SDK. For apps using React Native SDKs that bridge to native functionality, end-to-end testing with tools like Maestro becomes essential to validate the complete user experience and flows, including the native code execution that traditional testing cannot reach.

    What is Maestro?

    Maestro(opens in a new tab) is a mobile UI testing framework built on learnings from existing frameworks like Appium, Espresso, UIAutomator, and XCTest. Unlike traditional testing frameworks that require complex programming, Maestro uses simple YAML files to define test flows.

    Key advantages of Maestro

    Simplicity first — Tests are written in YAML, making them readable and maintainable by both developers and QA teams.

    Cross-platform support — One framework works for iOS, Android, React Native, and Flutter.

    No complex setup — Maestro requires minimal configuration to get started.

    CI/CD friendly — Lightweight architecture integrates easily with continuous integration pipelines, and it also supports cloud-based testing.

    Prerequisites

    Before getting started with Maestro, ensure you have the following:

    • A React Native development environment set up with the React Native CLI(opens in a new tab)
    • iOS Simulator (for iOS testing); Android Emulator or an Android device (for Android testing)
    • macOS or Linux (Maestro doesn’t support Windows natively)
    • Node.js 16+ for your React Native project
    • Basic YAML knowledge (though Maestro’s syntax is straightforward)

    Step 1 — Installing Maestro

    Install Maestro using the official installer script:

    Terminal window
    curl -Ls "https://get.maestro.mobile.dev" | bash

    Verify the installation:

    Terminal window
    maestro -v

    For iOS testing, you’ll also need Facebook IDB:

    Terminal window
    pip3 install fb-idb

    Step 2 — Setting up your React Native project for testing

    Next, you’ll create a sample React Native app to demonstrate Maestro testing. If you already have a project, you can skip to the configuration steps.

    Creating a test-ready React Native app

    Terminal window
    npx react-native@latest init MaestroTestApp
    cd MaestroTestApp

    Adding testID properties

    Maestro interacts with components using either text content or testID properties. Add testID to components you want to test:

    App.js
    import React, { useState } from "react";
    import {
    SafeAreaView,
    Text,
    TextInput,
    TouchableOpacity,
    Alert,
    } from "react-native";
    const App = () => {
    const [username, setUsername] = useState("");
    const [password, setPassword] = useState("");
    const [isLoggedIn, setIsLoggedIn] = useState(false);
    const handleLogin = () => {
    if (username && password) {
    setIsLoggedIn(true);
    Alert.alert("Success", "Login successful!");
    } else {
    Alert.alert("Error", "Please fill in all fields");
    }
    };
    const handleLogout = () => {
    setIsLoggedIn(false);
    setUsername("");
    setPassword("");
    };
    if (isLoggedIn) {
    return (
    <SafeAreaView style={{ flex: 1, padding: 20, justifyContent: "center" }}>
    <Text testID="welcome-message">Welcome, {username}!</Text>
    <TouchableOpacity testID="logout-button" onPress={handleLogout}>
    <Text>Logout</Text>
    </TouchableOpacity>
    </SafeAreaView>
    );
    }
    return (
    <SafeAreaView style={{ flex: 1, padding: 20, justifyContent: "center" }}>
    <Text testID="login-title">Log in to your account</Text>
    <TextInput
    testID="username-input"
    placeholder="Username"
    value={username}
    onChangeText={setUsername}
    autoCapitalize="none"
    />
    <TextInput
    testID="password-input"
    placeholder="Password"
    value={password}
    onChangeText={setPassword}
    secureTextEntry
    />
    <TouchableOpacity testID="login-button" onPress={handleLogin}>
    <Text>Login</Text>
    </TouchableOpacity>
    </SafeAreaView>
    );
    };
    export default App;

    Step 3 — Creating your first Maestro test flow

    Create a .maestro directory in your project root and add your first test file:

    Terminal window
    mkdir .maestro

    Basic login flow test

    Create .maestro/login-flow.yaml:

    Terminal window
    touch .maestro/login-flow.yaml
    .maestro/login-flow.yaml
    appId: com.maestrotestapp
    ---
    - launchApp
    - assertVisible: "Log in to your account"
    # Test successful login
    - tapOn:
    id: "username-input"
    - inputText: "testuser"
    - tapOn:
    id: "password-input"
    - inputText: "password123"
    - tapOn:
    id: "login-button"
    # Verify login success
    - assertVisible: "Welcome, testuser!"
    - assertVisible:
    id: "logout-button"
    # Test logout
    - tapOn:
    id: "logout-button"
    # Verify return to login screen
    - assertVisible: "Log in to your account"
    - assertVisible:
    id: "username-input"

    Step 4 — Running your tests

    Before executing any tests, the React Native app must be built and installed on the target device or simulator. This ensures Maestro can interact with a fully compiled version of the application during testing.

    Build and install your app

    First, build your React Native app:

    Terminal window
    # For iOS
    npx react-native run-ios
    # For Android
    npx react-native run-android

    Execute Maestro tests

    Run a single test flow:

    Terminal window
    maestro test .maestro/login-flow.yaml

    Run all tests in the directory:

    Terminal window
    maestro test .maestro/

    Understanding test output

    Maestro provides detailed output for each test step:

    ⚠️ Flow login-flow.yaml
    ✅ Launch app "com.maestrotestapp"
    ✅ Assert that "Log in to your account" is visible
    ✅ Tap on id: "username-input"
    ✅ Input text "testuser"
    ✅ Tap on id: "password-input"
    ✅ Input text "password123"
    ✅ Tap on id: "login-button"
    ✅ Assert that "Welcome, testuser!" is visible
    ✅ Assert that logout-button is visible
    ✅ Tap on id: "logout-button"
    ✅ Assert that "Log in to your account" is visible
    ✅ Assert that username-input is visible
    Flow succeeded

    Advanced Maestro techniques for React Native

    With basic tests in place, advanced techniques like scrolling, reusable variables, and AI-powered validations enable more robust and flexible test flows.

    Working with ScrollViews and navigation

    # Test scrolling and navigation
    - scroll
    - scrollUntilVisible:
    element:
    id: "bottom-button"
    direction: DOWN

    Using variables for reusable tests

    # Test with different data
    env:
    USERNAME: "testuser"
    PASSWORD: "password123"
    ---
    - tapOn:
    id: "username-input"
    - inputText: ${USERNAME}
    - tapOn:
    id: "password-input"
    - inputText: ${PASSWORD}

    AI-powered testing with Maestro

    Maestro also includes AI capabilities that can enhance your testing workflows.

    AI-powered assertions

    Use AI to validate complex UI states and content:

    # AI-powered visual validation.
    - assertWithAI: "Verify the login form is properly displayed"
    - assertNoDefectsWithAi: "Check for any visual defects on the screen"
    # AI-powered text extraction.
    - extractTextWithAI: "Extract the error message text"

    AI configuration

    To use AI commands like assertWithAI and assertNoDefectsWithAi, you need to configure an API key. Maestro uses custom AI models through its cloud backend, requiring the MAESTRO_CLOUD_API_KEY environment variable:

    Terminal window
    export MAESTRO_CLOUD_API_KEY=your_api_key_here

    Account required: You need a Maestro account to use AI features. Create a free account at maestro.dev(opens in a new tab). Some features might require a paid subscription.

    AI testing is particularly valuable for React Native apps where UI components may render differently across platforms, or when dealing with dynamic content from APIs.

    AI assistant integration with MCP

    Maestro supports the Model Context Protocol (MCP), which allows AI assistants like Claude, Cursor, or Windsurf to interact directly with your Maestro tests. This enables AI-powered test generation, debugging, and analysis:

    Terminal window
    # MCP is included with Maestro CLI.
    maestro mcp

    Configure your MCP client (like Claude Desktop) to connect to Maestro:

    {
    "mcpServers": {
    "maestro": {
    "command": "maestro",
    "args": ["mcp"]
    }
    }
    }

    With MCP integration, AI assistants can:

    • Generate test flows based on your app’s UI
    • Debug failing tests with intelligent analysis
    • Suggest improvements to existing test suites
    • Analyze test coverage and recommend additional scenarios

    Using Maestro Studio for visual test creation

    Maestro Studio is a visual tool that simplifies test creation:

    Terminal window
    maestro studio

    This opens a GUI where you can:

    • Record interactions by clicking your app
    • Generate YAML automatically from your actions
    • Inspect element properties to find the best selectors
    • Debug failing tests with visual step-by-step execution

    Maestro Studio is particularly useful when working with complex UI components or when you need to identify hard-to-select elements, either by ID or screen coordinates.

    Integrating Maestro with CI/CD

    Maestro integrates seamlessly with CI/CD pipelines. Simply install Maestro in your CI environment and run your tests:

    Terminal window
    # Install Maestro.
    curl -Ls "https://get.maestro.mobile.dev" | bash
    # Run tests.
    maestro test .maestro/

    For cloud-based testing, Maestro offers cloud execution, which handles device provisioning and parallel test execution automatically.

    Conclusion

    Maestro’s YAML-based approach makes it easy to create and maintain tests, giving you confidence in changes and additions made to your React Native apps.

    By following the practices outlined in this guide, you can:

    • Reduce testing overhead with simple, maintainable test flows
    • Increase confidence in your React Native apps across platforms
    • Catch issues early with automated UI testing in your CI/CD pipeline

    With Maestro, testing is no longer an afterthought — it becomes a reliable part of your development process, helping you ship better apps faster and with greater confidence.

    Level up your React Native testing

    Combine the power of Maestro with Nutrient React Native SDK to build, test, and ship reliable document workflows across iOS and Android.

    Erhard Brand

    Erhard Brand

    Hybrids Engineer

    Erhard is a mobile software engineer with a focus on iOS. He enjoys working in a fast-paced environment and is a solution-focused person. In his spare time, he enjoys spending time with his family and traveling.

    Explore related topics

    FREE TRIAL Ready to get started?