Exploring Mobile UI Testing with GitHub Actions and Maestro

Joe McGuinness
2 min readFeb 13, 2024

--

I recently had some time between projects to try out integrating Maestro (https://maestro.mobile.dev/), a tool for running UI tests against mobile apps, with a GitHub Actions workflow. I’m using a self hosted runner for this as I had some issues running against the github provided ones. Below, I’ll share my yaml file for this, and the reasons for each section

Starting Off: Code Checkout

- name: Checkout code
uses: actions/checkout@v2

The initial step involves checking out the codebase, a fundamental action that provides access to the latest version of our app for testing purposes.

Installing dependencies

- name: Install dependencies and Maestro
run: |
export MAESTRO_VERSION=1.33.1
curl -Ls “https://get.maestro.mobile.dev" | bash
arch -arm64 brew tap facebook/fb
arch -arm64 brew install facebook/fb/idb-companion
arch -arm64 brew install jq

Following that, I installed Maestro along with its necessary dependencies. I’ve encountered an issue in the latest version of Maestro (1.35.x), so I’m using an older version that I know works.

Setting Up the Java Environment


- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: ‘11’
distribution: ‘adopt’

Given Maestro’s Java dependency, setting up JDK 11 was needed. The existing `actions/setup-java` action facilitated this, streamlining the Java management process and ensuring its availability for Maestro.

Simulator Preparation for UI Testing

   - name: Start iOS Simulator
run: |
# Find a simulator by name (e.g., iPhone 15)
DEVICE_ID=$(xcrun simctl list devices available --json | jq -r '.devices[] | .[] | select(.name == "iPhone 15") | .udid' | head -n 1)
DEVICE_STATE=$(xcrun simctl list devices available --json | jq -r --arg DEVICE_ID "$DEVICE_ID" '.devices[] | .[] | select(.udid == $DEVICE_ID) | .state')

if [ -z "$DEVICE_ID" ]; then
echo "No available simulator found for the criteria."
exit 1
fi

echo "DEVICE_ID=$DEVICE_ID" >> $GITHUB_ENV

if [ "$DEVICE_STATE" != "Booted" ]; then
# Boot the simulator if it's not already booted
xcrun simctl boot "$DEVICE_ID"
# Wait a bit for the simulator to boot
sleep 30
else
echo "Simulator with DEVICE_ID=$DEVICE_ID is already booted."
fi

For these tests I’m using the iOS simulator. Here, I focused on selecting and booting an appropriate simulator (“iPhone 15”), utilizing `jq` to parse `simctl` outputs effectively. This ensured our tests would run in a controlled, consistent environment. We could run against any simulator and/or version of iOS installed on the runner machine.

Executing Maestro UI Tests


- name: Run Maestro UI tests
run: |
export PATH=”$PATH:$HOME/.maestro/bin”
xcrun simctl install $DEVICE_ID Wikipedia.app
maestro — device $DEVICE_ID test ios-advanced-flow.yaml

The final and most important part of this workflow was running the Maestro UI tests themselves. After ensuring Maestro’s binary was accessible, I installed the test application (the provided sample wikipedia app in this case) on the simulator and initiated the tests using the sample test file. I pass in the $DEVICE_ID captured in the previous step

Reflections

While it took some time getting my head around certain setup steps for this, I actually found the process for getting maestro tests running to be fairly straightforward. I now have a template that I can adapt for future projects. I hope this helps you all with your projects!

--

--