diff --git a/.changeset/large-aliens-arrive.md b/.changeset/large-aliens-arrive.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/large-aliens-arrive.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.github/workflows/actions.lock b/.github/workflows/actions.lock index 4773368e453..8278d5499ec 100644 --- a/.github/workflows/actions.lock +++ b/.github/workflows/actions.lock @@ -48,10 +48,8 @@ workflows: - 'actions/checkout@v4.4.0' - 'actions/setup-java@v4.9.1' - 'actions/setup-node@v4.4.0' - - 'actions/upload-artifact@v4.6.2' - 'gradle/actions@v6.3.0' - 'pnpm/action-setup@v4.3.0' - - 'reactivecircus/android-emulator-runner@v2.38.0' '.github/workflows/labeler-apply.yml': - 'actions/checkout@v4.4.0' - 'actions/download-artifact@v4.3.0' @@ -202,11 +200,6 @@ dependencies: commit: 'sha1-4ed28566c2bdcdaee6dca2b46b9666d01b4ed8a4' owner_id: 56475783 repo_id: 280818415 - 'reactivecircus/android-emulator-runner@v2.38.0': - ref: 'v2.38.0' - commit: 'sha1-a421e43855164a8197daf9d8d40fe71c6996bb0d' - owner_id: 51352484 - repo_id: 219782401 'slackapi/slack-github-action@v1.27.1': ref: 'v1.27.1' commit: 'sha1-fcfb566f8b0aab22203f066d80ca1d7e4b5d05b3' diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index 6ae4115e83d..d4c38bbdfca 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -7,9 +7,7 @@ on: - main paths: - '.github/workflows/expo-native-build.yml' - - 'integration/e2e.expo-native.config.ts' - 'integration/templates/expo-native/**' - - 'integration/tests/expo-native/**' - 'packages/expo/**' - 'packages/expo-biometrics/**' - 'packages/expo-google-signin/**' @@ -25,22 +23,15 @@ concurrency: env: FIXTURE_DIR: integration/templates/expo-native - E2E_DIR: integration/tests/expo-native FIXTURE_PUBLISHABLE_KEY: pk_test_ZHVtbXkuY2xlcmsuYWNjb3VudHMuZGV2JA SDK_PACK_DIR: /tmp/clerk-expo-pack - E2E_INSTANCE_NAME: clerkstage-with-native-components - BAPI_URL: https://api.clerkstage.dev - IOS_SIMULATORS: '2' - E2E_TELEMETRY_DISABLED: '1' jobs: native-build: if: ${{ github.head_ref != 'changeset-release/main' && (github.event_name == 'workflow_dispatch' || github.event.pull_request.draft == false) }} - name: Native ${{ matrix.run-e2e == true && 'E2E' || 'Build' }} (${{ matrix.platform }}, sdk ${{ matrix.expo-sdk }}) + name: Native Build (${{ matrix.platform }}, sdk ${{ matrix.expo-sdk }}) runs-on: ${{ matrix.runner }} - timeout-minutes: ${{ matrix.run-e2e == true && 60 || 45 }} - env: - CLERK_TEST_USERNAME_PREFIX: e2e_${{ github.run_id }}_${{ matrix.platform }}_ + timeout-minutes: 45 strategy: fail-fast: false matrix: @@ -54,11 +45,9 @@ jobs: - expo-sdk: 58 platform: android runner: blacksmith-8vcpu-ubuntu-2204 - run-e2e: true - expo-sdk: 58 platform: ios runner: blacksmith-6vcpu-macos-26 - run-e2e: true steps: - name: Checkout repo @@ -103,18 +92,18 @@ jobs: with: path: ${{ steps.native-build-key.outputs.artifact }} # Bump the version when native build commands change. - key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} + key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ steps.native-build-key.outputs.hash }} - - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true + - if: steps.native-build-cache.outputs.cache-hit != 'true' uses: pnpm/action-setup@v4.3.0 - - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true + - if: steps.native-build-cache.outputs.cache-hit != 'true' uses: actions/setup-node@v4.4.0 with: node-version: 24.15.0 cache: pnpm - name: Install monorepo dependencies - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true + if: steps.native-build-cache.outputs.cache-hit != 'true' run: pnpm install --frozen-lockfile - name: Build and pack Clerk packages @@ -132,7 +121,6 @@ jobs: working-directory: ${{ env.FIXTURE_DIR }} env: EXPO_SDK: ${{ matrix.expo-sdk }} - RUN_E2E: ${{ matrix.run-e2e == true && 'true' || 'false' }} run: | cp "package.sdk-$EXPO_SDK.json" package.json pnpm install --no-frozen-lockfile @@ -142,49 +130,13 @@ jobs: NATIVE_TARBALL="$(ls "$SDK_PACK_DIR"/clerk-expo-native-components-*.tgz)" BIOMETRICS_TARBALL="$(ls "$SDK_PACK_DIR"/clerk-expo-biometrics-*.tgz)" pnpm add "$SDK_TARBALL" "$GOOGLE_SIGNIN_TARBALL" "$NATIVE_TARBALL" "$BIOMETRICS_TARBALL" -w - # expo-dev-client makes even release builds boot into the dev - # launcher (unreachable Metro in CI), which stalls every e2e - # flow on a blank screen. Skip it on e2e jobs only. - DEV_CLIENT="expo-dev-client" - if [ "$RUN_E2E" = "true" ]; then DEV_CLIENT=""; fi - pnpm expo install expo-auth-session expo-constants expo-crypto $DEV_CLIENT expo-secure-store expo-web-browser - if [ "$RUN_E2E" = "true" ]; then - REACT_VERSION=$(node -p 'require("react/package.json").version') - REACT_DOM_VERSION=$(node -p 'require("react-dom/package.json").version') - if [ "$REACT_VERSION" != "$REACT_DOM_VERSION" ]; then - echo "::error::React version mismatch: react@$REACT_VERSION, react-dom@$REACT_DOM_VERSION" - exit 1 - fi - fi - - - name: Check e2e secret availability - id: gate - if: matrix.run-e2e == true - env: - KEYS: ${{ secrets.INTEGRATION_STAGING_INSTANCE_KEYS }} - run: | - if [ -n "$KEYS" ]; then - echo "ok=true" >> "$GITHUB_OUTPUT" - else - echo "ok=false" >> "$GITHUB_OUTPUT" - echo "::notice::INTEGRATION_STAGING_INSTANCE_KEYS unavailable (fork PR?); running build-only." - fi - - - name: Resolve Clerk instance keys - id: keys - if: steps.gate.outputs.ok == 'true' - continue-on-error: true - env: - INTEGRATION_STAGING_INSTANCE_KEYS: ${{ secrets.INTEGRATION_STAGING_INSTANCE_KEYS }} - run: node scripts/resolve-instance-keys.mjs INTEGRATION_STAGING_INSTANCE_KEYS "$E2E_INSTANCE_NAME" + pnpm expo install expo-auth-session expo-constants expo-crypto expo-dev-client expo-secure-store expo-web-browser - name: Write fixture .env if: steps.native-build-cache.outputs.cache-hit != 'true' working-directory: ${{ env.FIXTURE_DIR }} - env: - E2E_PK: ${{ steps.keys.outputs.pk }} run: | - echo "EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=${E2E_PK:-$FIXTURE_PUBLISHABLE_KEY}" > .env + echo "EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=$FIXTURE_PUBLISHABLE_KEY" > .env - name: Set up JDK 17 if: matrix.platform == 'android' @@ -237,131 +189,3 @@ jobs: with: path: ${{ steps.native-build-key.outputs.artifact }} key: ${{ steps.native-build-cache.outputs.cache-primary-key }} - - - name: Boot iOS simulators - if: matrix.platform == 'ios' && matrix.run-e2e == true && steps.keys.outputs.pk != '' - run: ${{ env.E2E_DIR }}/boot-ios-simulators.sh boot "$IOS_SIMULATORS" - - - name: Cache iOS automation runner - if: matrix.platform == 'ios' && steps.keys.outputs.pk != '' - uses: actions/cache@v4.3.0 - with: - path: ~/.agent-device - key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: agent-device-${{ runner.os }}- - - - name: Run iOS e2e - id: run_e2e_ios - if: matrix.platform == 'ios' && steps.keys.outputs.sk != '' - env: - CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} - CLERK_API_URL: ${{ env.BAPI_URL }} - run: | - "$E2E_DIR/boot-ios-simulators.sh" wait - mkdir -p "$RUNNER_TEMP/e2e-device-logs" - log_pids=() - trap 'kill "${log_pids[@]}" 2>/dev/null || true; wait "${log_pids[@]}" 2>/dev/null || true' EXIT - for udid in ${CLERK_TEST_DEVICES//,/ }; do - xcrun simctl install "$udid" "$FIXTURE_DIR/ios/build/Build/Products/Release-iphonesimulator/ClerkExpoNativeBuildFixture.app" - xcrun simctl spawn "$udid" log stream --style compact \ - --predicate 'processImagePath CONTAINS "ClerkExpoNativeBuildFixture"' \ - > "$RUNNER_TEMP/e2e-device-logs/$udid-console.log" 2>&1 & - log_pids+=($!) - done - pnpm test:integration:expo-native:ios --reporter list,junit,markdown - - - name: Enable KVM - if: matrix.platform == 'android' && steps.keys.outputs.sk != '' - 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: AVD cache - id: avd-cache - if: matrix.platform == 'android' && steps.keys.outputs.sk != '' - uses: actions/cache@v4.3.0 - with: - path: | - ~/.android/avd/* - ~/.android/adb* - key: avd-34-google_apis-x86_64-v1 - - - name: Create AVD snapshot - if: matrix.platform == 'android' && steps.keys.outputs.sk != '' && steps.avd-cache.outputs.cache-hit != 'true' - uses: reactivecircus/android-emulator-runner@v2.38.0 - with: - api-level: 34 - target: google_apis - arch: x86_64 - force-avd-creation: false - emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim - disable-animations: false - script: echo "Generated AVD snapshot for caching." - - - name: Run Android e2e - id: run_e2e_android - if: matrix.platform == 'android' && steps.keys.outputs.sk != '' - uses: reactivecircus/android-emulator-runner@v2.38.0 - env: - CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} - CLERK_API_URL: ${{ env.BAPI_URL }} - with: - api-level: 34 - target: google_apis - arch: x86_64 - force-avd-creation: false - emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim - disable-animations: true - # The action runs each script line in a separate sh -c; the folded - # scalar (>-) plus && keeps everything in one shell invocation. - script: >- - mkdir -p "$RUNNER_TEMP/e2e-device-logs" && - adb install -r "$FIXTURE_DIR/android/app/build/outputs/apk/release/app-release.apk" && - (adb logcat -v threadtime > "$RUNNER_TEMP/e2e-device-logs/logcat.log" 2>&1 &) && - pnpm test:integration:expo-native:android --reporter list,junit,markdown - - - name: Delete leftover test users - if: always() && steps.keys.outputs.sk != '' - env: - CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} - run: | - curl -fsS -G "$BAPI_URL/v1/users" --data-urlencode "limit=100" --data-urlencode "query=$CLERK_TEST_USERNAME_PREFIX" -H "Authorization: Bearer $CLERK_SECRET_KEY" | - jq -r --arg p "$CLERK_TEST_USERNAME_PREFIX" '.[] | select((.username // "") | startswith($p)) | .id' | - while read -r user_id; do - curl -fsS --retry 3 --retry-delay 1 -o /dev/null -X DELETE "$BAPI_URL/v1/users/$user_id" -H "Authorization: Bearer $CLERK_SECRET_KEY" || - echo "::warning::Could not delete leftover test user $user_id" - done - - - name: Upload e2e artifacts - if: always() && steps.keys.outputs.sk != '' - uses: actions/upload-artifact@v4.6.2 - with: - name: e2e-${{ matrix.platform }} - include-hidden-files: true - path: | - integration/.e2e - ${{ runner.temp }}/e2e-device-logs - if-no-files-found: warn - retention-days: 7 - - - name: Report e2e outcome - if: always() && steps.keys.outputs.sk != '' - env: - IOS_OUTCOME: ${{ steps.run_e2e_ios.outcome }} - ANDROID_OUTCOME: ${{ steps.run_e2e_android.outcome }} - run: | - outcome="$IOS_OUTCOME" - [ "$outcome" = "skipped" ] && outcome="$ANDROID_OUTCOME" - echo "## Native e2e (${{ matrix.platform }}): $outcome" >> "$GITHUB_STEP_SUMMARY" - if [ -f integration/.e2e/summary.md ]; then - cat integration/.e2e/summary.md >> "$GITHUB_STEP_SUMMARY" - fi - if [ "$outcome" = "failure" ]; then - echo "::error::Native e2e failed. See the e2e-${{ matrix.platform }} artifact." - fi - flaky=$(jq -r '[.run.results[] | select(.status == "flaky") | .file] | join(", ")' integration/.e2e/report.json 2>/dev/null || true) - if [ -n "$flaky" ]; then - echo "::error::Flaky flow(s), failed then passed on the retry: $flaky" - exit 1 - fi diff --git a/.gitignore b/.gitignore index f0aef8bbd7a..24d1b33d3a8 100644 --- a/.gitignore +++ b/.gitignore @@ -67,7 +67,6 @@ packages/*/examples/*/package-lock.json packages/*/examples/*/yarn.lock /test-results/ /playwright-report/ -/integration/.e2e/ /playwright/.cache/ # integration testing diff --git a/integration/e2e.expo-native.config.ts b/integration/e2e.expo-native.config.ts deleted file mode 100644 index 88c47c58e57..00000000000 --- a/integration/e2e.expo-native.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { mobile } from '@e2e-dev/mobile'; -import type { E2EConfig } from 'e2e'; - -const app = { bundleId: 'com.clerk.exponativebuildfixture' }; -const devices = process.env.CLERK_TEST_DEVICES?.split(','); - -export default { - tests: 'tests/expo-native/*.e2e.ts', - targets: [ - { name: 'ios', engine: mobile({ platform: 'ios', device: devices }), app }, - { name: 'android', engine: mobile({ platform: 'android', device: devices }), app }, - ], - workers: devices?.length ?? 1, - timeout: 300_000, -} satisfies E2EConfig; diff --git a/integration/templates/expo-native/App.tsx b/integration/templates/expo-native/App.tsx index 86967b97b52..cd31678f24d 100644 --- a/integration/templates/expo-native/App.tsx +++ b/integration/templates/expo-native/App.tsx @@ -1,171 +1,18 @@ -import { ClerkProvider, useAuth, useUser } from '@clerk/expo'; -import { AuthView, UserButton, UserProfileView } from '@clerk/expo/native-components'; -import { tokenCache } from '@clerk/expo/token-cache'; -import { useState } from 'react'; -import { Button, Modal, StyleSheet, Text, View } from 'react-native'; +import { type ReactElement } from 'react'; +import { LogBox } from 'react-native'; -import { BiometricAvailabilityButton } from './components/BiometricAvailabilityButton'; -import { GoogleSignInButton } from './components/GoogleSignInButton'; +import { readVerifyLaunch } from './verify/launch'; +import { logRequests, VerifyHost } from './verify/VerifyHost'; -const publishableKey = process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY; +const verifyLaunch = readVerifyLaunch(); -if (!publishableKey) { - throw new Error('Missing EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY'); +if (verifyLaunch.runId !== null) { + LogBox.ignoreAllLogs(); } - -function NativeBuildFixture() { - const { isLoaded, isSignedIn, signOut } = useAuth({ treatPendingAsSignedOut: false }); - const { user } = useUser(); - const [isAuthOpen, setIsAuthOpen] = useState(false); - const [isProfileOpen, setIsProfileOpen] = useState(false); - const [signOutResult, setSignOutResult] = useState(null); - - if (isProfileOpen) { - return ( - - - - Rehosted RN body - - ), - }, - ]} - isDismissible={false} - onHostBack={() => setIsProfileOpen(false)} - /> - - - ); - } - - return ( - - - Clerk Expo Native Fixture - {isSignedIn && } - - - {isLoaded ? `signed ${isSignedIn ? 'in' : 'out'}` : 'loading'} - {user?.id && {user.id}} - {signOutResult && {`sign out: ${signOutResult}`}} -