u/GludiusMaximus

A few months ago I spent an unfortunate amount of time setting up our GH Actions to successfully run our Maestro tests (on Android - iOS would be another story I think).

Now, while working on another task, I see that Expo / EAS offer a maestro job "type" which looks like a lot less configuration. I'm wondering if anyone is using it and can attest to its stability (or not).

Fwiw, my workflow file currently looks like this - it feels a bit duct-taped together, and I am totally open to hearing feedback on it. Looking at it, it feels very brittle and I would happily move to EAS if it simplifies this process.

tl;dr it:

  1. sets up an android emulator from a potential list of devices from a matrix
  2. Creates AVD on the emulator
  3. makes sure there's enough space on the emulator to even install my app
  4. downloads the latest staging version of the APK from eas (a bit hacky but is very consistent)
  5. Runs the maestro tests
  6. outputs screenshots and test results as artifcats

​

on:
  workflow_dispatch:
    inputs:
      apk_url:
        description: 'URL to the Staging APK from EAS'
        required: true

jobs:
  setup-emulator:
    name: Setup Emulator (${{ matrix.device.profile }})
    runs-on: ubuntu-latest
    env:
      FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
    strategy:
      fail-fast: true
      matrix:
        device:
          - { api: 33, profile: "pixel_7_pro" }
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Enable KVM
        run: |
          echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
          sudo udevadm control --reload-rules
          sudo udevadm trigger --name-match=kvm
      - name: Check disk space
        run: |
          echo "Removing dotnet and swift directories..."
          sudo rm -rf /usr/share/dotnet
          sudo rm -rf /usr/share/swift
      - name: AVD cache
        uses: actions/cache@v4
        id: avd-cache
        with:
          path: |
            ~/.android/avd/*
            ~/.android/adb*
          key: avd-${{ matrix.device.api }}-2048M
      - name: Create AVD and generate snapshot for caching
        if: steps.avd-cache.outputs.cache-hit != 'true'
        uses: reactivecircus/android-emulator-runner@v2
        with:
          api-level: ${{ matrix.device.api }}
          target: google_apis
          arch: x86_64
          profile: ${{ matrix.device.profile }}
          force-avd-creation: false
          emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
          disable-animations: true
          cores: 2
          ram-size: 2048M
          disk-size: 2048M
          script: echo "Generated AVD snapshot for caching."

  run-maestro-tests:
    name: Run Maestro Tests (${{ matrix.device.profile }})
    needs: setup-emulator
    runs-on: ubuntu-latest
    env:
      FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
    strategy:
      fail-fast: true
      matrix:
        device:
          - { api: 33, profile: "pixel_7_pro" }
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Enable KVM
        run: |
          echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
          sudo udevadm control --reload-rules
          sudo udevadm trigger --name-match=kvm
      - name: Check disk space
        run: |
          echo "Removing dotnet and swift directories..."
          sudo rm -rf /usr/share/dotnet
          sudo rm -rf /usr/share/swift
      - name: AVD cache
        uses: actions/cache@v4
        id: avd-cache
        with:
          path: |
            ~/.android/avd/*
            ~/.android/adb*
          key: avd-${{ matrix.device.api }}-2048M
      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: 22.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: Download Latest Staging APK
        id: download_apk
        run: |
          mkdir -p ./apk
          BUILD_LIST=$(eas build:list --platform=android --status=finished --profile=staging --json --non-interactive)
          BUILD_ID=$(echo "$BUILD_LIST" | jq -r '.[-1].id')
          ARTIFACT_URL=$(echo "$BUILD_LIST" | jq -r '.[0].artifacts.buildUrl')
          echo "Downloading from: $ARTIFACT_URL"
          curl -L "$ARTIFACT_URL" -o ./apk/app-client-debug.apk
      - name: Verify APK Download
        run: |
          if [ -f "./apk/app-client-debug.apk" ]; then
            MIN_SIZE=200
            FILE_SIZE=$(du -m ./apk/app-client-debug.apk | cut -f1)
            echo "APK exists. Size: ${FILE_SIZE}MB"
            if [ $FILE_SIZE -lt $MIN_SIZE ]; then
              echo "Error: APK size is less than ${MIN_SIZE}MB!"
              exit 1
            fi
          else
            echo "Error: APK file NOT found!"
            exit 1
          fi
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '17'
      - name: Install Maestro
        run: |
          curl -Ls "https://get.maestro.mobile.dev" | bash
          echo "$HOME/.maestro/bin" >> $GITHUB_PATH
      - name: Run Android Emulator and Maestro Tests
        uses: reactivecircus/android-emulator-runner@v2
        with:
          api-level: ${{ matrix.device.api }}
          target: google_apis
          arch: x86_64
          profile: ${{ matrix.device.profile }}
          disk-size: 2048M
          ram-size: 2048M
          cores: 2
          force-avd-creation: false
          disable-animations: true
          working-directory: .
          emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
          script: bash .github/scripts/run-maestro.sh
      - name: (Optional) Upload Test Reports
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: maestro-test-report-${{ matrix.device.profile }}
          path: reports/
u/GludiusMaximus — 24 days ago