Automated End-2-End Testing

Native E2E Testing With Expo and Maestro in 5 steps

Learn how to implement End-2-End testing for iOS and Android apps and integrate into GitHub CI.

Christof
Lingvano

--

Native E2E Testing with Maestro and Expo

AsAs a former web developer, it is quite a change to release native apps. The time it takes to ship your changes to production is way longer than deploying your changes on the web.

Do you struggle with native app testing as well? Luckily, there are some awesome tools to make the workflow for native apps more stable and easier to manage.

Roll out new releases with ease and confidence! A huge part of native releases is the confidence that everything in the app works fine. Once a release has started, it is impossible to make it undone. We have implemented a lot of automated testing but struggled with native E2E for a long time. We tried many tools like Appium or Detox, but now we have finally found a working solution: Maestro tackles the problems of native End-2-End testing and even makes testing fun — locally and in CI.

In the next 5 steps, you will learn how to set up E2E testing for Expo apps with Maestro and create a GitHub CI automation.

Prerequisite for this tutorial

This tutorial is built for a React-Native Expo app for iOS, Android and Web. The automation runs in GitHub Actions. There is an example repository. We recommend setting up a new dummy project. Run these commands:

npx create-expo-app maestro-eas-example
cd maestro-eas-example
eas login
eas build:configure

Add the bundleIdentifier to app.json. You will later need it to start the Maestro tests.

"android": {
"package": "com.maestroEasExample.app"
},
"ios": {
"bundleIdentifier": "com.maestroEasExample.app"
}

1. Setup Maestro

Install Maestro locally. You can also find the guide in Maestro Docs.

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

For iOS emulators, you will need some additional config (replace idOfIOSDevice with the correct ID by running xcrun simctl list).

brew tap facebook/fb
brew install facebook/fb/idb-companion
idb_companion - udid idOfIOSDevice

2. Write your first test

Let’s start with a simple test. You can check out how assertions and actions work directly within the Maestro Docs. Create your first test in ./maestro/ as test.yaml.

appId: com.maestroEasExample.app
---
- launchApp:
clearState: true

- assertVisible: "Open up App.js to start working on your app!"

3. Make your first test green

Start your app locally and run the Maestro test. Feel free to use expo run:ios or expo run:android. If this tutorial works on one platform, it will also work on the other.

expo run:[ios|android]
maestro test maestro/test.yaml

4. Prepare GitHub automation

Create a public GitHub repository and add your code to your new repository. Add the Expo token as a secret to your repository. Create the GitHub workflow ./github/workflows/eas-build.yaml (folder structure is important):

name: EAS Builds
on:
push:
branches: [main]

jobs:
eas-build:
name: Trigger EAS build for development-sim
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- name: 🏗 Setup repository
uses: actions/checkout@v3

- name: 🏗 Setup Node
uses: actions/setup-node@v3
with:
node-version: 18.x
cache: yarn

- name: 🏗 Setup EAS
uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}

- name: 📦 Install dependencies
run: yarn install

- name: 🚀 Send build request
run: eas build --platform all --non-interactive --no-wait --profile development-sim
shell: bash

Maestro requires a simulator build. Therefore, you need to create a new profile in eas.json by adding the following block to the buildsobject.

"development-sim": {
"distribution": "internal",
"ios": {
"simulator": true
}
},

Add your EAS projectId and owner to the app.json.

"owner": "yourEasUser",
"extra": {
"eas": {
"projectId": "yourEasProjectId"
}
},

For Android builds, you once need to run eas build locally to generate a new Android Keystore.

 eas build --platform android --no-wait --profile development-sim

Commit your changes and push them to your repository. In the GitHub Actions tab, you will see your automation running. Once finished, you can open the step ”🚀 Send build request”. At the end of this command, you will find the links to Expo’s build details. Congrats! You now have your first automated app build 🎉

Screenshot of GitHub Actions
On line 22 and 23 you get the direct links to Expo, where you can download your app builds.

5. Add automated E2E testing to your new build

Copy the Maestro API key and add it as a secret to Expo. Make sure to name the secret MAESTRO_API_KEY. Create the eas-build-on-success.sh file.

#!/usr/bin/env bash

set -eox pipefail

curl -Ls "https://get.maestro.mobile.dev" | bash
export PATH="$PATH":"$HOME/.maestro/bin"

if [ "$EAS_BUILD_PLATFORM" = "ios" ]
then
brew install java
echo 'export PATH="/opt/homebrew/opt/openjdk/bin:$PATH"' >> ~/.zshrc
sudo ln -sfn /opt/homebrew/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk
export CPPFLAGS="-I/opt/homebrew/opt/openjdk/include"

APP_EXECUTABLE_PATH=/Users/expo/workingdir/build/ios/build/Build/Products/Release-iphonesimulator/MaestroEasExample.app
else
APP_EXECUTABLE_PATH=/home/expo/workingdir/build/android/app/build/outputs/apk/release/app-release.apk
fi

MAESTRO_API_KEY=$MAESTRO_API_KEY
maestro cloud --apiKey $MAESTRO_API_KEY $APP_EXECUTABLE_PATH maestro/test.yaml

In the package.json, you need to add the eas-build-on-success hook.

"eas-build-on-success": "bash ./path/to/eas-build-on-success.sh"

Commit and push your changes again. Your pipeline will run, and after the build is ready, it will automatically start the Maestro test flow. In the Expo build details, you can open “Build success hook”. At the end of this command, you will find the link to Maestro Cloud, where you can see the videos of your test assertions.

Congrats! 🥳 Your app is now automatically E2E tested every time you push to your repository! Make sure to cover all your features in test flows (and use the amazing Maestro Studio for that), and you can be confident about your app working fine with every release!

Screenshot of test flows in Maestro Cloud
You will find screen recordings of you test assertions in Maestro Cloud

Optional step: Optimize your workflow with an error notification system

Automatically notify your team if a pipeline fails. We have decided to automatically create Asana tickets if an E2E test fails, as it offers space for discussion, and developers can be easily assigned to fix the problem, but you can choose whatever fits you. Just use the eas-on-error-script hook!

As easy as that

That’s it! Super simple setup. With these 5 steps, you made sure your iOS and Android app is E2E tested, and integrated automation into your workflow. This will guarantee that new code pushed to your repository does not break anything. Once you have covered your whole app with Maestro test flows, you can now release without worrying about the functionality of your app — if the CI pipeline is green, all is fine 🚀

Check out and star the example repository of this tutorial. Also, have a look at our other projects, where we share some details of the technical setup & infrastructure of our web, iOS, and Android React-Native Expo app. You will soon find other cool stuff there, like auto-submitting your builds to AppStore and PlayConnect, web E2E automation, UI testing, …

Do you have questions about our setup or ideas for improvement? Just leave a comment! Make sure to follow us to get more insights into our projects and our day-to-day developer life.

Curious about our app? You can check out our production version on Web, iOS or Android. Or follow us on Twitter, Instagram or LinkedIn.

Also, we are always hiring =) join us!

--

--