diff --git a/.github/scripts/run-nightly-e2e.sh b/.github/scripts/run-nightly-e2e.sh index dbd49d39d0..df387ef24c 100755 --- a/.github/scripts/run-nightly-e2e.sh +++ b/.github/scripts/run-nightly-e2e.sh @@ -144,16 +144,27 @@ fi phase "Building and installing the development client" if [[ "$platform" == "ios" ]]; then + # Passing --device makes this Expo version merge simulator and devicectl + # results. On Xcode 26.4, devicectl can misclassify the simulator as a + # physical device and incorrectly require signing. Exactly one simulator is + # booted above, so Expo's default simulator-only resolver selects it. + echo "Building for already booted iOS simulator $device_id" EXPO_PUBLIC_ENV=e2e \ NODE_ENV=test \ RN_SRC_EXT=e2e.ts,e2e.tsx \ - pnpm exec expo run:ios --device "$device_id" --no-bundler \ + pnpm exec expo run:ios --no-bundler \ 2>&1 | tee "$artifact_dir/build.log" else + expo_device_name="$(adb -s "$device_id" emu avd name | sed -n '1p' | tr -d '\r')" + if [[ -z "$expo_device_name" ]]; then + echo "Could not resolve the AVD name for $device_id" >&2 + exit 1 + fi + echo "Building for Android AVD $expo_device_name ($device_id)" EXPO_PUBLIC_ENV=e2e \ NODE_ENV=test \ RN_SRC_EXT=e2e.ts,e2e.tsx \ - pnpm exec expo run:android --device "$device_id" --no-bundler \ + pnpm exec expo run:android --device "$expo_device_name" --no-bundler \ 2>&1 | tee "$artifact_dir/build.log" fi diff --git a/.github/workflows/nightly-e2e.yml b/.github/workflows/nightly-e2e.yml index 0deb92b622..182337df02 100644 --- a/.github/workflows/nightly-e2e.yml +++ b/.github/workflows/nightly-e2e.yml @@ -82,17 +82,40 @@ jobs: - name: Boot one iOS simulator run: | echo "Booting iOS simulator" > artifacts/ios/phase.txt - udid=$(xcrun simctl list devices available --json | jq -r \ - '[.devices[][] | select(.name | startswith("iPhone"))] | first | .udid') - if [ -z "$udid" ] || [ "$udid" = "null" ]; then - echo "No available iPhone simulator was found" >&2 + device_name="iPhone 17" + runtime_name="iOS 26.5" + + runtime_id=$(xcrun simctl list runtimes available --json | jq -r \ + --arg name "$runtime_name" \ + '[.runtimes[] | select(.name == $name and .isAvailable != false)] | first | .identifier // empty') + if [ -z "$runtime_id" ]; then + echo "The $runtime_name simulator runtime is not installed. Available iOS runtimes:" >&2 + xcrun simctl list runtimes available --json | jq -r \ + '.runtimes[] | select(.name | startswith("iOS")) | "- \(.name)"' >&2 exit 1 fi + + device_type_id=$(xcrun simctl list devicetypes --json | jq -r \ + --arg name "$device_name" \ + '[.devicetypes[] | select(.name == $name)] | first | .identifier // empty') + if [ -z "$device_type_id" ]; then + echo "The $device_name simulator device type is not installed" >&2 + exit 1 + fi + + udid=$(xcrun simctl list devices available --json | jq -r \ + --arg runtime "$runtime_id" \ + --arg name "$device_name" \ + '[.devices[$runtime][]? | select(.name == $name)] | first | .udid // empty') + if [ -z "$udid" ]; then + udid=$(xcrun simctl create "$device_name" "$device_type_id" "$runtime_id") + fi + echo "IOS_UDID=$udid" >> "$GITHUB_ENV" xcrun simctl shutdown all || true xcrun simctl boot "$udid" xcrun simctl bootstatus "$udid" -b - echo "Using iOS simulator $udid" + echo "Using $device_name on $runtime_name ($udid)" - name: Run iOS Maestro suite run: .github/scripts/run-nightly-e2e.sh ios "$IOS_UDID" diff --git a/docs/testing.md b/docs/testing.md index 9bde1e18e0..d265255220 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -40,7 +40,8 @@ stateful mock-server manager, so the suite must not be sharded. The jobs run Maestro CLI 2.6.1 locally on GitHub Actions; Maestro Cloud is not used. iOS runs on `macos-26-xlarge` with Xcode 26.4. Android runs on `Linux-x64-32core`. Both use Java 17 and the Node and pnpm versions declared in -`package.json`. +`package.json`. The iOS job selects an iPhone 17 simulator running iOS 26.5; +Android uses a Pixel 6 AVD with the API 35 Google APIs x86_64 image. The mock-server manager listens on host port 1986 and creates test services on port 3000. Metro listens on 8081. Android reverses ports 3000 and 8081 into the