From 92bc8c52edfcb72627cb04580cbd493e2277318e Mon Sep 17 00:00:00 2001 From: theGrep01 Date: Wed, 10 Sep 2025 15:29:06 +0300 Subject: [PATCH] feat: add Android and iOS E2E test workflows and actions --- .github/actions/android-e2e/action.yaml | 87 +++++++++++++++++++++++++ .github/actions/ios-e2e/action.yaml | 79 ++++++++++++++++++++++ .github/workflows/build-and-test.yml | 5 ++ .github/workflows/e2e-metro.yml | 59 +++++++++++++++++ 4 files changed, 230 insertions(+) create mode 100644 .github/actions/android-e2e/action.yaml create mode 100644 .github/actions/ios-e2e/action.yaml create mode 100644 .github/workflows/e2e-metro.yml diff --git a/.github/actions/android-e2e/action.yaml b/.github/actions/android-e2e/action.yaml new file mode 100644 index 00000000000..24c9978cb8d --- /dev/null +++ b/.github/actions/android-e2e/action.yaml @@ -0,0 +1,87 @@ +name: Android E2E Tests +description: 'Runs Android E2E tests' + +inputs: + app_name: + description: 'Name of the app to test' + required: true + github_token: + description: 'GitHub token for authentication' + required: true + +runs: + using: 'composite' + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: true + clean: true + + - name: Setup KVM (Required for Android Emulator) + 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 + shell: bash + + - uses: pnpm/action-setup@v3 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + shell: bash + + - name: Install Maestro CLI + run: | + curl -Ls "https://get.maestro.mobile.dev" | bash + echo "${HOME}/.maestro/bin" >> $GITHUB_PATH + shell: bash + + - name: Local RNEF Setup + shell: bash + run: | + RNEF_PATH="apps/${{ inputs.app_name }}/.rnef/cache" + mkdir -p $RNEF_PATH + echo "{\"githubToken\": \"${{ inputs.github_token }}\"}" > "$RNEF_PATH/project.json" + + - name: E2E Prepare Script + run: | + pnpm --filter ${{ inputs.app_name }} e2e:prepare:android + # Serve mini apps in the background + pnpm --filter ${{ inputs.app_name }} e2e:serve:android & + shell: bash + + - uses: callstackincubator/android@v1 + with: + github-token: ${{ inputs.github_token }} + variant: 'Release' + working-directory: './apps/${{ inputs.app_name}}' + + - name: Run Android E2E Tests + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ env.ANDROID_EMULATOR_API_LEVEL }} + target: ${{ env.ANDROID_EMULATOR_TARGET }} + arch: ${{ env.ANDROID_EMULATOR_ARCH }} + disk-size: ${{ env.ANDROID_EMULATOR_DISK_SPACE }} + emulator-boot-timeout: ${{ env.ANDROID_EMULATOR_BOOT_TIMEOUT }} + force-avd-creation: false + disable-animations: true + emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + script: | + pnpm --filter ${{ inputs.app_name }} android:release + pnpm --filter ${{ inputs.app_name }} adbreverse + pnpm --filter ${{ inputs.app_name }} e2e:run:android + + - name: Upload Maestro Logs on Failure + if: failure() # Runs only if any of the previous steps fail + uses: actions/upload-artifact@v4 + with: + name: maestro-logs-android-${{ inputs.app_name }} + path: ~/.maestro/tests/ diff --git a/.github/actions/ios-e2e/action.yaml b/.github/actions/ios-e2e/action.yaml new file mode 100644 index 00000000000..3810ad4a445 --- /dev/null +++ b/.github/actions/ios-e2e/action.yaml @@ -0,0 +1,79 @@ +name: iOS E2E Tests +description: 'Runs iOS E2E tests' + +inputs: + app_name: + description: 'Name of the app to test' + required: true + github_token: + description: 'GitHub token for authentication' + required: true + +runs: + using: 'composite' + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: true + clean: true + + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ env.RUBY_VERSION }} + + - uses: pnpm/action-setup@v3 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + shell: bash + + - name: Install Maestro CLI and iOS Utilities + run: | + curl -Ls "https://get.maestro.mobile.dev" | bash + brew tap facebook/fb + brew install facebook/fb/idb-companion + echo "${HOME}/.maestro/bin" >> $GITHUB_PATH + shell: bash + + - name: Local RNEF Setup + shell: bash + run: | + RNEF_PATH="apps/${{ inputs.app_name }}/.rnef/cache" + mkdir -p $RNEF_PATH + echo "{\"githubToken\": \"${{ inputs.github_token }}\"}" > "$RNEF_PATH/project.json" + + - uses: callstackincubator/ios@v1 + with: + github-token: ${{ inputs.github_token }} + destination: 'simulator' + scheme: 'MFExampleHost' + configuration: 'Release' + working-directory: './apps/${{ inputs.app_name}}' + + - name: E2E Prepare Script + shell: bash + run: | + pnpm --filter ${{ inputs.app_name }} e2e:prepare:ios + # Serve mini apps in the background + pnpm --filter ${{ inputs.app_name }} e2e:serve:ios & + + - name: Run iOS E2E Tests + run: | + pnpm --filter ${{ inputs.app_name }} ios:release + pnpm --filter ${{ inputs.app_name }} e2e:run:ios + shell: bash + + - name: Upload Maestro Logs on Failure + if: failure() # Runs only if any of the previous steps fail + uses: actions/upload-artifact@v4 + with: + name: maestro-logs-ios-${{ inputs.app_name }} + path: ~/.maestro/tests/ diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 6c82f98d9c8..d6d4aabfb14 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -141,6 +141,11 @@ jobs: uses: ./.github/workflows/e2e-router.yml secrets: inherit + e2e-metro: + needs: checkout-install + uses: ./.github/workflows/e2e-metro.yml + secrets: inherit + build-metro: needs: checkout-install uses: ./.github/workflows/build-metro.yml diff --git a/.github/workflows/e2e-metro.yml b/.github/workflows/e2e-metro.yml new file mode 100644 index 00000000000..0341e86f4b1 --- /dev/null +++ b/.github/workflows/e2e-metro.yml @@ -0,0 +1,59 @@ +name: Trigger E2E Tests + +on: + workflow_call: + +permissions: + actions: read + contents: read + checks: write + pull-requests: write + id-token: write + +concurrency: + group: e2e-tests-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + e2e-matrix-android: + runs-on: ubuntu-latest + timeout-minutes: 60 + strategy: + matrix: + app_name: [example-host] + env: + ANDROID_EMULATOR_API_LEVEL: 28 + ANDROID_EMULATOR_TARGET: default + ANDROID_EMULATOR_ARCH: x86_64 + ANDROID_EMULATOR_DISK_SPACE: 1024M + ANDROID_EMULATOR_RAM_SIZE: 256M + ANDROID_EMULATOR_HEAP_SIZE: 256M + ANDROID_EMULATOR_BOOT_TIMEOUT: 2700 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Android E2E Tests + uses: ./.github/actions/android-e2e + with: + app_name: ${{ matrix.app_name }} + github_token: ${{ secrets.GITHUB_TOKEN }} + e2e-matrix-ios: + runs-on: macos-latest + timeout-minutes: 60 + strategy: + matrix: + app_name: [example-host] + env: + RUBY_VERSION: 2.7.6 + MAESTRO_VERSION: 1.39.13 + MAESTRO_DRIVER_STARTUP_TIMEOUT: 360000 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: iOS E2E Tests + uses: ./.github/actions/ios-e2e + with: + app_name: ${{ matrix.app_name }} + github_token: ${{ secrets.GITHUB_TOKEN }}