Skip to content

E2E Tests

E2E Tests #98

Workflow file for this run

name: E2E Tests
on:
workflow_dispatch:
inputs:
app:
description: 'Specific app to test (leave empty for all apps)'
required: false
type: string
platform:
description: 'Platform to test'
required: false
default: 'all'
type: choice
options:
- all
- android
- ios
jobs:
discover-apps:
name: Discover Apps
runs-on: ubuntu-latest
outputs:
apps: ${{ steps.set-apps.outputs.apps }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Discover apps
id: set-apps
run: |
if [ -n "${{ github.event.inputs.app }}" ]; then
apps='["${{ github.event.inputs.app }}"]'
else
# Dynamically discover apps in the /apps directory
apps=$(find apps -maxdepth 1 -mindepth 1 -type d -exec basename {} \; | jq -R . | jq -sc .)
fi
echo "apps=$apps" >> $GITHUB_OUTPUT
echo "Discovered apps: $apps"
e2e-android:
name: E2E Android - ${{ matrix.app }}
runs-on: ubuntu-latest
needs: discover-apps
if: ${{ github.event.inputs.platform == 'all' || github.event.inputs.platform == 'android' }}
strategy:
fail-fast: false
matrix:
app: ${{ fromJson(needs.discover-apps.outputs.apps) }}
steps:
- name: Delete unnecessary tools
uses: jlumbroso/free-disk-space@v1.3.1
with:
android: false # Don't remove Android tools
tool-cache: true # Remove image tool cache - rm -rf "$AGENT_TOOLSDIRECTORY"
docker-images: false # Takes 16s, enable if needed in the future
large-packages: false # includes google-cloud-sdk and it's slow
- name: Checkout code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: latest
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '23'
cache: 'pnpm'
- name: Install dependencies
run: |
pnpm install
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Restore APK from cache
id: cache-apk-restore
uses: actions/cache/restore@v4
with:
path: apps/${{ matrix.app }}/android/app/build/outputs/apk/debug/app-debug.apk
key: apk-${{ matrix.app }}
- name: Build Android app
if: steps.cache-apk-restore.outputs.cache-hit != 'true'
working-directory: apps/${{ matrix.app }}
run: |
pnpm nx run @react-native-harness/${{ matrix.app }}:build-android --tasks=assembleDebug
- name: Save APK to cache
if: steps.cache-apk-restore.outputs.cache-hit != 'true' && success()
uses: actions/cache/save@v4
with:
path: apps/${{ matrix.app }}/android/app/build/outputs/apk/debug/app-debug.apk
key: apk-${{ matrix.app }}
- name: Enable KVM group perms
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
ls /dev/kvm
- name: AVD cache
uses: actions/cache@v4
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-35-2
- 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: 35
arch: x86_64
profile: pixel_7
disk-size: 1G
heap-size: 1G
force-avd-creation: false
avd-name: Pixel_8_API_35
disable-animations: true
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
script: echo "Generated AVD snapshot for caching."
- name: Run E2E tests
uses: reactivecircus/android-emulator-runner@v2
with:
working-directory: apps/${{ matrix.app }}/android
api-level: 35
arch: x86_64
force-avd-creation: false
avd-name: Pixel_8_API_35
disable-animations: true
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
script: |
adb install -r "./app/build/outputs/apk/debug/app-debug.apk"
pnpm nx run @react-native-harness/${{ matrix.app }}:start --args="--harnessRunner android"
e2e-ios:
name: E2E iOS - ${{ matrix.app }}
runs-on: macos-latest
needs: discover-apps
if: ${{ github.event.inputs.platform == 'all' || github.event.inputs.platform == 'ios' }}
env:
NODE_OPTIONS: '--max-old-space-size=4096 --max-semi-space-size=64'
strategy:
fail-fast: false
matrix:
app: ${{ fromJson(needs.discover-apps.outputs.apps) }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: latest
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24.10.0'
cache: 'pnpm'
- name: Install dependencies
run: |
pnpm install
- name: Restore app from cache
id: cache-app-restore
uses: actions/cache/restore@v4
with:
path: ./apps/${{ matrix.app }}/ios/build/Build/Products/Debug-iphonesimulator/Playground.app
key: ios-app-${{ matrix.app }}
- name: CocoaPods cache
if: steps.cache-app-restore.outputs.cache-hit != 'true'
uses: actions/cache@v4
with:
path: |
./apps/${{ matrix.app }}/ios/Pods
~/Library/Caches/CocoaPods
~/.cocoapods
key: ${{ matrix.app }}-${{ runner.os }}-pods-${{ hashFiles('./apps/${{ matrix.app }}/ios/Podfile.lock') }}
restore-keys: |
${{ matrix.app }}-${{ runner.os }}-pods-
- name: Install CocoaPods
if: steps.cache-app-restore.outputs.cache-hit != 'true'
working-directory: apps/${{ matrix.app }}/ios
run: |
pod install
- name: Build iOS app
if: steps.cache-app-restore.outputs.cache-hit != 'true'
working-directory: apps/${{ matrix.app }}
run: |
pnpm react-native build-ios --buildFolder ./build --verbose
- name: Save app to cache
if: steps.cache-app-restore.outputs.cache-hit != 'true' && success()
uses: actions/cache/save@v4
with:
path: ./apps/${{ matrix.app }}/ios/build/Build/Products/Debug-iphonesimulator/Playground.app
key: ios-app-${{ matrix.app }}
- uses: futureware-tech/simulator-action@v4
with:
model: 'iPhone 16 Pro'
os: iOS
os_version: 18.6
wait_for_boot: true
erase_before_boot: false
- name: Install app
run: |
xcrun simctl install booted ./apps/${{ matrix.app }}/ios/build/Build/Products/Debug-iphonesimulator/Playground.app
- name: Run E2E tests
run: |
pnpm nx run-many -t build --projects="packages/*"
pnpm nx run @react-native-harness/${{ matrix.app }}:start --args="--harnessRunner ios"
- name: Capture simulator screenshot on failure
if: failure()
run: |
mkdir -p screenshots
xcrun simctl io booted screenshot screenshots/ios-failure-${{ matrix.app }}.png
- name: Upload screenshot artifact
if: failure()
uses: actions/upload-artifact@v4
with:
name: ios-failure-screenshot-${{ matrix.app }}
path: screenshots/ios-failure-${{ matrix.app }}.png
retention-days: 7