Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8054905
feat(e2e-latest): add mobile-devtools plugin and enable New Arch
abueide May 7, 2026
c756500
feat(examples): add mobile-devtools plugin to all examples
abueide May 7, 2026
26c1e5c
feat(ci): add mobile E2E workflow triggered on PR branch
abueide May 7, 2026
e95241f
fix(ci): resolve E2E workflow failures
abueide May 8, 2026
cf200f9
fix(ci): resolve all E2E build failures
abueide May 8, 2026
f8ab21c
fix(e2e): resolve E2E-compat build failures with Nix SDK
abueide May 8, 2026
91e958b
ci(e2e): disable E2E-latest jobs until fixes land separately
abueide May 8, 2026
52195fd
fix(ci): enable corepack before root yarn install
abueide May 8, 2026
0e40601
fix(ci): use --pure mode for all devbox steps
abueide May 8, 2026
255479f
fix(ci): use segkit doctor --fix for iOS deps
abueide May 8, 2026
3393a68
fix(ci): use nix run for segkit doctor outside devbox
abueide May 8, 2026
5c52605
fix(ci): use devbox-provided segkit for doctor
abueide May 8, 2026
3a2f15a
fix(ci): add || true to segkit doctor --fix for resilience
abueide May 8, 2026
fea64c7
fix(ci): each E2E job targets one device set, add headless + caching
abueide May 8, 2026
b5f96d6
refactor(e2e-latest): remove New Architecture changes from devbox PR
abueide May 8, 2026
c5e067d
chore(ios): standardize min device on iPhone 16 / iOS 18.5
abueide May 8, 2026
d22d8a7
chore(examples): single device per example, remove unused definitions
abueide May 8, 2026
f79d5bc
feat(android): read minSdkVersion from ANDROID_MIN_SDK env var
abueide May 8, 2026
83a0d7b
fix(android): add ANDROID_COMPILE_SDK to E2E-compat android.lock
abueide May 9, 2026
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
330 changes: 330 additions & 0 deletions .github/workflows/e2e-mobile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,330 @@
name: Mobile E2E Tests

on:
push:
branches: [feat/devbox-e2e-latest]
workflow_dispatch:
inputs:
example:
description: 'Example to test (E2E-latest, E2E-compat, or all)'
type: choice
options: [all, E2E-latest, E2E-compat]
default: all

concurrency:
group: e2e-mobile-${{ github.ref }}
cancel-in-progress: true

jobs:
android-e2e-compat:
name: Android E2E (RN 0.72 + Old Arch, API 24)
runs-on: ubuntu-24.04
timeout-minutes: 45
defaults:
run:
working-directory: examples/E2E-compat
env:
ANDROID_DEVICES: min
ANDROID_DEFAULT_DEVICE: min
steps:
- uses: actions/checkout@v4

- 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

- name: Free disk space
run: |
sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc \
/usr/local/share/powershell /usr/local/share/chromium \
/usr/local/share/boost /opt/hostedtoolcache
sudo apt-get clean
df -h /

