Run Maestro tests #6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Run Maestro tests | |
| env: | |
| # The name of the main module repository | |
| main_project_module: app | |
| # The name in the Play Store | |
| playstore_name: Soundscape | |
| on: | |
| # Allows you to run this workflow manually from the Actions tab. With no | |
| # inputs it downloads and tests the latest GitHub release. An optional tag | |
| # can be given to test an older release instead. | |
| workflow_dispatch: | |
| inputs: | |
| release_tag: | |
| description: 'Release tag to test (e.g. soundscape-1.0.12). Leave empty for the latest release.' | |
| required: false | |
| type: string | |
| # Allows another workflow (e.g. run-tests) to call this as a follow-on job, | |
| # passing the name of an APK artifact it uploaded earlier in the same run. | |
| workflow_call: | |
| inputs: | |
| apk_artifact: | |
| description: 'Name of an APK artifact uploaded earlier in the same run to install and test.' | |
| required: false | |
| type: string | |
| fail_on_error: | |
| description: 'Fail the run if any Maestro flow fails. Callers can set this false to keep Maestro non-blocking.' | |
| required: false | |
| type: boolean | |
| default: true | |
| jobs: | |
| maestro-test: | |
| runs-on: ubuntu-latest | |
| environment: development | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| # When called from another workflow, grab the APK that workflow built and | |
| # uploaded earlier in the same run. | |
| - name: Download APK from calling workflow | |
| if: ${{ inputs.apk_artifact != '' }} | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: ${{ inputs.apk_artifact }} | |
| path: apk | |
| # When run standalone, download the APK from a GitHub release. Defaults to | |
| # the latest release unless a tag was supplied. | |
| - name: Download APK from release | |
| if: ${{ inputs.apk_artifact == '' }} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RELEASE_TAG: ${{ inputs.release_tag }} | |
| run: | | |
| mkdir -p apk | |
| if [ -z "$RELEASE_TAG" ]; then | |
| RELEASE_TAG=$(gh release view --json tagName -q .tagName) | |
| echo "No tag supplied, using latest release: $RELEASE_TAG" | |
| else | |
| echo "Using requested release: $RELEASE_TAG" | |
| fi | |
| gh release download "$RELEASE_TAG" --pattern 'release-apk-*.zip' --dir apk | |
| unzip -o apk/release-apk-*.zip -d apk | |
| # The artifact (debug build) and the release zip (release build) put the | |
| # APK at different paths, so locate it rather than hard-coding the name. | |
| - name: Locate APK | |
| id: find-apk | |
| run: | | |
| apk_path=$(find apk -name '*.apk' | head -n1) | |
| if [ -z "$apk_path" ]; then | |
| echo "No APK found to test" >&2 | |
| exit 1 | |
| fi | |
| echo "Found APK: $apk_path" | |
| echo "apk_path=$apk_path" >> "$GITHUB_OUTPUT" | |
| - 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: Install Maestro | |
| run: MAESTRO_VERSION=2.6.0 curl -Ls 'https://get.maestro.mobile.dev' | bash | |
| # Fetch the Glasgow offline map extract on the runner host; it is pushed | |
| # onto the emulator in the Maestro Tests step below. | |
| - name: Download offline map extract | |
| run: | | |
| curl -Lsf -o glasgow-gb.pmtiles \ | |
| 'https://pub-0a3501283b024ab3bbfbb6d1e217f5d0.r2.dev/street-metadata/glasgow-gb.pmtiles' | |
| - name: Maestro Tests | |
| id: maestro-tests | |
| uses: reactivecircus/android-emulator-runner@v2 | |
| continue-on-error: true # IMPORTANT: allow pipeline to continue to Android Test Report step | |
| with: | |
| api-level: 34 | |
| arch: x86_64 | |
| ram-size: 2048M | |
| enable-hw-keyboard: false | |
| target: default | |
| script: | | |
| adb logcat -c # clear logs | |
| touch app/emulator.log # create log file | |
| chmod 777 app/emulator.log # allow writing to log file | |
| adb logcat >> app/emulator.log & # pipe all logcat messages into log file as a background process | |
| adb install ${{ steps.find-apk.outputs.apk_path }} | |
| # Push the Glasgow offline map extract into the app's offline-extracts | |
| # directory and pin the emulator GPS to the STA office, so the | |
| # location-dependent flows run against known map data and a fixed | |
| # location. The extracts directory is the app-specific external files | |
| # dir + "/Download" (see GeoEngine.offlineExtractPath); scoped storage | |
| # blocks writes there even for the shell user, so we use root - the | |
| # emulator runs a userdebug image, so "adb root" is available. | |
| # | |
| # The android-emulator-runner runs each script line in its own | |
| # "sh -c", so a shell variable assigned on one line is empty by the | |
| # next; the extract directory path is therefore inlined rather than | |
| # held in a variable. It is the app-specific external files dir + | |
| # "/Download" (see GeoEngine.offlineExtractPath). | |
| adb root | |
| adb wait-for-device | |
| adb shell mkdir -p /storage/emulated/0/Android/data/org.scottishtecharmy.soundscape/files/Download | |
| adb push glasgow-gb.pmtiles /storage/emulated/0/Android/data/org.scottishtecharmy.soundscape/files/Download/ | |
| # The .geojson metadata sidecar (findExtracts reads "<pmtiles>.geojson") | |
| # is committed under .github/fixtures as it is too small to be worth a | |
| # download, unlike the pmtiles itself. | |
| adb push .github/fixtures/glasgow-gb.pmtiles.geojson /storage/emulated/0/Android/data/org.scottishtecharmy.soundscape/files/Download/ | |
| # adb emu geo fix takes longitude then latitude. | |
| adb emu geo fix -3.223538 55.955360 | |
| mkdir maestro_outputs | |
| # Run every flow even if an earlier one fails, then fail the step at | |
| # the end if any of them failed. | |
| status=0 | |
| $HOME/.maestro/bin/maestro test --format=junit --output=report1.xml --test-output-dir=maestro_outputs --no-ansi maestro/Onboarding.yaml || status=1 | |
| $HOME/.maestro/bin/maestro test --format=junit --output=report2.xml --test-output-dir=maestro_outputs --no-ansi maestro/HomePage.yaml || status=1 | |
| $HOME/.maestro/bin/maestro test --format=junit --output=report3.xml --test-output-dir=maestro_outputs --no-ansi maestro/LocationDetails.yaml || status=1 | |
| $HOME/.maestro/bin/maestro test --format=junit --output=report4.xml --test-output-dir=maestro_outputs --no-ansi maestro/PlacesNearby.yaml || status=1 | |
| $HOME/.maestro/bin/maestro test --format=junit --output=report5.xml --test-output-dir=maestro_outputs --no-ansi maestro/MarkersAndRoutes.yaml || status=1 | |
| $HOME/.maestro/bin/maestro test --format=junit --output=report6.xml --test-output-dir=maestro_outputs --no-ansi maestro/RouteCreation.yaml || status=1 | |
| exit $status | |
| - name: Upload maestro reports | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: maestro-reports | |
| path: maestro_outputs | |
| - name: Upload Failing Test Report Log | |
| if: steps.maestro-tests.outcome != 'success' # upload the generated log on failure of the tests job | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: logs | |
| path: app/emulator.log # path to where the log is | |
| - name: Raise error on test fail # set a red tick on the workflow run if the tests failed | |
| # inputs.fail_on_error is unset for a manual (workflow_dispatch) run, in | |
| # which case we still want to fail; a caller can pass false to suppress. | |
| if: steps.maestro-tests.outcome != 'success' && inputs.fail_on_error != false | |
| run: exit 1 |