diff --git a/.github/workflows/browserstack-e2e-android.yml b/.github/workflows/browserstack-e2e-android.yml index 8fd11794..8e2723da 100644 --- a/.github/workflows/browserstack-e2e-android.yml +++ b/.github/workflows/browserstack-e2e-android.yml @@ -4,9 +4,6 @@ # This software may be modified and distributed under the terms # of the MIT license. See the LICENSE file for details. # -# TODO: This workflow is not enforced right now and is currently failing. -# We have an open ticket with BrowserStack waiting for them to release a new version -# of the cloud driver based on Detox version 20.43+. name: BrowserStack E2E — Android on: @@ -146,12 +143,18 @@ jobs: # across all included modules so the directories are present. run: | cd android && ./gradlew \ + :ping-identity_rn-binding:generateCodegenArtifactsFromSchema \ :ping-identity_rn-browser:generateCodegenArtifactsFromSchema \ + :ping-identity_rn-device-client:generateCodegenArtifactsFromSchema \ :ping-identity_rn-device-id:generateCodegenArtifactsFromSchema \ :ping-identity_rn-device-profile:generateCodegenArtifactsFromSchema \ + :ping-identity_rn-external-idp:generateCodegenArtifactsFromSchema \ + :ping-identity_rn-fido:generateCodegenArtifactsFromSchema \ :ping-identity_rn-journey:generateCodegenArtifactsFromSchema \ :ping-identity_rn-logger:generateCodegenArtifactsFromSchema \ + :ping-identity_rn-oath:generateCodegenArtifactsFromSchema \ :ping-identity_rn-oidc:generateCodegenArtifactsFromSchema \ + :ping-identity_rn-push:generateCodegenArtifactsFromSchema \ :ping-identity_rn-storage:generateCodegenArtifactsFromSchema \ :react-native-async-storage_async-storage:generateCodegenArtifactsFromSchema diff --git a/.github/workflows/browserstack-prep-ios-artifacts.yml b/.github/workflows/browserstack-prep-ios-artifacts.yml index 2e8f9ab2..450994d5 100644 --- a/.github/workflows/browserstack-prep-ios-artifacts.yml +++ b/.github/workflows/browserstack-prep-ios-artifacts.yml @@ -39,7 +39,7 @@ jobs: timeout-minutes: 60 env: - XCODE_VERSION: ${{ vars.XCODE_VERSION || '26.4.1' }} + XCODE_VERSION: ${{ vars.XCODE_VERSION || '26.1.1' }} RUBY_VERSION: '2.6.10' BUNDLE_GEMFILE: ${{ github.workspace }}/PingTestRunner/Gemfile PING_TEST_RUNNER_DIR: PingTestRunner diff --git a/.github/workflows/build-and-test-ios.yml b/.github/workflows/build-and-test-ios.yml index 1ce0b809..992d5cad 100644 --- a/.github/workflows/build-and-test-ios.yml +++ b/.github/workflows/build-and-test-ios.yml @@ -83,40 +83,9 @@ jobs: working-directory: ${{ env.IOS_DIRECTORY }} run: bundle exec pod install --repo-update - # Resolve Xcode: the pinned XCODE_VERSION may exist on the runner but lack the iOS simulator runtime - # component (SDK ≠ runtime — the SDK ships inside Xcode but the runtime is provisioned separately). - # This step prefers the pinned version but falls back to the newest installed Xcode whose major.minor - # iOS version has a matching pre-provisioned simulator runtime, so the destination is always bootable. - - name: Resolve Xcode version - run: | - PINNED="/Applications/Xcode_${{ env.XCODE_VERSION }}.app" - SELECTED="" - # Get all available iOS runtime versions (system-wide, not Xcode-scoped). - AVAILABLE_RUNTIMES=$(xcrun simctl list runtimes 2>/dev/null \ - | grep -i "iOS" | grep -v "unavailable" \ - | grep -oE "[0-9]+\.[0-9]+" | sort -u) - for app in "$PINNED" $(ls -d /Applications/Xcode*.app 2>/dev/null | sort -rV); do - [ -d "$app" ] || continue - # Derive the iOS SDK version this Xcode ships with (e.g. "26.1" from "iphonesimulator26.1"). - xcode_ios=$(DEVELOPER_DIR="$app/Contents/Developer" \ - xcodebuild -showsdks 2>/dev/null \ - | grep -i "iphonesimulator" | grep -oE "[0-9]+\.[0-9]+" | sort -rV | head -1) - [ -n "$xcode_ios" ] || continue - # Check if a runtime matching this Xcode's major.minor iOS version is provisioned. - if echo "$AVAILABLE_RUNTIMES" | grep -qx "$xcode_ios"; then - SELECTED="$app" - echo "XCODE_RESOLVED_PATH=$app" >> "$GITHUB_ENV" - echo "Resolved Xcode: $app (iOS SDK $xcode_ios, runtime available)" - break - else - echo "Skipping $app: iOS $xcode_ios SDK present but runtime not provisioned (available: $(echo $AVAILABLE_RUNTIMES | tr '\n' ' '))" - fi - done - [ -n "$SELECTED" ] || { echo "No Xcode with a matching provisioned iOS simulator runtime found"; exit 1; } - # Select Xcode version - name: Select Xcode version - run: sudo xcode-select -s "${{ env.XCODE_RESOLVED_PATH }}" && /usr/bin/xcodebuild -version + run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app && /usr/bin/xcodebuild -version # Clang module caches are sensitive to SDK header mtimes on the runner image. # This must run AFTER Xcode is selected so the active SDK is finalised. @@ -136,31 +105,29 @@ jobs: chmod +x product/xcresultparser sudo mv product/xcresultparser /usr/local/bin/ - # Resolve the best available iPhone simulator: prefer iPhone 17, fall back to any iPhone. - # Uses the device UDID as the destination to avoid OS version string mismatches between - # simctl runtime keys (e.g. "iOS-26-4") and xcodebuild's reported OS (e.g. "26.4.1"). + # Resolve the best available iPhone simulator using xcodebuild -showdestinations. + # This asks Xcode itself which destinations are eligible for the scheme — only simulators + # compatible with the active Xcode SDK appear in "Available destinations", so no version + # string matching is needed and incompatible runtimes are automatically excluded. + # Prefers iPhone 17; falls back to any available iPhone simulator. # Sets DESTINATION and SIMULATOR_UDID in GITHUB_ENV for all subsequent steps. - name: Resolve simulator destination run: | - DEVICES_JSON=$(xcrun simctl list devices available --json) - RESULT=$(echo "$DEVICES_JSON" | jq -r ' - [.devices | to_entries[] - | select(.key | test("iOS")) - | . as $runtime - | .value[] - | select(.name | test("^iPhone")) - | { - os: ($runtime.key | gsub("com.apple.CoreSimulator.SimRuntime.iOS-"; "") | gsub("-"; ".")), - name: .name, - udid: .udid - }] - | (map(select(.name == "iPhone 17")) | sort_by(.os) | last) - // (sort_by(.os) | last) - | "\(.name)|\(.os)|\(.udid)" - ') - SIMULATOR_NAME=$(echo "$RESULT" | cut -d'|' -f1) - OS_VERSION=$(echo "$RESULT" | cut -d'|' -f2) - SIMULATOR_UDID=$(echo "$RESULT" | cut -d'|' -f3) + DESTINATIONS=$(xcodebuild -showdestinations \ + -workspace "${{ env.WORKSPACE }}" \ + -scheme "${{ env.SCHEME }}" 2>&1) + echo "--- xcodebuild -showdestinations output ---" + echo "$DESTINATIONS" + echo "-------------------------------------------" + AVAILABLE=$(echo "$DESTINATIONS" | awk '/Available destinations/{flag=1; next} /Ineligible destinations/{flag=0} flag') + DEST_LINE=$(echo "$AVAILABLE" | grep "platform:iOS Simulator" | grep "name:iPhone 17" | tail -1) + if [ -z "$DEST_LINE" ]; then + DEST_LINE=$(echo "$AVAILABLE" | grep "platform:iOS Simulator" | grep "name:iPhone" | tail -1) + fi + [ -n "$DEST_LINE" ] || { echo "No eligible iPhone simulator found"; exit 1; } + SIMULATOR_UDID=$(echo "$DEST_LINE" | grep -oE 'id:[A-F0-9-]+' | cut -d: -f2) + SIMULATOR_NAME=$(echo "$DEST_LINE" | grep -oE 'name:[^,}]+' | cut -d: -f2 | xargs) + OS_VERSION=$(echo "$DEST_LINE" | grep -oE 'OS:[^,}]+' | cut -d: -f2 | xargs) echo "Resolved: $SIMULATOR_NAME ($OS_VERSION) [$SIMULATOR_UDID]" echo "DESTINATION=platform=iOS Simulator,id=${SIMULATOR_UDID}" >> "$GITHUB_ENV" echo "SIMULATOR_UDID=${SIMULATOR_UDID}" >> "$GITHUB_ENV" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 27c9ccc9..7a869f48 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,7 @@ # name: CI on: + workflow_dispatch: pull_request: types: [opened, reopened, synchronize, edited] @@ -104,10 +105,7 @@ jobs: secrets: inherit # Run Android E2E tests on BrowserStack real devices after Android unit tests pass. - # Blocked: BrowserStack cloud driver does not yet support Detox 20.43+. - # Remove the `if false` guard once the upstream fix is released. browserstack-android: - if: false needs: android-unit-tests permissions: contents: read diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 3a603a05..dbd54368 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -115,13 +115,7 @@ jobs: path: PingTestRunner/artifacts/ # ── Android E2E (emulator on ubuntu-latest) ─────────────────────────────── - # NOTE: This job will currently fail. The BrowserStack Detox fork we depend on - # for cloud device testing is pinned to a Detox version that is incompatible - # with React Native 0.80. - # TODO: Re-enable and validate once BrowserStack releases an updated version - # of their Detox fork with RN 0.80 support. e2e-android: - if: false name: E2E — Android Emulator runs-on: ubuntu-latest timeout-minutes: 60 diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index 9bf917b2..110677dc 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/PingTestRunner/android/app/build.gradle b/PingTestRunner/android/app/build.gradle index a1940bb3..1bd593e6 100644 --- a/PingTestRunner/android/app/build.gradle +++ b/PingTestRunner/android/app/build.gradle @@ -74,6 +74,12 @@ android { proguardFile "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules-app.pro" } } + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + excludes += "/META-INF/versions/9/OSGI-INF/MANIFEST.MF" + } + } } dependencies { diff --git a/PingTestRunner/android/settings.gradle b/PingTestRunner/android/settings.gradle index 7c07059f..666523fb 100644 --- a/PingTestRunner/android/settings.gradle +++ b/PingTestRunner/android/settings.gradle @@ -33,10 +33,14 @@ include(":ping-identity_rn-browser") project(":ping-identity_rn-browser").projectDir = file("../../packages/browser/android") include(":ping-identity_rn-core") project(":ping-identity_rn-core").projectDir = file("../../packages/core/android") +include(":ping-identity_rn-device-client") +project(":ping-identity_rn-device-client").projectDir = file("../../packages/device-client/android") include(":ping-identity_rn-device-id") project(":ping-identity_rn-device-id").projectDir = file("../../packages/device-id/android") include(":ping-identity_rn-device-profile") project(":ping-identity_rn-device-profile").projectDir = file("../../packages/device-profile/android") +include(":ping-identity_rn-external-idp") +project(":ping-identity_rn-external-idp").projectDir = file("../../packages/external-idp/android") include(":ping-identity_rn-fido") project(":ping-identity_rn-fido").projectDir = file("../../packages/fido/android") include(":ping-identity_rn-journey") diff --git a/PingTestRunner/package.json b/PingTestRunner/package.json index 764cfa70..add5ffe5 100644 --- a/PingTestRunner/package.json +++ b/PingTestRunner/package.json @@ -21,7 +21,7 @@ "test:bs:android": "NODE_NO_WARNINGS=1 detox test --configuration android.bs --loglevel trace", "test:e2e:ios": "sh -c 'export DETOX_SERVER_PORT=${DETOX_SERVER_PORT:-8099}; export NODE_NO_WARNINGS=1; yarn e2e:android:free-detox-port && detox test --configuration ios.sim \"$@\"' --", "build:e2e:android": "detox build --configuration android.emu", - "build:bs:android": "cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release", + "build:bs:android": "cd android && ./gradlew :app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release", "build:e2e:ios": "detox build --configuration ios.sim", "build:bs:ios:archive": "sh ./scripts/build-bs-ios-archive.sh", "build:bs:ios:ipa": "sh ./scripts/build-bs-ios-ipa.sh", @@ -63,7 +63,7 @@ "@testing-library/react-native": "^13.3.3", "@types/jest": "^29.5.14", "@types/react": "^19.1.0", - "detox": "npm:@browserstack/detox@20.38.0-cloud.1", + "detox": "npm:@browserstack/detox@20.38.0-cloud.3", "dotenv": "^16.4.7", "eslint": "^8.19.0", "jest": "^29.7.0", diff --git a/yarn.lock b/yarn.lock index ab789145..5970dafd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6442,9 +6442,9 @@ __metadata: languageName: node linkType: hard -"detox@npm:@browserstack/detox@20.38.0-cloud.1": - version: 20.38.0-cloud.1 - resolution: "@browserstack/detox@npm:20.38.0-cloud.1" +"detox@npm:@browserstack/detox@20.38.0-cloud.3": + version: 20.38.0-cloud.3 + resolution: "@browserstack/detox@npm:20.38.0-cloud.3" dependencies: "@wix-pilot/core": "npm:^3.2.2" "@wix-pilot/detox": "npm:^1.0.11" @@ -6490,7 +6490,7 @@ __metadata: optional: true bin: detox: local-cli/cli.js - checksum: 10c0/5f59b76c1b9427132b5b3068cdab5950893b1d98d44f7418d0f2563853d618b62b8db53be762bedf73793f15eb5b51fce75cab62e5aa34bb65773494c18683d3 + checksum: 10c0/e49a2c37146b3e6cbf2221fea32b29ace3dda75d6bcaae6a531b3827a1b8a4f99556dd7b858881d4eace49df0db3249c36aa8d786b076cbb05e323eb25e2f39f languageName: node linkType: hard @@ -12554,7 +12554,7 @@ __metadata: "@testing-library/react-native": "npm:^13.3.3" "@types/jest": "npm:^29.5.14" "@types/react": "npm:^19.1.0" - detox: "npm:@browserstack/detox@20.38.0-cloud.1" + detox: "npm:@browserstack/detox@20.38.0-cloud.3" dotenv: "npm:^16.4.7" eslint: "npm:^8.19.0" jest: "npm:^29.7.0"