Maestro E2E testing patterns for React Native. Use when implementing end-to-end tests.
This skill inherits all available tools. When active, it can use any tool Claude has access to.
This skill covers Maestro E2E testing for React Native apps.
Use this skill when:
YAML SIMPLICITY - Maestro uses simple YAML syntax for readable, maintainable tests.
# macOS/Linux
curl -Ls "https://get.maestro.mobile.dev" | bash
# Verify installation
maestro -v
__tests__/
└── e2e/
├── flows/
│ ├── login.yaml
│ └── common.yaml
├── login_flow.yaml
├── signup_flow.yaml
├── navigation_flow.yaml
└── checkout_flow.yaml
# __tests__/e2e/login_flow.yaml
appId: com.myapp
---
- launchApp
- tapOn: "Email"
- inputText: "test@example.com"
- tapOn: "Password"
- inputText: "password123"
- tapOn: "Sign In"
- assertVisible: "Welcome"
# Launch app
- launchApp
# Clear app state and launch
- launchApp:
clearState: true
# Stop app
- stopApp
# Tap by text
- tapOn: "Button Text"
# Tap by accessibility ID
- tapOn:
id: "submit-button"
# Tap by index (when multiple matches)
- tapOn:
text: "Item"
index: 0
# Long press
- longPressOn: "Delete"
# Input text
- inputText: "Hello World"
# Clear and input
- clearText
- inputText: "New Text"
# Input in specific field
- tapOn: "Email"
- inputText: "user@example.com"
# Assert element is visible
- assertVisible: "Success"
# Assert element is not visible
- assertNotVisible: "Error"
# Assert with timeout
- extendedWaitUntil:
visible: "Loaded"
timeout: 10000
# Scroll down
- scroll
# Scroll until visible
- scrollUntilVisible:
element: "Target Item"
direction: DOWN
timeout: 10000
# Scroll in element
- scroll:
element:
id: "scrollable-list"
direction: DOWN
# Swipe left (delete)
- swipe:
direction: LEFT
start: "Item to delete"
# Swipe down (refresh)
- swipe:
direction: DOWN
start:
above: "First Item"
# Wait for animation
- waitForAnimationToEnd
# Wait specific time (ms)
- wait: 2000
# Wait until visible
- extendedWaitUntil:
visible: "Element"
timeout: 5000
# Take screenshot
- takeScreenshot: screen_name
# flows/login.yaml
- tapOn: "Email"
- inputText: ${email}
- tapOn: "Password"
- inputText: ${password}
- tapOn: "Sign In"
- assertVisible: "Welcome"
# main_test.yaml
- launchApp
- runFlow:
file: flows/login.yaml
env:
email: "test@example.com"
password: "password123"
- tapOn: "Profile"
# Handle optional popups
- runFlow:
when:
visible: "Accept Cookies"
commands:
- tapOn: "Accept"
- tapOn: "Continue"
# Use environment variables
appId: ${APP_ID}
---
- launchApp
- tapOn: "Email"
- inputText: ${TEST_EMAIL}
# Run with variables
APP_ID=com.myapp TEST_EMAIL=test@test.com maestro test test.yaml
# iOS-specific
- runFlow:
when:
platform: iOS
commands:
- tapOn: "iOS Settings"
# Android-specific
- runFlow:
when:
platform: Android
commands:
- tapOn: "Android Settings"
# __tests__/e2e/login_flow.yaml
appId: com.myapp
---
- launchApp:
clearState: true
# Navigate to login
- tapOn: "Sign In"
# Enter credentials
- tapOn:
id: "email-input"
- inputText: "test@example.com"
- tapOn:
id: "password-input"
- inputText: "password123"
# Submit
- tapOn:
id: "login-button"
# Wait for navigation
- waitForAnimationToEnd
# Verify success
- assertVisible: "Welcome back"
- assertVisible: "Home"
# Take screenshot
- takeScreenshot: login_success
# __tests__/e2e/form_validation.yaml
appId: com.myapp
---
- launchApp
# Test empty submission
- tapOn: "Submit"
- assertVisible: "Email is required"
# Test invalid email
- tapOn: "Email"
- inputText: "invalid"
- tapOn: "Submit"
- assertVisible: "Invalid email"
# Test valid submission
- clearText
- inputText: "valid@example.com"
- tapOn: "Password"
- inputText: "ValidPass123!"
- tapOn: "Submit"
- assertVisible: "Success"
# __tests__/e2e/navigation_flow.yaml
appId: com.myapp
---
- launchApp
# Test tab navigation
- tapOn:
id: "tab-home"
- assertVisible: "Home Screen"
- tapOn:
id: "tab-search"
- assertVisible: "Search"
- tapOn:
id: "tab-profile"
- assertVisible: "Profile"
# Test back navigation
- tapOn: "Settings"
- assertVisible: "Settings"
- back
- assertVisible: "Profile"
# Run single test
maestro test __tests__/e2e/login_flow.yaml
# Run all tests
maestro test __tests__/e2e/
# Run on specific platform
maestro test __tests__/e2e/ --platform ios
# Generate JUnit report
maestro test __tests__/e2e/ --format junit --output results/
# .github/workflows/e2e.yml
name: E2E Tests
on: [push, pull_request]
jobs:
e2e:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
- name: Install dependencies
run: npm ci
- name: Install Maestro
run: |
curl -Ls "https://get.maestro.mobile.dev" | bash
echo "$HOME/.maestro/bin" >> $GITHUB_PATH
- name: Build app
run: npx expo prebuild && npx expo run:ios
- name: Run E2E tests
run: maestro test __tests__/e2e/
- name: Upload results
uses: actions/upload-artifact@v3
with:
name: e2e-results
path: results/