diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6ca43a7..d19e1fe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,79 +7,146 @@ on: branches: [main] jobs: - android: - name: Build Android App - runs-on: ubuntu-latest + ios-build: + name: iOS Build + runs-on: macos-latest + defaults: + run: + working-directory: example env: SKIP_YARN_COREPACK_CHECK: 0 steps: - - uses: actions/checkout@v4 - - - name: Setup Java - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: '17' + - name: Checkout repository + uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 'lts/*' + node-version: '22' cache: 'yarn' + cache-dependency-path: example/yarn.lock + + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' + bundler-cache: true + + - name: Cache CocoaPods + uses: actions/cache@v4 + with: + path: | + example/swift/Pods + key: ${{ runner.os }}-pods-${{ hashFiles('example/swift/Podfile.lock') }} + restore-keys: | + ${{ runner.os }}-pods- - name: Install root dependencies run: yarn install - name: Install example dependencies + run: yarn install + + - name: Install pods run: | - cd example - yarn install - cd .. + cd swift + pod install - - name: Build Android App + - name: Install Maestro CLI run: | - cd example/kotlin - ./gradlew assembleDebug + curl -Ls "https://get.maestro.mobile.dev" | bash + brew tap facebook/fb + brew install facebook/fb/idb-companion - ios: - name: Build iOS App - runs-on: macos-latest + - name: Add Maestro to path + run: echo "${HOME}/.maestro/bin" >> $GITHUB_PATH + + - name: Start packager + run: yarn start & + + - name: Build iOS App (Release) + run: | + cd swift + xcodebuild -workspace SwiftExample.xcworkspace -scheme SwiftExample -configuration Release -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 15' build CODE_SIGNING_ALLOWED=NO + + - name: Setup iOS simulator + run: | + UDID=$(xcrun simctl list devices | grep "iPhone" | grep "Booted" | head -1 | grep -E -o -i "([0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})") + if [ -z "$UDID" ]; then + UDID=$(xcrun simctl list devices available | grep "iPhone" | head -1 | grep -E -o -i "([0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})") + xcrun simctl boot "${UDID}" + fi + open -a Simulator + xcrun simctl launch "${UDID}" com.callstack.reactnativebrownfield.SwiftExample + + - name: Run iOS tests + run: | + export MAESTRO_DRIVER_STARTUP_TIMEOUT=1500000 + export MAESTRO_WAIT_TIMEOUT=10000 + yarn test:e2e:ios + + android-build: + name: Android Build + runs-on: ubuntu-latest + defaults: + run: + working-directory: example env: SKIP_YARN_COREPACK_CHECK: 0 steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: 'lts/*' + node-version: '22' cache: 'yarn' + cache-dependency-path: example/yarn.lock - - name: Setup Ruby - uses: ruby/setup-ruby@v1 + - name: Setup Java + uses: actions/setup-java@v4 with: - ruby-version: '3.2' - bundler-cache: true + distribution: 'zulu' + java-version: '17' - name: Install root dependencies run: yarn install - name: Install example dependencies - run: | - cd example - yarn install - cd .. + run: yarn install - - name: Install pods - run: | - cd example/swift - pod install + - name: Start packager + run: yarn start & - - name: Build iOS App + - name: Install Maestro CLI run: | - cd example/swift - xcodebuild -workspace SwiftExample.xcworkspace -scheme SwiftExample -configuration Debug -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 15' build CODE_SIGNING_ALLOWED=NO \ No newline at end of file + curl -Ls "https://get.maestro.mobile.dev" | bash + + - name: Add Maestro to path + run: echo "${HOME}/.maestro/bin" >> $GITHUB_PATH + + - name: Create AVD and generate snapshot for caching + uses: reactivecircus/android-emulator-runner@v2 + with: + target: aosp_atd + api-level: 30 + arch: x86 + ram-size: 4096M + channel: canary + profile: pixel + avd-name: Pixel_3a_API_30_AOSP + force-avd-creation: false + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + emulator-boot-timeout: 12000 + disable-animations: false + working-directory: example/kotlin + script: | + chmod +x ./gradlew + ./gradlew :app:installRelease + cd .. + yarn test:e2e:android \ No newline at end of file diff --git a/example/kotlin/app/src/main/java/com/callstack/kotlinexample/MainActivity.kt b/example/kotlin/app/src/main/java/com/callstack/kotlinexample/MainActivity.kt index 0ffe9cc..f5632c0 100644 --- a/example/kotlin/app/src/main/java/com/callstack/kotlinexample/MainActivity.kt +++ b/example/kotlin/app/src/main/java/com/callstack/kotlinexample/MainActivity.kt @@ -84,7 +84,7 @@ fun HomeScreen( verticalArrangement = Arrangement.Center ) { Text( - "React Native Brownfield Example", + "React Native Brownfield", fontSize = 30.sp, modifier = Modifier.padding(15.dp), textAlign = TextAlign.Center diff --git a/example/maestro-tests/android_test.yml b/example/maestro-tests/android_test.yml new file mode 100644 index 0000000..55fd25c --- /dev/null +++ b/example/maestro-tests/android_test.yml @@ -0,0 +1,37 @@ +appId: com.callstack.kotlinexample + +--- +- launchApp +- assertVisible: "React Native Brownfield" +- tapOn: "Navigate to React Native Fragment with Compose" + +- assertVisible: "React Native Screen" + +- tapOn: "Push next screen" + +- assertVisible: "React Native Screen" + +- tapOn: "Go back" + +- assertVisible: "React Native Screen" + +- tapOn: "Go back" + +- assertVisible: "React Native Brownfield" + +- tapOn: "Navigate to React Native Fragment Activity" + +- assertVisible: "React Native Screen" + +- tapOn: "Push next screen" + +- assertVisible: "React Native Screen" + +- tapOn: "Go back" + +- assertVisible: "React Native Screen" + +- tapOn: "Go back" + +- assertVisible: "React Native Brownfield" + diff --git a/example/maestro-tests/ios_test.yml b/example/maestro-tests/ios_test.yml new file mode 100644 index 0000000..1a54058 --- /dev/null +++ b/example/maestro-tests/ios_test.yml @@ -0,0 +1,21 @@ +appId: com.callstack.reactnativebrownfield.SwiftExample + +--- +- launchApp + +- assertVisible: "React Native Brownfield" +- tapOn: "Push React Native screen" + +- assertVisible: "React Native Screen" + +- tapOn: "Push next screen" + +- assertVisible: "React Native Screen" + +- tapOn: "Go back" + +- assertVisible: "React Native Screen" + +- tapOn: "Go back" + +- assertVisible: "React Native Brownfield" diff --git a/example/package.json b/example/package.json index ae93ed1..0a0ced8 100644 --- a/example/package.json +++ b/example/package.json @@ -5,7 +5,9 @@ "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", - "start": "react-native start" + "start": "react-native start", + "test:e2e:ios": "maestro test ./maestro-tests/ios_test.yml", + "test:e2e:android": "maestro test ./maestro-tests/android_test.yml" }, "dependencies": { "react": "19.0.0", diff --git a/example/swift/App.swift b/example/swift/App.swift index 2638d42..f9ca460 100644 --- a/example/swift/App.swift +++ b/example/swift/App.swift @@ -20,7 +20,7 @@ struct ContentView: View { var body: some View { NavigationView { VStack { - Text("React Native Brownfield App") + Text("React Native Brownfield") .font(.title) .bold() .padding()