|
26 | 26 | e2e_web_sdk_react: ${{ steps.filter.outputs.e2e_web_sdk_react }} |
27 | 27 | e2e_react_web_sdk: ${{ steps.filter.outputs.e2e_react_web_sdk }} |
28 | 28 | e2e_react_native_android: ${{ steps.filter.outputs.e2e_react_native_android }} |
| 29 | + e2e_ios: ${{ steps.filter.outputs.e2e_ios }} |
29 | 30 | steps: |
30 | 31 | - uses: namespacelabs/nscloud-checkout-action@938f5d2d403d6224d9a0c0dc559b1dae09c2ede4 # v8.1.1 |
31 | 32 |
|
@@ -125,6 +126,14 @@ jobs: |
125 | 126 | - 'package.json' |
126 | 127 | - 'pnpm-lock.yaml' |
127 | 128 | - '.github/workflows/main-pipeline.yaml' |
| 129 | + # iOS native implementation E2E coverage scope. |
| 130 | + e2e_ios: |
| 131 | + - 'implementations/ios-sdk/**' |
| 132 | + - 'lib/mocks/**' |
| 133 | + - 'packages/ios/**' |
| 134 | + - 'package.json' |
| 135 | + - 'pnpm-lock.yaml' |
| 136 | + - '.github/workflows/main-pipeline.yaml' |
128 | 137 |
|
129 | 138 | setup: |
130 | 139 | name: 🛠️ pnpm install |
@@ -650,6 +659,57 @@ jobs: |
650 | 659 | if-no-files-found: error |
651 | 660 | retention-days: 1 |
652 | 661 |
|
| 662 | + e2e-ios-sdk-build: |
| 663 | + name: 🍎 Build iOS UI Test Bundles |
| 664 | + runs-on: namespace-profile-macos-apple-silicon-arm64-6-cpu-14-gb |
| 665 | + timeout-minutes: 30 |
| 666 | + needs: [setup, changes] |
| 667 | + if: needs.changes.outputs.e2e_ios == 'true' |
| 668 | + env: |
| 669 | + DERIVED_DATA: /tmp/optimization-ios-derived-data |
| 670 | + steps: |
| 671 | + - uses: namespacelabs/nscloud-checkout-action@938f5d2d403d6224d9a0c0dc559b1dae09c2ede4 # v8.1.1 |
| 672 | + |
| 673 | + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 |
| 674 | + with: |
| 675 | + node-version-file: '.nvmrc' |
| 676 | + package-manager-cache: false |
| 677 | + |
| 678 | + - uses: pnpm/action-setup@903f9c1a6ebcba6cf41d87230be49611ac97822e # v6.0.3 |
| 679 | + |
| 680 | + - name: Install XcodeGen and xcbeautify |
| 681 | + run: brew install xcodegen xcbeautify |
| 682 | + |
| 683 | + - name: Set up caches (Namespace) |
| 684 | + uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3 |
| 685 | + with: |
| 686 | + cache: pnpm |
| 687 | + path: | |
| 688 | + ~/Library/Caches/org.swift.swiftpm |
| 689 | +
|
| 690 | + - name: Show toolchain |
| 691 | + run: | |
| 692 | + xcodebuild -version |
| 693 | + xcrun simctl list runtimes | head |
| 694 | +
|
| 695 | + - run: pnpm install --prefer-offline --frozen-lockfile |
| 696 | + |
| 697 | + - name: Build iOS UI test bundles (SwiftUI + UIKit) |
| 698 | + run: pnpm run implementation:ios-sdk -- test:e2e:ios:build:release |
| 699 | + |
| 700 | + - name: Stage Build/Products for artifact |
| 701 | + run: | |
| 702 | + mkdir -p /tmp/ios-artifact |
| 703 | + cp -R "$DERIVED_DATA/Build/Products" /tmp/ios-artifact/Products |
| 704 | + ls /tmp/ios-artifact/Products/*.xctestrun |
| 705 | +
|
| 706 | + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 |
| 707 | + with: |
| 708 | + name: ios-uitest-bundles |
| 709 | + path: /tmp/ios-artifact/ |
| 710 | + if-no-files-found: error |
| 711 | + retention-days: 1 |
| 712 | + |
653 | 713 | e2e-react-native-android: |
654 | 714 | name: 📱 E2E React Native Android (shard ${{ matrix.shard }}/2) |
655 | 715 | runs-on: namespace-profile-linux-16-vcpu-32-gb-ram-optimal |
@@ -808,3 +868,107 @@ jobs: |
808 | 868 | implementations/react-native-sdk/.detox/ |
809 | 869 | /tmp/mock-server.log |
810 | 870 | retention-days: 7 |
| 871 | + |
| 872 | + e2e-ios-sdk: |
| 873 | + name: 🍎 E2E iOS UI (${{ matrix.scheme }}) |
| 874 | + runs-on: namespace-profile-macos-apple-silicon-arm64-6-cpu-14-gb |
| 875 | + timeout-minutes: 45 |
| 876 | + needs: [setup, changes, e2e-ios-sdk-build] |
| 877 | + if: needs.changes.outputs.e2e_ios == 'true' |
| 878 | + strategy: |
| 879 | + fail-fast: false |
| 880 | + matrix: |
| 881 | + include: |
| 882 | + - scheme: SwiftUI |
| 883 | + - scheme: UIKit |
| 884 | + env: |
| 885 | + DERIVED_DATA: /tmp/optimization-ios-derived-data |
| 886 | + IOS_SCHEME: ${{ matrix.scheme }} |
| 887 | + IOS_SIM_NAME: 'iPhone 16' |
| 888 | + IOS_SIM_OS: 'latest' |
| 889 | + # Smoke mode for the first PR — restrict to one test class per scheme. |
| 890 | + # Remove this env var in a follow-up PR to enable the full suite. |
| 891 | + IOS_ONLY_TESTING: OptimizationAppUITests${{ matrix.scheme }}/PreviewPanelTests |
| 892 | + steps: |
| 893 | + - uses: namespacelabs/nscloud-checkout-action@938f5d2d403d6224d9a0c0dc559b1dae09c2ede4 # v8.1.1 |
| 894 | + |
| 895 | + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 |
| 896 | + with: |
| 897 | + node-version-file: '.nvmrc' |
| 898 | + package-manager-cache: false |
| 899 | + |
| 900 | + - uses: pnpm/action-setup@903f9c1a6ebcba6cf41d87230be49611ac97822e # v6.0.3 |
| 901 | + |
| 902 | + - name: Install xcbeautify |
| 903 | + run: brew install xcbeautify |
| 904 | + |
| 905 | + - uses: namespacelabs/nscloud-cache-action@15799a6b54e5765f85b2aac25b3f0df43ed571c0 # v1.4.3 |
| 906 | + with: |
| 907 | + cache: pnpm |
| 908 | + |
| 909 | + - run: pnpm install --prefer-offline --frozen-lockfile |
| 910 | + |
| 911 | + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 |
| 912 | + with: |
| 913 | + name: ios-uitest-bundles |
| 914 | + path: /tmp/ios-artifact/ |
| 915 | + |
| 916 | + - name: Reconstruct DerivedData layout at stable path |
| 917 | + run: | |
| 918 | + mkdir -p "$DERIVED_DATA/Build" |
| 919 | + mv /tmp/ios-artifact/Products "$DERIVED_DATA/Build/Products" |
| 920 | + ls "$DERIVED_DATA/Build/Products" |
| 921 | +
|
| 922 | + - name: Boot iOS Simulator |
| 923 | + run: | |
| 924 | + DEVICE_UDID=$(xcrun simctl create "ci-${{ matrix.scheme }}" "$IOS_SIM_NAME") |
| 925 | + echo "DEVICE_UDID=$DEVICE_UDID" >> "$GITHUB_ENV" |
| 926 | + xcrun simctl boot "$DEVICE_UDID" |
| 927 | + xcrun simctl bootstatus "$DEVICE_UDID" -b |
| 928 | +
|
| 929 | + - name: Start Mock Server |
| 930 | + run: | |
| 931 | + pnpm --dir lib/mocks serve > /tmp/mock-server.log 2>&1 & |
| 932 | + echo $! > /tmp/mock-server.pid |
| 933 | + for i in {1..60}; do |
| 934 | + if nc -z localhost 8000 2>/dev/null; then |
| 935 | + echo "Mock server is ready" |
| 936 | + break |
| 937 | + fi |
| 938 | + echo "Waiting for mock server... ($i/60)" |
| 939 | + sleep 1 |
| 940 | + done |
| 941 | + if ! nc -z localhost 8000 2>/dev/null; then |
| 942 | + echo "Mock server failed to start:" |
| 943 | + cat /tmp/mock-server.log |
| 944 | + exit 1 |
| 945 | + fi |
| 946 | +
|
| 947 | + - name: Verify built xctestrun exists for ${{ matrix.scheme }} |
| 948 | + shell: 'bash -eo pipefail {0}' |
| 949 | + run: | |
| 950 | + shopt -s nullglob |
| 951 | + matches=("$DERIVED_DATA"/Build/Products/OptimizationApp"$IOS_SCHEME"_*.xctestrun) |
| 952 | + if [ ${#matches[@]} -eq 0 ]; then |
| 953 | + echo "No xctestrun found for scheme $IOS_SCHEME under $DERIVED_DATA/Build/Products/" >&2 |
| 954 | + ls -la "$DERIVED_DATA/Build/Products/" || true |
| 955 | + exit 1 |
| 956 | + fi |
| 957 | + printf 'Found xctestrun: %s\n' "${matches[@]}" |
| 958 | +
|
| 959 | + - name: Run iOS UI tests (${{ matrix.scheme }}) |
| 960 | + shell: 'bash -eo pipefail {0}' |
| 961 | + run: pnpm run implementation:ios-sdk -- test:e2e:ios:run:release |
| 962 | + |
| 963 | + - name: Stop Mock Server |
| 964 | + if: always() |
| 965 | + run: kill $(cat /tmp/mock-server.pid) 2>/dev/null || true |
| 966 | + |
| 967 | + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 |
| 968 | + if: ${{ !cancelled() }} |
| 969 | + with: |
| 970 | + name: ci-results-ios-${{ matrix.scheme }} |
| 971 | + path: | |
| 972 | + /tmp/optimization-ios-derived-data/Test-*.xcresult |
| 973 | + /tmp/mock-server.log |
| 974 | + retention-days: 7 |
0 commit comments