- name: Setup Gradle cache
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-compat-${{ hashFiles('examples/E2E-compat/android/gradle/wrapper/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-compat-

- name: Install Devbox
uses: jetify-com/devbox-install-action@v0.14.0
with:
enable-cache: true
project-path: examples/E2E-compat

- name: Install root dependencies
working-directory: .
run: devbox run --pure -- yarn install --no-immutable

- name: Install dependencies
run: devbox run --pure -- yarn install --no-immutable

- name: Build Android (release)
run: devbox run --pure build:android

- name: Start emulator
run: devbox run --pure -e EMU_HEADLESS=1 start:emu min

- name: Run Detox tests
run: devbox run --pure -- yarn detox test --configuration android.emu.release
continue-on-error: true

- name: Stop emulator
if: always()
run: devbox run --pure stop:emu || true

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-compat-android-results
path: examples/E2E-compat/artifacts/
if-no-files-found: ignore

android-e2e-latest:
if: false # Disabled until E2E-latest fixes land in separate PR
name: Android E2E (RN 0.84 + New Arch, API 36)
runs-on: ubuntu-24.04
timeout-minutes: 45
defaults:
run:
working-directory: examples/E2E-latest
env:
ANDROID_DEVICES: max
ANDROID_DEFAULT_DEVICE: max
steps:
- uses: actions/checkout@v4

- 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

- name: Free disk space
run: |
sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc \
/usr/local/share/powershell /usr/local/share/chromium \
/usr/local/share/boost /opt/hostedtoolcache
sudo apt-get clean
df -h /

- name: Setup Gradle cache
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-latest-${{ hashFiles('examples/E2E-latest/android/gradle/wrapper/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-latest-

- name: Install Devbox
uses: jetify-com/devbox-install-action@v0.14.0
with:
enable-cache: true
project-path: examples/E2E-latest

- name: Install root dependencies
working-directory: .
run: devbox run --pure -- yarn install --no-immutable

- name: Install dependencies
run: devbox run --pure -- yarn install --no-immutable

- name: Build Android (release)
run: devbox run --pure build:android

- name: Start emulator
run: devbox run --pure -e EMU_HEADLESS=1 start:emu max

- name: Run Detox tests
run: devbox run --pure -- yarn detox test --configuration android.emu.release
continue-on-error: true

- name: Stop emulator
if: always()
run: devbox run --pure stop:emu || true

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-latest-android-results
path: examples/E2E-latest/artifacts/
if-no-files-found: ignore

ios-e2e-compat:
name: iOS E2E (RN 0.72 + Old Arch, iOS 18.5)
runs-on: macos-15
timeout-minutes: 45
defaults:
run:
working-directory: examples/E2E-compat
env:
IOS_DEVICES: min
IOS_DEFAULT_DEVICE: min
IOS_DOWNLOAD_RUNTIME: '0'
steps:
- uses: actions/checkout@v4

- name: Select Xcode
run: |
XCODE_APP=$(ls -d /Applications/Xcode_16*.app 2>/dev/null | sort -V | tail -1)
if [ -z "$XCODE_APP" ]; then
XCODE_APP="/Applications/Xcode.app"
fi
echo "Selecting: $XCODE_APP"
sudo xcode-select -s "$XCODE_APP/Contents/Developer"
xcodebuild -version
xcrun simctl list runtimes | grep -i ios

- name: Setup CocoaPods cache
uses: actions/cache@v4
with:
path: |
~/.cocoapods/repos
~/Library/Caches/CocoaPods
key: ${{ runner.os }}-pods-compat-${{ hashFiles('examples/E2E-compat/ios/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-compat-

- name: Install Devbox
uses: jetify-com/devbox-install-action@v0.14.0
with:
enable-cache: true
project-path: examples/E2E-compat

- name: Install iOS dependencies
run: devbox run --pure -- segkit doctor --fix || true

- name: Install root dependencies
working-directory: .
run: devbox run --pure -- yarn install --no-immutable

- name: Install dependencies
run: devbox run --pure -- yarn install --no-immutable

- name: Install pods
run: devbox run --pure install:pods

- name: Build iOS (release)
run: devbox run --pure build:ios

- name: Start simulator
run: devbox run --pure -e SIM_HEADLESS=1 start:sim min

- name: Run Detox tests
run: devbox run --pure -- yarn detox test --configuration ios.sim.release
continue-on-error: true

- name: Stop simulator
if: always()
run: devbox run --pure stop:sim || true

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-compat-ios-results
path: examples/E2E-compat/artifacts/
if-no-files-found: ignore

ios-e2e-latest:
if: false # Disabled until E2E-latest fixes land in separate PR
name: iOS E2E (RN 0.84 + New Arch, iOS 26.2)
runs-on: macos-26
timeout-minutes: 45
defaults:
run:
working-directory: examples/E2E-latest
env:
IOS_DEVICES: max
IOS_DEFAULT_DEVICE: max
IOS_DOWNLOAD_RUNTIME: '0'
steps:
- uses: actions/checkout@v4

- name: Select Xcode
run: |
XCODE_APP=$(ls -d /Applications/Xcode_26*.app 2>/dev/null | sort -V | tail -1)
if [ -z "$XCODE_APP" ]; then
XCODE_APP="/Applications/Xcode.app"
fi
echo "Selecting: $XCODE_APP"
sudo xcode-select -s "$XCODE_APP/Contents/Developer"
xcodebuild -version
xcrun simctl list runtimes | grep -i ios

- name: Setup CocoaPods cache
uses: actions/cache@v4
with:
path: |
~/.cocoapods/repos
~/Library/Caches/CocoaPods
key: ${{ runner.os }}-pods-latest-${{ hashFiles('examples/E2E-latest/ios/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-latest-

- name: Install Devbox
uses: jetify-com/devbox-install-action@v0.14.0
with:
enable-cache: true
project-path: examples/E2E-latest

- name: Install iOS dependencies
run: devbox run --pure -- segkit doctor --fix || true

- name: Install root dependencies
working-directory: .
run: devbox run --pure -- yarn install --no-immutable

- name: Install dependencies
run: devbox run --pure -- yarn install --no-immutable

- name: Install pods
run: devbox run --pure install:pods

- name: Build iOS (release)
run: devbox run --pure build:ios

- name: Start simulator
run: devbox run --pure -e SIM_HEADLESS=1 start:sim max

- name: Run Detox tests
run: devbox run --pure -- yarn detox test --configuration ios.sim.release
continue-on-error: true

- name: Stop simulator
if: always()
run: devbox run --pure stop:sim || true

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-latest-ios-results
path: examples/E2E-latest/artifacts/
if-no-files-found: ignore

summary:
name: E2E Summary
runs-on: ubuntu-latest
needs: [android-e2e-compat, ios-e2e-compat]
if: always()
steps:
- name: Report results
run: |
echo "## Mobile E2E Test Results"
echo ""
echo "| Example | Platform | Result |"
echo "|---------|----------|--------|"
echo "| E2E-compat (RN 0.72, Old Arch) | Android (API 24) | ${{ needs.android-e2e-compat.result }} |"
echo "| E2E-compat (RN 0.72, Old Arch) | iOS (18.5) | ${{ needs.ios-e2e-compat.result }} |"
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,7 @@ AGENTS.md

# Notes and research (not for commit)
notes/

# Devbox
.devbox/
devbox.lock
17 changes: 12 additions & 5 deletions examples/AnalyticsReactNativeExample/android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
buildscript {
ext {
buildToolsVersion = "35.0.0"
def compileSdkEnv = System.getenv("ANDROID_COMPILE_SDK") ?: System.getenv("ANDROID_MAX_API") ?: "35"
def targetSdkEnv = System.getenv("ANDROID_TARGET_SDK") ?: System.getenv("ANDROID_MAX_API") ?: "35"
buildToolsVersion = System.getenv("ANDROID_BUILD_TOOLS_VERSION") ?: "35.0.0"
minSdkVersion = 24
compileSdkVersion = 35
targetSdkVersion = 34
ndkVersion = "26.1.10909125"
kotlinVersion = "1.9.24"
compileSdkVersion = compileSdkEnv.toInteger()
targetSdkVersion = targetSdkEnv.toInteger()
kotlinVersion = "2.1.20"
def ndkVersionEnv = System.getenv("ANDROID_NDK_VERSION")
if (ndkVersionEnv) {
ndkVersion = ndkVersionEnv
} else {
ndkVersion = "26.1.10909125"
}
}
repositories {
google()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"devices": [
{
"name": "medium_phone_api36",
"api": 36,
"device": "medium_phone",
"tag": "google_apis"
}
],
"checksum": "e1a32475f99e1b20d5f0a20076f5ccade1803a8fe88af3bbad56e3e89ba332b7"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "medium_phone_api36",
"api": 36,
"device": "medium_phone",
"tag": "google_apis"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"devices": [
{
"name": "iPhone 17",
"runtime": "26.2"
}
],
"checksum": "7d4b3ac2354a9fd80740d7f9ab5313b3e39fc87d59174e154e04c4996c332186"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "iPhone 17",
"runtime": "26.2"
}
Loading
Loading