End‐To‐End Testing with Maestro - Swent-Fall-2024-team-10/leazy GitHub Wiki

End-to-end (E2E) testing allows you to simulate real-world user interactions with your app, ensuring that key workflows function as expected. Maestro is a tool specifically designed to automate E2E testing in a simple and effective way, particularly for React Native apps.

Why Use Maestro?

Cross-Platform: Maestro supports both iOS and Android. Simple YAML-based Syntax: Define flows easily in YAML format. Test Automation: Automate complex workflows like login, navigation, and form submissions. Fast Feedback Loop: Run tests locally and see results in real-time.

Setting Up Maestro for React Native

1. Install Maestro

To install Maestro, run the following commands:

Linux or macOS with the CLI :

Run the following command to install Maestro on macOS, Linux or Windows (WSL):

curl -fsSL "https://get.maestro.mobile.dev" | bash

macOS if you have homebrew:

Dependencies:

Xcode (recommended version is 14 or higher)

Please make sure that Command Line Tools are installed (Xcode -> Preferences -> Locations -> Command Line Tools)

After setting up the macOS dependencies above, follow the default installation instructions:

brew tap mobile-dev-inc/tap brew install maestro

After installation, check if Maestro is installed correctly by running:

$ maestro -v

2. App Setup

Ensure that your app is set up with correct app identifiers to be compatible with Maestro:

For iOS: Add ios.bundleIdentifier in app.json. For Android: Add android.package in app.json. Example app.json:

{
  "expo": {
    "name": "leazy",
    "slug": "leazy",
    "version": "1.0.0",
    "orientation": "portrait",
    "icon": "./assets/images/icon.png",
    "scheme": "myapp",
    "userInterfaceStyle": "automatic",
    "splash": {
      "image": "./assets/images/splash.png",
      "resizeMode": "contain",
      "backgroundColor": "#ffffff"
    },
    "ios": {
      "supportsTablet": true, 
      "bundleIdentifier": "com.swent.leazy"
    },
    "android": {
      "adaptiveIcon": {
        "foregroundImage": "./assets/images/adaptive-icon.png",
        "backgroundColor": "#ffffff"
      },
      "package": "com.swent.leazy"
    },
    "web": {
      "bundler": "metro",
      "output": "static",
      "favicon": "./assets/images/favicon.png"
    },
    "experiments": {
      "typedRoutes": true
    }
  }
}

Ensure that you have the bundle identifier and package defined as Maestro uses them to launch the app for testing.

3. Creating a Test Flow

You can write Maestro flows in a YAML file that defines each step of the user interaction. (create a flow.yml file in the root of the project)

Example Workflow: Testing Navigation and Form Submission In this example, we'll test a navigation flow where the user:

1 . Opens the app. 2. Navigates to "Settings." 3. Goes back. 4. Taps on "Report." 5. Submits a form with issue details.

Test flow file (flow.yaml):

appId: "com.swent.leazy"
---
- launchApp

- tapOn: "Go to Settings"

- tapOn : 
      id: "go-back-button"

- tapOn:
    point: "7%,6%"

- tapOn: "Report"

- tapOn: "Name the issue"
- inputText: "Meastro test for e2e"

- tapOn: "Description"
- inputText: "This is a test for e2e"

4. Running the Workflow

You can run your Maestro test locally using the following command on a new tab:

$ maestro test flow.yaml

After starting the app by doing this command :

npx expo start

Using Test IDs

To make your flows less dependent on UI text and more flexible across different languages or environments, you can use test IDs for selecting UI elements.

<TouchableOpacity testID='go-back-button' style={styles.backButton} onPress={() => navigation.goBack()}>
        <Ionicons name="arrow-back" size={24} color="black" />
        <Text style={styles.backButtonText}>Back</Text>
      </TouchableOpacity>
<Button title="Sign in" testID="signInButton" onPress={handleSignIn} />

Then, in your Maestro flow:

- tapOn:
    id: "signInButton"

Or you can use directly the title of the button :

<Button
          title="Go to Settings"
          onPress={() => navigation.navigate('Settings')} // Navigate to Settings
        />

Also if you are stuck on how to interact with button that do not exist on the code (I had this problem where I couldn't find the navigation button), you can use the command $ maestro studio after launching your simulator.

It will allow you to visually select UI elements in order to receive suggestions on how to interact with the element in your Flow

Maestro Studio automatically generates examples of how you can interact with the selected element in your Flows. You can double click on the example to execute it directly, or use the hotkeys to copy it to the clipboard or open the relevant documentation

image

image

image

Advanced Maestro Features

1. Random Inputs

Maestro can generate random text, emails, and numbers, which is useful for testing forms:

- inputRandomText
- inputRandomEmail
- inputRandomNumber
 

2. Assertions

Use assertions to check if elements are visible or if certain conditions are met. For example, verifying if a success message appears:

- assertVisible: "Sign in successfully"

3. Nested Flows

You can reuse common steps (like logging in) by creating nested flows:

# sign-in-subflow.yaml
appId: com.example.app
---
# Enter username
- tapOn:
    id: "usernameInput"
- inputText: ${USERNAME}
- hideKeyboard

# Enter password
- tapOn:
    id: "passwordInput"
- inputText: ${PASSWORD}
- hideKeyboard

# Main flow using the nested flow
- runFlow:
    file: sign-in-subflow.yaml
    env:
      USERNAME: "TestUser"
      PASSWORD: "TestPassword"

Recording Flows

You can record a video of the flow execution to review or debug later:

$ maestro record flow.yaml

This generates an .mp4 video that shows the entire flow being executed, which is useful for debugging complex interactions.

Conclusion

Maestro provides a flexible and powerful way to write end-to-end tests for React Native applications. With the YAML-based syntax, you can easily automate workflows and ensure your app behaves correctly in various scenarios. You can also integrate your tests into your CI pipeline and use advanced features like random input generation and recording flows for debugging.

Make sure to use test IDs for more reliable testing and take advantage of nested flows to reduce code duplication in your tests.

I will do a demo for you on Thursday so that you'll be able to visualise everything

⚠️ **GitHub.com Fallback** ⚠️