diff --git a/.changeset/new-queens-brake.md b/.changeset/new-queens-brake.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/new-queens-brake.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index 03e8520dbb0..fe42691e2cb 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -8,6 +8,7 @@ on: paths: - '.github/workflows/expo-native-build.yml' - 'integration/templates/expo-native/**' + - 'integration/tests/expo-native/**' - 'packages/expo/**' workflow_dispatch: @@ -20,15 +21,19 @@ 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 + MAESTRO_VERSION: '2.6.1' jobs: native-build: if: ${{ github.head_ref != 'changeset-release/main' }} name: Expo ${{ matrix.expo-sdk }} / ${{ matrix.platform }} runs-on: ${{ matrix.runner }} - timeout-minutes: 45 + timeout-minutes: ${{ matrix.run-e2e == true && 60 || 45 }} strategy: fail-fast: false matrix: @@ -48,9 +53,11 @@ jobs: - expo-sdk: 57 platform: android runner: blacksmith-8vcpu-ubuntu-2204 + run-e2e: true - expo-sdk: 57 platform: ios runner: blacksmith-6vcpu-macos-26 + run-e2e: true steps: - name: Checkout repo @@ -72,27 +79,51 @@ jobs: pnpm --filter @clerk/expo... build mkdir -p "$SDK_PACK_DIR" pnpm --filter @clerk/expo pack --pack-destination "$SDK_PACK_DIR" - SDK_TARBALL="$(ls "$SDK_PACK_DIR"/clerk-expo-*.tgz)" - if tar -tf "$SDK_TARBALL" | grep -q '^package/e2e/'; then - echo "Fixture files must not be packed into @clerk/expo" - exit 1 - fi - name: Install fixture dependencies 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 SDK_TARBALL="$(ls "$SDK_PACK_DIR"/clerk-expo-*.tgz)" pnpm add "$SDK_TARBALL" -w - pnpm expo install expo-auth-session expo-constants expo-crypto expo-dev-client expo-secure-store expo-web-browser + # expo-dev-client makes even release builds boot into the dev + # launcher (unreachable Metro in CI), which stalls every Maestro + # 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 + + - 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" - name: Write fixture .env working-directory: ${{ env.FIXTURE_DIR }} + env: + E2E_PK: ${{ steps.keys.outputs.pk }} run: | - echo "EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=$FIXTURE_PUBLISHABLE_KEY" > .env + echo "EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=${E2E_PK:-$FIXTURE_PUBLISHABLE_KEY}" > .env - name: Set up JDK 17 if: ${{ matrix.platform == 'android' }} @@ -120,3 +151,201 @@ jobs: if: ${{ matrix.platform == 'ios' }} working-directory: ${{ env.FIXTURE_DIR }} run: pnpm build:ios + + - name: Cache Maestro + if: steps.keys.outputs.pk != '' + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + with: + path: ~/.maestro + key: maestro-${{ runner.os }}-${{ env.MAESTRO_VERSION }} + + - name: Install Maestro + if: steps.keys.outputs.pk != '' + # pipefail + binary check so a curl flake doesn't leave a missing + # binary that only surfaces later as exit-code-127. + run: | + set -o pipefail + if [ -x "$HOME/.maestro/bin/maestro" ]; then + echo "Using cached Maestro" + else + installed=0 + for i in 1 2 3; do + if curl -fLs --retry 3 --retry-delay 5 "https://get.maestro.mobile.dev" | MAESTRO_VERSION="$MAESTRO_VERSION" bash; then + if [ -x "$HOME/.maestro/bin/maestro" ]; then installed=1; break; fi + fi + echo "Maestro install attempt $i failed (or binary missing); retrying" + sleep 5 + done + [ "$installed" = 1 ] || { echo "::error::Maestro install failed after 3 attempts"; exit 1; } + fi + echo "$HOME/.maestro/bin" >> "$GITHUB_PATH" + "$HOME/.maestro/bin/maestro" --version + + - name: Boot iOS simulator + id: sim + if: matrix.platform == 'ios' && steps.keys.outputs.pk != '' + uses: futureware-tech/simulator-action@e89aa8f93d3aec35083ff49d2854d07f7186f7f5 # v5 + with: + model: 'iPhone 17 Pro' + + # Provisioned as late as possible (after the expensive native build and + # simulator boot) so live credentials exist for the shortest window. + - name: Provision test user via BAPI + id: user + if: steps.keys.outputs.pk != '' + continue-on-error: true + env: + CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} + run: | + email="ci-${GITHUB_RUN_ID}-${RANDOM}+clerk_test@clerkcookie.com" + username="ci_${GITHUB_RUN_ID}_${RANDOM}" + password="ClerkCI!$(openssl rand -hex 8)Aa1" + http_code=$(curl -sS -o /tmp/bapi_response.json -w "%{http_code}" -X POST "$BAPI_URL/v1/users" \ + -H "Authorization: Bearer $CLERK_SECRET_KEY" \ + -H "Content-Type: application/json" \ + -d "{\"email_address\":[\"$email\"],\"username\":\"$username\",\"password\":\"$password\"}") + if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then + echo "::error::BAPI user creation failed (HTTP $http_code)" + cat /tmp/bapi_response.json + exit 1 + fi + user_id=$(jq -er '.id' /tmp/bapi_response.json) + echo "::add-mask::$password" + { + echo "email=$email" + echo "password=$password" + echo "user_id=$user_id" + } >> "$GITHUB_OUTPUT" + + - name: Run iOS e2e (Maestro) + id: run_e2e_ios + if: matrix.platform == 'ios' && steps.user.outputs.user_id != '' + # Burn-in: e2e cannot fail the check yet. Flip to hard-fail in a + # follow-up once the suite has proven quiet. + continue-on-error: true + working-directory: ${{ env.FIXTURE_DIR }} + env: + CLERK_TEST_EMAIL: ${{ steps.user.outputs.email }} + CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }} + SIM_UDID: ${{ steps.sim.outputs.udid }} + run: | + echo "Using simulator $SIM_UDID" + # Kill animations + predictive keyboard: animations add latency to + # every tap; predictive text hijacks inputText targets. + xcrun simctl spawn "$SIM_UDID" defaults write com.apple.UIKit UIAnimationDragCoefficient -float 0.01 || true + xcrun simctl spawn "$SIM_UDID" defaults write -g ApplePersistenceIgnoreState -bool YES || true + xcrun simctl spawn "$SIM_UDID" defaults write com.apple.keyboard.ContinuousPath -bool NO || true + xcrun simctl spawn "$SIM_UDID" defaults write com.apple.keyboard.AutoCapitalization -bool NO || true + xcrun simctl spawn "$SIM_UDID" defaults write com.apple.keyboard.AutoCorrection -bool NO || true + xcrun simctl spawn "$SIM_UDID" defaults write com.apple.keyboard.Prediction -bool NO || true + xcrun simctl install "$SIM_UDID" ios/build/Build/Products/Release-iphonesimulator/ClerkExpoNativeBuildFixture.app + # Stream the app's console output into the debug artifact so a hang has + # actionable evidence (keychain/network errors) instead of just screenshots. + mkdir -p "$RUNNER_TEMP/maestro-debug" + xcrun simctl spawn "$SIM_UDID" log stream --style compact \ + --predicate 'processImagePath CONTAINS "ClerkExpoNativeBuildFixture"' \ + > "$RUNNER_TEMP/maestro-debug/sim-console.log" 2>&1 & + LOG_PID=$! + cd "$GITHUB_WORKSPACE/$E2E_DIR" + rc=0 + MAESTRO_DEBUG_OUTPUT="$RUNNER_TEMP/maestro-debug" ./run-flows.sh \ + xcrun simctl terminate "$SIM_UDID" com.clerk.exponativebuildfixture || rc=$? + kill "$LOG_PID" 2>/dev/null || true + exit "$rc" + + - name: Enable KVM + if: matrix.platform == 'android' && steps.user.outputs.user_id != '' + 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.user.outputs.user_id != '' + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-34-google_apis-x86_64-v1 + + - name: Create AVD snapshot + if: matrix.platform == 'android' && steps.user.outputs.user_id != '' && steps.avd-cache.outputs.cache-hit != 'true' + uses: reactivecircus/android-emulator-runner@e89f39f1abbbd05b1113a29cf4db69e7540cae5a # v2 + 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 (Maestro) + id: run_e2e_android + if: matrix.platform == 'android' && steps.user.outputs.user_id != '' + continue-on-error: true + uses: reactivecircus/android-emulator-runner@e89f39f1abbbd05b1113a29cf4db69e7540cae5a # v2 + env: + CLERK_TEST_EMAIL: ${{ steps.user.outputs.email }} + CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }} + 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: >- + adb install -r integration/templates/expo-native/android/app/build/outputs/apk/release/app-release.apk && + cd integration/tests/expo-native && + MAESTRO_DEBUG_OUTPUT="$RUNNER_TEMP/maestro-debug" ./run-flows.sh adb shell am force-stop com.clerk.exponativebuildfixture + + # Runs before the artifact upload so the credentials are already dead + # by the time the debug files become downloadable. + - name: Cleanup test user + if: always() && steps.user.outputs.user_id != '' + env: + CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} + USER_ID: ${{ steps.user.outputs.user_id }} + run: | + curl -fsS -X DELETE "$BAPI_URL/v1/users/$USER_ID" \ + -H "Authorization: Bearer $CLERK_SECRET_KEY" || true + + # Maestro debug files record flow env (and typed input) in plaintext; + # add-mask only covers step logs, not artifact contents. + - name: Scrub test credentials from Maestro debug output + if: always() && (steps.run_e2e_ios.outcome == 'failure' || steps.run_e2e_android.outcome == 'failure') + env: + CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }} + run: | + [ -d "$RUNNER_TEMP/maestro-debug" ] || exit 0 + [ -n "$CLERK_TEST_PASSWORD" ] || exit 0 + # shellcheck disable=SC2016 + find "$RUNNER_TEMP/maestro-debug" -type f \ + \( -name '*.json' -o -name '*.log' -o -name '*.txt' -o -name '*.yaml' \) \ + -exec perl -pi -e 's/\Q$ENV{CLERK_TEST_PASSWORD}\E/[REDACTED]/g' {} + + + - name: Upload Maestro artifacts on e2e failure + if: always() && (steps.run_e2e_ios.outcome == 'failure' || steps.run_e2e_android.outcome == 'failure') + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: maestro-${{ matrix.platform }}-sdk${{ matrix.expo-sdk }} + path: ${{ runner.temp }}/maestro-debug + retention-days: 7 + + - name: Report e2e outcome + if: always() && steps.user.outputs.user_id != '' + 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 "## Maestro e2e (${{ matrix.platform }}, SDK ${{ matrix.expo-sdk }}): $outcome" >> "$GITHUB_STEP_SUMMARY" + if [ "$outcome" = "failure" ]; then + echo "::warning::Maestro e2e failed (burn-in mode: not failing the job). See the maestro-${{ matrix.platform }}-sdk${{ matrix.expo-sdk }} artifact." + fi diff --git a/.github/workflows/mobile-e2e.yml b/.github/workflows/mobile-e2e.yml deleted file mode 100644 index 5c75f37af06..00000000000 --- a/.github/workflows/mobile-e2e.yml +++ /dev/null @@ -1,247 +0,0 @@ -# Manual mobile e2e for @clerk/expo native components. -# Clones clerk-expo-quickstart, builds the NativeComponentQuickstart app, -# and runs Maestro flows on iOS simulator and Android emulator. -# -# Secrets: -# INTEGRATION_STAGING_INSTANCE_KEYS — JSON map of named staging test instances -# ({ "": { "pk": "pk_test_...", "sk": "sk_test_..." } }). -# Same secret used by /integration (Playwright) staging jobs. We read the -# entry named EXPO_INSTANCE_NAME (set in env: below). -# -# Test users are provisioned per-run via Clerk Backend API and deleted at -# teardown — same pattern as /integration's createBapiUser. -name: "Mobile e2e (@clerk/expo)" - -on: - workflow_dispatch: - inputs: - quickstart_ref: - description: "clerk-expo-quickstart git ref (branch, tag, or SHA)" - required: false - default: "main" - exclude_tags: - description: "Maestro tags to exclude (comma-separated)" - required: false - default: "manual,skip" - -env: - EXPO_INSTANCE_NAME: clerkstage-with-native-components - -concurrency: - group: mobile-e2e-${{ github.ref }} - cancel-in-progress: true - -jobs: - android: - name: Android - runs-on: 'blacksmith-8vcpu-ubuntu-2204' - timeout-minutes: 45 - defaults: - run: - working-directory: . - steps: - - name: Checkout @clerk/javascript - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - with: - persist-credentials: false - - - name: Checkout clerk-expo-quickstart - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - with: - persist-credentials: false - repository: clerk/clerk-expo-quickstart - ref: ${{ inputs.quickstart_ref }} - path: clerk-expo-quickstart - - - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 - with: - node-version: 20 - cache: pnpm - - - name: Install monorepo deps - run: pnpm install --frozen-lockfile - - - name: Build @clerk/expo - run: pnpm turbo build --filter=@clerk/expo... - - - name: Install quickstart deps - working-directory: clerk-expo-quickstart/NativeComponentQuickstart - run: pnpm install - - - name: Resolve Clerk instance keys - id: keys - env: - INTEGRATION_STAGING_INSTANCE_KEYS: ${{ secrets.INTEGRATION_STAGING_INSTANCE_KEYS }} - run: node scripts/resolve-instance-keys.mjs INTEGRATION_STAGING_INSTANCE_KEYS "$EXPO_INSTANCE_NAME" - - - name: Write quickstart .env - working-directory: clerk-expo-quickstart/NativeComponentQuickstart - run: | - echo "EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=${{ steps.keys.outputs.pk }}" > .env - - - name: Provision test user via BAPI - id: user - env: - CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} - run: | - email="ci-${GITHUB_RUN_ID}-${RANDOM}+clerk_test@clerkcookie.com" - password="ClerkCI!$(openssl rand -hex 8)Aa1" - response=$(curl -fsS -X POST https://api.clerk.com/v1/users \ - -H "Authorization: Bearer $CLERK_SECRET_KEY" \ - -H "Content-Type: application/json" \ - -d "{\"email_address\":[\"$email\"],\"password\":\"$password\"}") - user_id=$(echo "$response" | jq -er '.id') - echo "::add-mask::$password" - echo "email=$email" >> "$GITHUB_OUTPUT" - echo "password=$password" >> "$GITHUB_OUTPUT" - echo "user_id=$user_id" >> "$GITHUB_OUTPUT" - - - name: Set up JDK 17 - uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 - with: - distribution: temurin - java-version: 17 - - - name: Install Maestro - run: | - curl -Ls "https://get.maestro.mobile.dev" | bash - echo "$HOME/.maestro/bin" >> "$GITHUB_PATH" - - - name: Run Android e2e - uses: reactivecircus/android-emulator-runner@e89f39f1abbbd05b1113a29cf4db69e7540cae5a # v2 - env: - CLERK_TEST_EMAIL: ${{ steps.user.outputs.email }} - CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }} - EXCLUDE_TAGS: ${{ inputs.exclude_tags }} - with: - api-level: 34 - target: google_apis - arch: x86_64 - script: | - cd clerk-expo-quickstart/NativeComponentQuickstart - npx expo prebuild --clean - npx expo run:android --variant release --no-bundler - cd ../../integration-mobile - # Maestro doesn't auto-recurse into subdirectories; pass each flow explicitly. - find flows -type f -name "*.yaml" ! -path "*/common/*" -print0 | \ - xargs -0 maestro test --exclude-tags "$EXCLUDE_TAGS" - - - name: Upload Maestro artifacts on failure - if: failure() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 - with: - name: maestro-android - path: ~/.maestro/tests - - - name: Cleanup test user - if: always() && steps.user.outputs.user_id != '' - env: - CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} - USER_ID: ${{ steps.user.outputs.user_id }} - run: | - curl -fsS -X DELETE "https://api.clerk.com/v1/users/$USER_ID" \ - -H "Authorization: Bearer $CLERK_SECRET_KEY" || true - - ios: - name: iOS - runs-on: macos-15 - timeout-minutes: 60 - steps: - - name: Checkout @clerk/javascript - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - with: - persist-credentials: false - - - name: Checkout clerk-expo-quickstart - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - with: - persist-credentials: false - repository: clerk/clerk-expo-quickstart - ref: ${{ inputs.quickstart_ref }} - path: clerk-expo-quickstart - - - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 - with: - node-version: 20 - cache: pnpm - - - name: Install monorepo deps - run: pnpm install --frozen-lockfile - - - name: Build @clerk/expo - run: pnpm turbo build --filter=@clerk/expo... - - - name: Install quickstart deps - working-directory: clerk-expo-quickstart/NativeComponentQuickstart - run: pnpm install - - - name: Resolve Clerk instance keys - id: keys - env: - INTEGRATION_STAGING_INSTANCE_KEYS: ${{ secrets.INTEGRATION_STAGING_INSTANCE_KEYS }} - run: node scripts/resolve-instance-keys.mjs INTEGRATION_STAGING_INSTANCE_KEYS "$EXPO_INSTANCE_NAME" - - - name: Write quickstart .env - working-directory: clerk-expo-quickstart/NativeComponentQuickstart - run: | - echo "EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=${{ steps.keys.outputs.pk }}" > .env - - - name: Provision test user via BAPI - id: user - env: - CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} - run: | - email="ci-${GITHUB_RUN_ID}-${RANDOM}+clerk_test@clerkcookie.com" - password="ClerkCI!$(openssl rand -hex 8)Aa1" - response=$(curl -fsS -X POST https://api.clerk.com/v1/users \ - -H "Authorization: Bearer $CLERK_SECRET_KEY" \ - -H "Content-Type: application/json" \ - -d "{\"email_address\":[\"$email\"],\"password\":\"$password\"}") - user_id=$(echo "$response" | jq -er '.id') - echo "::add-mask::$password" - echo "email=$email" >> "$GITHUB_OUTPUT" - echo "password=$password" >> "$GITHUB_OUTPUT" - echo "user_id=$user_id" >> "$GITHUB_OUTPUT" - - - name: Cache SPM - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 - with: - path: ~/Library/Developer/Xcode/DerivedData - key: spm-${{ hashFiles('packages/expo/package.json') }} - - - name: Install Maestro - run: | - curl -Ls "https://get.maestro.mobile.dev" | bash - echo "$HOME/.maestro/bin" >> "$GITHUB_PATH" - - - name: Build and run iOS e2e - env: - CLERK_TEST_EMAIL: ${{ steps.user.outputs.email }} - CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }} - EXCLUDE_TAGS: ${{ inputs.exclude_tags }} - run: | - cd clerk-expo-quickstart/NativeComponentQuickstart - npx expo prebuild --clean - npx expo run:ios --configuration Release --no-bundler - cd ../../integration-mobile - # Maestro doesn't auto-recurse into subdirectories; pass each flow explicitly. - find flows -type f -name "*.yaml" ! -path "*/common/*" -print0 | \ - xargs -0 maestro test --exclude-tags "$EXCLUDE_TAGS,androidOnly" - - - name: Upload Maestro artifacts on failure - if: failure() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 - with: - name: maestro-ios - path: ~/.maestro/tests - - - name: Cleanup test user - if: always() && steps.user.outputs.user_id != '' - env: - CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} - USER_ID: ${{ steps.user.outputs.user_id }} - run: | - curl -fsS -X DELETE "https://api.clerk.com/v1/users/$USER_ID" \ - -H "Authorization: Bearer $CLERK_SECRET_KEY" || true diff --git a/integration/templates/expo-native/App.tsx b/integration/templates/expo-native/App.tsx index 4d549077e3e..1f824007263 100644 --- a/integration/templates/expo-native/App.tsx +++ b/integration/templates/expo-native/App.tsx @@ -11,7 +11,7 @@ if (!publishableKey) { } function NativeBuildFixture() { - const { isLoaded, isSignedIn } = useAuth({ treatPendingAsSignedOut: false }); + const { isLoaded, isSignedIn, signOut } = useAuth({ treatPendingAsSignedOut: false }); const { user } = useUser(); const [isAuthOpen, setIsAuthOpen] = useState(false); @@ -25,9 +25,17 @@ function NativeBuildFixture() { {isLoaded ? `signed ${isSignedIn ? 'in' : 'out'}` : 'loading'} {user?.id && {user.id}}