From 7b2b16ae9ee99cfc4be15eb64e88b27e4a51519f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Kapu=C5=9Bciak?= Date: Thu, 12 Nov 2026 12:10:15 +0100 Subject: [PATCH 1/2] verify: the workflow e2e init writes for this project --- .github/workflows/e2e.yml | 84 +++++++++++++++++++++++---------------- e2e.config.ts | 2 +- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 53469b3..598c81f 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -1,3 +1,5 @@ +# Written by `e2e init --ci github-actions`: the e2e tests on every pull request +# and every push to main, one job per platform. See https://e2e.com/docs/ci/github-actions name: e2e on: @@ -14,8 +16,6 @@ concurrency: jobs: web: - # Fork pull requests get no secrets, so the agent steps can't call the model. - if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: ubuntu-latest timeout-minutes: 30 steps: @@ -24,7 +24,8 @@ jobs: with: node-version: 24 cache: npm - - run: npm ci + - name: Install dependencies + run: npm ci - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.cache/ms-playwright @@ -33,27 +34,28 @@ jobs: - name: Install browsers run: npx e2e-web install chromium --with-deps - # The web target starts Metro itself (app.command in e2e.config.ts). - name: Run e2e run: npx e2e run --target web --reporter list,junit env: AI_GATEWAY_API_KEY: ${{ secrets.AI_GATEWAY_API_KEY }} - - name: Upload report + - name: Upload the report if: ${{ !cancelled() }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: e2e-web - path: .e2e - if-no-files-found: warn - # .e2e is a hidden directory, which upload-artifact skips by default. + path: | + .e2e/report.json + .e2e/junit.xml + .e2e/results + # .e2e is a hidden directory, which upload-artifact skips when it expands a folder. include-hidden-files: true + if-no-files-found: warn retention-days: 7 ios: - if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: macos-26 - # The Release build alone takes about 35 minutes on this runner. + # A Release build for the simulator alone can take 35 minutes on this runner. timeout-minutes: 90 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -61,19 +63,20 @@ jobs: with: node-version: 24 cache: npm - - run: npm ci + - name: Install dependencies + run: npm ci - # ios/ is generated (CNG); expo run:ios prebuilds it, installs pods, and builds without a simulator. - - name: Build for the simulator + # Expo generates ios/ (CNG): expo run:ios prebuilds it, installs the pods, and builds without a simulator. + - name: Build the app run: npx expo run:ios --configuration Release --device generic --no-bundler --output build/ios - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.agent-device/apple-runner/derived key: agent-device-runner-${{ runner.os }}-${{ hashFiles('package-lock.json') }} - # Boots the image's own iPhone 17 Pro on the pinned runtime: a simulator made with - # `simctl create` spent over 7 minutes on its first boot. Bump the runtime on purpose, - # after a local run on it, since the accessibility tree changes between iOS releases. + # Boots the image's own iPhone 17 Pro on a pinned runtime: a simulator made with `simctl create` + # can spend minutes on its first boot. Bump the runtime on purpose, after a local run on it, + # since the accessibility tree changes between iOS releases. - name: Boot a simulator and install the app env: IOS_RUNTIME: com.apple.CoreSimulator.SimRuntime.iOS-26-5 @@ -87,29 +90,35 @@ jobs: fi xcrun simctl boot "$UDID" xcrun simctl bootstatus "$UDID" - APP=$(find build/ios -maxdepth 3 -name 'e2ereactnative.app' -type d | head -n 1) - test -n "$APP" - echo "Installing $APP" + APP=$(find build -maxdepth 5 -name '*.app' -type d | head -n 1) + if [ -z "$APP" ]; then + echo "::error::No .app under build/" + exit 1 + fi xcrun simctl install "$UDID" "$APP" - echo "E2E_IOS_DEVICE=$UDID" >> "$GITHUB_ENV" + # A target with device: process.env.E2E_DEVICE drives this simulator, whatever else the image has. + echo "E2E_DEVICE=$UDID" >> "$GITHUB_ENV" - name: Run e2e run: npx e2e run --target ios --workers 1 --reporter list,junit env: AI_GATEWAY_API_KEY: ${{ secrets.AI_GATEWAY_API_KEY }} - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + - name: Upload the report if: ${{ !cancelled() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: e2e-ios - path: .e2e - if-no-files-found: warn - # .e2e is a hidden directory, which upload-artifact skips by default. + path: | + .e2e/report.json + .e2e/junit.xml + .e2e/results + # .e2e is a hidden directory, which upload-artifact skips when it expands a folder. include-hidden-files: true + if-no-files-found: warn retention-days: 7 android: - if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} runs-on: ubuntu-latest timeout-minutes: 60 steps: @@ -122,7 +131,8 @@ jobs: with: distribution: temurin java-version: 17 - - run: npm ci + - name: Install dependencies + run: npm ci - name: Enable KVM run: | @@ -130,12 +140,12 @@ jobs: sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - # android/ is generated (CNG). The Expo template signs release builds with the debug keystore. - # Only the emulator's ABI: building all four takes about 25 minutes. - - name: Build the APK + # Expo generates android/ (CNG) and signs release builds with the debug keystore. + # Only the emulator's ABI: building all four takes about 25 minutes longer. + - name: Build the app run: | npx expo prebuild --platform android --no-install - cd android && ./gradlew :app:assembleRelease -PreactNativeArchitectures=x86_64 + (cd android && ./gradlew :app:assembleRelease -PreactNativeArchitectures=x86_64) # The emulator action downloads the system image once and fails the job when that download drops. - name: Install the emulator system image @@ -149,7 +159,7 @@ jobs: done exit 1 - - name: Run on an emulator + - name: Run e2e uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2.38.0 with: api-level: 36 @@ -164,12 +174,16 @@ jobs: env: AI_GATEWAY_API_KEY: ${{ secrets.AI_GATEWAY_API_KEY }} - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + - name: Upload the report if: ${{ !cancelled() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: e2e-android - path: .e2e - if-no-files-found: warn - # .e2e is a hidden directory, which upload-artifact skips by default. + path: | + .e2e/report.json + .e2e/junit.xml + .e2e/results + # .e2e is a hidden directory, which upload-artifact skips when it expands a folder. include-hidden-files: true + if-no-files-found: warn retention-days: 7 diff --git a/e2e.config.ts b/e2e.config.ts index 15a81a9..1467c10 100644 --- a/e2e.config.ts +++ b/e2e.config.ts @@ -25,7 +25,7 @@ export default { { name: 'ios', // CI passes the UDID of a simulator it created on a pinned iOS runtime. - engine: mobile({ platform: 'ios', device: process.env.E2E_IOS_DEVICE || 'iPhone 17 Pro' }), + engine: mobile({ platform: 'ios', device: process.env.E2E_DEVICE || 'iPhone 17 Pro' }), // A development build made with `npx expo run:ios`; Metro serves the JS bundle. app: { bundleId: 'dev.e2e.podcasts', From 0890eef492853a0f8df91f45534be4e901634cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Kapu=C5=9Bciak?= Date: Thu, 12 Nov 2026 14:20:54 +0100 Subject: [PATCH 2/2] verify: regenerate with the final template --- .github/workflows/e2e.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 598c81f..cf45603 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -148,13 +148,18 @@ jobs: (cd android && ./gradlew :app:assembleRelease -PreactNativeArchitectures=x86_64) # The emulator action downloads the system image once and fails the job when that download drops. + # sdkmanager can also report success for a package that holds no image, so the step checks for one. - name: Install the emulator system image run: | SDKMANAGER="$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" + IMAGE="$ANDROID_HOME/system-images/android-36/google_apis/x86_64" "$SDKMANAGER" --licenses < <(yes) > /dev/null for attempt in 1 2 3; do - "$SDKMANAGER" --install 'system-images;android-36;google_apis;x86_64' > /dev/null && exit 0 + if "$SDKMANAGER" --install 'system-images;android-36;google_apis;x86_64' > /dev/null && ls "$IMAGE"/*.img > /dev/null 2>&1; then + exit 0 + fi echo "Download attempt $attempt failed" + rm -rf "$IMAGE" sleep 30 done exit 1 @@ -173,6 +178,8 @@ jobs: npx e2e run --target android --workers 1 --reporter list,junit env: AI_GATEWAY_API_KEY: ${{ secrets.AI_GATEWAY_API_KEY }} + # The emulator the action boots, for a target with device: process.env.E2E_DEVICE. + E2E_DEVICE: emulator-5554 - name: Upload the report if: ${{ !cancelled() }}