Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 123 additions & 109 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,112 +50,126 @@ jobs:
include-hidden-files: true
retention-days: 7

# ios:
# if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
# runs-on: macos-26
# timeout-minutes: 60
# steps:
# - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
# with:
# node-version: 24
# cache: npm
# - run: npm ci

# # ios/ is generated (CNG); expo run:ios prebuilds it, installs pods, and builds without a simulator.
# - name: Build for the simulator
# 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') }}

# - name: Boot a simulator and install the app
# run: |
# UDID=$(xcrun simctl create e2e "iPhone 17 Pro" com.apple.CoreSimulator.SimRuntime.iOS-26-5)
# xcrun simctl bootstatus "$UDID" -b
# APP=$(find build/ios -maxdepth 3 -name 'e2ereactnative.app' -type d | head -n 1)
# echo "Installing $APP"
# xcrun simctl install "$UDID" "$APP"
# echo "E2E_IOS_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
# if: ${{ !cancelled() }}
# with:
# name: e2e-ios
# path: .e2e
# if-no-files-found: warn
# # .e2e is a hidden directory, which upload-artifact skips by default.
# include-hidden-files: true
# 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:
# - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
# with:
# node-version: 24
# cache: npm
# - uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0
# with:
# distribution: temurin
# java-version: 17
# - run: npm ci

# - 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

# # 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
# run: |
# npx expo prebuild --platform android --no-install
# 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
# run: |
# SDKMANAGER="$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager"
# "$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
# echo "Download attempt $attempt failed"
# sleep 30
# done
# exit 1

# - name: Run on an emulator
# uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2.38.0
# with:
# api-level: 36
# arch: x86_64
# target: google_apis
# profile: pixel_7
# emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim
# disable-animations: true
# script: |
# adb install -r android/app/build/outputs/apk/release/app-release.apk
# npx e2e run --target android --workers 1 --reporter list,junit
# env:
# AI_GATEWAY_API_KEY: ${{ secrets.AI_GATEWAY_API_KEY }}

# - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
# if: ${{ !cancelled() }}
# with:
# name: e2e-android
# path: .e2e
# if-no-files-found: warn
# # .e2e is a hidden directory, which upload-artifact skips by default.
# include-hidden-files: true
# 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.
timeout-minutes: 90
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: npm
- run: npm ci

# ios/ is generated (CNG); expo run:ios prebuilds it, installs pods, and builds without a simulator.
- name: Build for the simulator
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.
- name: Boot a simulator and install the app
env:
IOS_RUNTIME: com.apple.CoreSimulator.SimRuntime.iOS-26-5
run: |
set -euo pipefail
UDID=$(xcrun simctl list devices available -j | jq -r --arg rt "$IOS_RUNTIME" '.devices[$rt][]? | select(.name == "iPhone 17 Pro") | .udid' | head -n 1)
if [ -z "$UDID" ]; then
echo "::error::No iPhone 17 Pro on $IOS_RUNTIME"
xcrun simctl list runtimes
exit 1
fi
xcrun simctl boot "$UDID"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This unconditionally boots the selected simulator, so the job fails if the runner image already has its iPhone 17 Pro booted. Replace it with xcrun simctl bootstatus "$UDID" -b, which handles both shutdown and booted states while waiting for readiness.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At .github/workflows/e2e.yml, line 88:

<comment>This unconditionally boots the selected simulator, so the job fails if the runner image already has its iPhone 17 Pro booted. Replace it with `xcrun simctl bootstatus "$UDID" -b`, which handles both shutdown and booted states while waiting for readiness.</comment>

<file context>
@@ -50,112 +50,126 @@ jobs:
+            xcrun simctl list runtimes
+            exit 1
+          fi
+          xcrun simctl boot "$UDID"
+          xcrun simctl bootstatus "$UDID"
+          APP=$(find build/ios -maxdepth 3 -name 'e2ereactnative.app' -type d | head -n 1)
</file context>
Suggested change
xcrun simctl boot "$UDID"
xcrun simctl bootstatus "$UDID" -b

xcrun simctl bootstatus "$UDID"
APP=$(find build/ios -maxdepth 3 -name 'e2ereactnative.app' -type d | head -n 1)
test -n "$APP"
echo "Installing $APP"
xcrun simctl install "$UDID" "$APP"
echo "E2E_IOS_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
if: ${{ !cancelled() }}
with:
name: e2e-ios
path: .e2e
if-no-files-found: warn
# .e2e is a hidden directory, which upload-artifact skips by default.
include-hidden-files: true
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:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: npm
- uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0
with:
distribution: temurin
java-version: 17
- run: npm ci

- 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

# 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
run: |
npx expo prebuild --platform android --no-install
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
run: |
SDKMANAGER="$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager"
"$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
echo "Download attempt $attempt failed"
sleep 30
done
exit 1

- name: Run on an emulator
uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2.38.0
with:
api-level: 36
arch: x86_64
target: google_apis
profile: pixel_7
emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim
disable-animations: true
script: |
adb install -r android/app/build/outputs/apk/release/app-release.apk
npx e2e run --target android --workers 1 --reporter list,junit
env:
AI_GATEWAY_API_KEY: ${{ secrets.AI_GATEWAY_API_KEY }}

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
name: e2e-android
path: .e2e
if-no-files-found: warn
# .e2e is a hidden directory, which upload-artifact skips by default.
include-hidden-files: true
retention-days: 7
Loading