Claude-skill-registry-data maestro-testing
Maestro E2E testing patterns for React Native. Use when implementing end-to-end tests.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry-data
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry-data "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/maestro-testing" ~/.claude/skills/majiayu000-claude-skill-registry-data-maestro-testing && rm -rf "$T"
manifest:
data/maestro-testing/SKILL.mdsource content
Maestro Testing Skill
This skill covers Maestro E2E testing for React Native apps.
When to Use
Use this skill when:
- Writing E2E tests
- Testing user flows
- Automating UI testing
- CI/CD testing
Core Principle
YAML SIMPLICITY - Maestro uses simple YAML syntax for readable, maintainable tests.
Installation
# macOS/Linux curl -Ls "https://get.maestro.mobile.dev" | bash # Verify installation maestro -v
Project Structure
__tests__/ └── e2e/ ├── flows/ │ ├── login.yaml │ └── common.yaml ├── login_flow.yaml ├── signup_flow.yaml ├── navigation_flow.yaml └── checkout_flow.yaml
Basic Test
# __tests__/e2e/login_flow.yaml appId: com.myapp --- - launchApp - tapOn: "Email" - inputText: "test@example.com" - tapOn: "Password" - inputText: "password123" - tapOn: "Sign In" - assertVisible: "Welcome"
Common Commands
App Control
# Launch app - launchApp # Clear app state and launch - launchApp: clearState: true # Stop app - stopApp
Tap Actions
# 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"
Text Input
# Input text - inputText: "Hello World" # Clear and input - clearText - inputText: "New Text" # Input in specific field - tapOn: "Email" - inputText: "user@example.com"
Assertions
# Assert element is visible - assertVisible: "Success" # Assert element is not visible - assertNotVisible: "Error" # Assert with timeout - extendedWaitUntil: visible: "Loaded" timeout: 10000
Scrolling
# 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 Gestures
# Swipe left (delete) - swipe: direction: LEFT start: "Item to delete" # Swipe down (refresh) - swipe: direction: DOWN start: above: "First Item"
Waiting
# Wait for animation - waitForAnimationToEnd # Wait specific time (ms) - wait: 2000 # Wait until visible - extendedWaitUntil: visible: "Element" timeout: 5000
Screenshots
# Take screenshot - takeScreenshot: screen_name
Flow Composition
Reusable Flows
# 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"
Conditional Flows
# Handle optional popups - runFlow: when: visible: "Accept Cookies" commands: - tapOn: "Accept" - tapOn: "Continue"
Environment Variables
# 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
Platform-Specific Tests
# iOS-specific - runFlow: when: platform: iOS commands: - tapOn: "iOS Settings" # Android-specific - runFlow: when: platform: Android commands: - tapOn: "Android Settings"
Complete Test Examples
Login Flow
# __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
Form Validation
# __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"
Navigation Flow
# __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"
Running Tests
# 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/
CI/CD Integration
# .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/
Notes
- Requires simulator/emulator running
- Use accessibility IDs for reliable selection
- Keep tests independent
- Use reusable flows for common actions
- Test on both platforms
- Consider Maestro Cloud for CI