Skip to content

ci(e2e): Add Expo native E2E testing#9186

Draft
wobsoriano wants to merge 6 commits into
mainfrom
rob/mobile-593-maestro-tests
Draft

ci(e2e): Add Expo native E2E testing#9186
wobsoriano wants to merge 6 commits into
mainfrom
rob/mobile-593-maestro-tests

Conversation

@wobsoriano

@wobsoriano wobsoriano commented Jul 16, 2026

Copy link
Copy Markdown
Member

Description

This PR adds E2E coverage for our @clerk/expo SDK (finally!) using Maestro.

Each flow is a single scenario, and every native interaction is followed by an assertion that the JS layer observed it, so the native-to-JS session sync (and the reverse) is what's actually under test:

  • sign-in.yaml: signs in through the native AuthView with email + password, asserts the JS side sees the session (useAuth state and user id rendered by the fixture), then signs out from the JS side and asserts the native session is gone.

  • session-persists-across-restart.yaml: signs in, fully kills and relaunches the app without clearing state, and asserts the session is restored from secure-store with no re-auth.

  • authview-detach-reattach.yaml: opens the AuthView, dismisses it with the platform-native gesture (Android back button, iOS sheet close), reopens it, and completes a full sign-in on the remounted view.

  • user-button-sign-out-re-sign-in.yaml: opens the UserButton account sheet, signs out natively, asserts JS observes it, then signs in again in the same app process.

Cold launch and initialization are exercised implicitly.

Rather than a new workflow, this reuses the existing expo-native-build.yml: the SDK 57 matrix entries get run-e2e: true and run the Maestro suite after their normal fixture build. If we want e2e on other SDK versions later, it's just a matter of adding the same flag to their matrix entries.

Summary by CodeRabbit

  • New Features

    • Added end-to-end authentication coverage for Expo Native sign-in and sign-out flows on iOS and Android.
    • Added visible sign-in and sign-out controls to the Expo Native test fixture.
    • Added a dedicated command for running Expo Native integration tests.
  • Bug Fixes

    • Improved mobile test reliability with app warmup, retries, state cleanup, and diagnostic artifacts.

@changeset-bot

changeset-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4b3447f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Jul 17, 2026 8:07am
swingset Ready Ready Preview, Comment Jul 17, 2026 8:07am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 0736cd8e-7ba4-46a9-af77-7516203fd0e2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Expo Native integration testing was added with Maestro flows, fixture authentication controls, a retrying flow runner, and iOS/Android CI execution. The workflow provisions temporary credentials, captures diagnostics, and cleans up test users.

Changes

Expo Native E2E

Layer / File(s) Summary
Fixture authentication and Maestro flows
integration/templates/expo-native/*, integration/tests/expo-native/config.yaml, integration/tests/expo-native/flows/*
The fixture now exposes authentication test IDs and sign-out behavior. Maestro flows cover app startup, email/password sign-in, signed-in assertions, and signed-out assertions.
Maestro flow runner
integration/tests/expo-native/run-flows.sh, package.json
A new runner validates required environment variables, warms up the app, retries each flow once, and returns the aggregated result through a package script.
iOS and Android CI execution
.github/workflows/expo-native-build.yml, .changeset/new-queens-brake.md
The workflow provisions temporary E2E users, builds and runs the fixture on both platforms, uploads failure artifacts, reports results, and deletes the temporary user. The workflow also validates the packaged Expo artifact and triggers for Expo Native test changes.

Estimated code review effort: 4 (Complex) | ~45 minutes

Suggested labels: expo

Poem

A bunny taps sign-in, then hops out with care,
Maestro checks sessions are flowing everywhere.
iOS and Android both follow the trail,
With retries and screenshots when tests fail.
The test user is cleaned from the burrow at night.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding Expo native E2E testing to CI.

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9186

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9186

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9186

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9186

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9186

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9186

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9186

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9186

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9186

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9186

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9186

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9186

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9186

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9186

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9186

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9186

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9186

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9186

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9186

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9186

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9186

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9186

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9186

commit: 4b3447f

@macroscopeapp

macroscopeapp Bot commented Jul 17, 2026

Copy link
Copy Markdown

Approvability

Verdict: Approved

This PR adds CI/e2e testing infrastructure (Maestro flows, workflow updates) for Expo native components. All changes are confined to test fixtures, test files, and GitHub workflows with no production code impact.

You can customize Macroscope's approvability policy. Learn more.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
integration/tests/expo-native/config.yaml (1)

8-11: 🩺 Stability & Availability | 🔵 Trivial

Configure animation suppression in the actual local device setup.

Maestro documents disableAnimations as cloud-only, while the runner executes local maestro test commands. These settings are therefore ignored in this CI path and will not reduce simulator/emulator flakiness. (docs.maestro.dev)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integration/tests/expo-native/config.yaml` around lines 8 - 11, Replace the
ineffective disableAnimations entries in the iOS and Android configuration with
the local device setup mechanism supported by the runner, ensuring animations
are disabled before local maestro test execution for both platforms. Remove the
cloud-only settings rather than retaining them as the suppression path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/expo-native-build.yml:
- Around line 118-129: Update the “Resolve Clerk instance keys” and “Provision
test user via BAPI” steps to stop masking setup failures with continue-on-error.
Ensure key-resolution or user-provisioning failures make the burn-in job fail or
are surfaced as the burn-in outcome, while retaining conditional skipping only
when fork secrets are unavailable.

In `@integration/tests/expo-native/flows/subflows/open-app.yaml`:
- Around line 10-12: Update the retry comments in open-app.yaml (lines 10-12)
and assert-signed-in.yaml (lines 1-2) to state that Maestro polls assertVisible
until its default 7-second timeout; remove wording that implies assertVisible
never retries. No other behavior changes are needed.

In `@integration/tests/expo-native/flows/subflows/sign-in-email-password.yaml`:
- Around line 14-28: Update the email/username input flow around the initial tap
in the sign-in subflow to call eraseText after focusing the field, matching the
password flow. Keep the conditional Select All handling if needed, but ensure
the persisted identifier is cleared unconditionally before inputText enters
CLERK_TEST_EMAIL.

---

Nitpick comments:
In `@integration/tests/expo-native/config.yaml`:
- Around line 8-11: Replace the ineffective disableAnimations entries in the iOS
and Android configuration with the local device setup mechanism supported by the
runner, ensuring animations are disabled before local maestro test execution for
both platforms. Remove the cloud-only settings rather than retaining them as the
suppression path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: c9312e4c-7110-4c0f-a075-501c5f38dc6a

📥 Commits

Reviewing files that changed from the base of the PR and between b37ba0d and d56a00a.

📒 Files selected for processing (15)
  • .changeset/new-queens-brake.md
  • .github/workflows/expo-native-build.yml
  • .github/workflows/mobile-e2e.yml
  • integration/templates/expo-native/App.tsx
  • integration/templates/expo-native/package.sdk-57.json
  • integration/tests/expo-native/.gitignore
  • integration/tests/expo-native/config.yaml
  • integration/tests/expo-native/flows/sign-in.yaml
  • integration/tests/expo-native/flows/subflows/_warmup.yaml
  • integration/tests/expo-native/flows/subflows/assert-signed-in.yaml
  • integration/tests/expo-native/flows/subflows/assert-signed-out.yaml
  • integration/tests/expo-native/flows/subflows/open-app.yaml
  • integration/tests/expo-native/flows/subflows/sign-in-email-password.yaml
  • integration/tests/expo-native/run-flows.sh
  • package.json
💤 Files with no reviewable changes (1)
  • .github/workflows/mobile-e2e.yml

Comment thread .github/workflows/expo-native-build.yml Outdated
Comment on lines +118 to +129
- 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: Provision test user via BAPI
id: user
if: steps.keys.outputs.pk != ''
continue-on-error: true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not silently convert E2E setup failures into skipped coverage.

If key resolution or user provisioning fails, the empty user ID skips every E2E and reporting step while the job succeeds. Reserve skipping for unavailable fork secrets; otherwise report the setup failure as the burn-in outcome or remove these continue-on-error settings.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/expo-native-build.yml around lines 118 - 129, Update the
“Resolve Clerk instance keys” and “Provision test user via BAPI” steps to stop
masking setup failures with continue-on-error. Ensure key-resolution or
user-provisioning failures make the burn-in job fail or are surfaced as the
burn-in outcome, while retaining conditional skipping only when fork secrets are
unavailable.

Comment on lines +10 to +12
# Text-only matching from here on: iOS failed combined id+text filters on RN
# Text elements in CI while id-only and text-only both match. Also wait out
# clerk-js init ('loading') with a retrying wait; assertVisible never retries.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '1,120p' integration/tests/expo-native/flows/subflows/open-app.yaml
printf '\n---\n'
sed -n '1,80p' integration/tests/expo-native/flows/subflows/assert-signed-in.yaml
printf '\n---\n'
rg -n "assertVisible|extendedWaitUntil|loading|text-only|id-only|combined id\\+text" integration/tests/expo-native -S

Repository: clerk/javascript

Length of output: 2017


🌐 Web query:

Maestro assertVisible retries default timeout documentation

💡 Result:

The default timeout for the assertVisible command in Maestro is 7 seconds [1][2]. When you call assertVisible, Maestro does not fail immediately if the element is not found [1][3]. Instead, it automatically waits and polls for the element to appear, retrying until it becomes visible or the 7-second timeout is reached [1][3]. If you need a longer wait time than the 7-second default, you should use the extendedWaitUntil command, which allows you to specify a custom timeout [1][4]. Key points: - Default Timeout: 7 seconds [1][2]. - Behavior: Continuous polling for the element's visibility until the timeout expires [3]. - Alternative: Use extendedWaitUntil for scenarios requiring a longer duration [1][4].

Citations:


Correct the assertVisible retry note. Maestro polls assertVisible until its 7-second default timeout, so the comments in integration/tests/expo-native/flows/subflows/open-app.yaml and integration/tests/expo-native/flows/subflows/assert-signed-in.yaml should say that instead of implying it never retries.

📍 Affects 2 files
  • integration/tests/expo-native/flows/subflows/open-app.yaml#L10-L12 (this comment)
  • integration/tests/expo-native/flows/subflows/assert-signed-in.yaml#L1-L2
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integration/tests/expo-native/flows/subflows/open-app.yaml` around lines 10 -
12, Update the retry comments in open-app.yaml (lines 10-12) and
assert-signed-in.yaml (lines 1-2) to state that Maestro polls assertVisible
until its default 7-second timeout; remove wording that implies assertVisible
never retries. No other behavior changes are needed.

Comment thread integration/tests/expo-native/flows/subflows/sign-in-email-password.yaml Outdated
Adds open-auth-view-button and sign-out-button testIDs to App.tsx so
Maestro can drive the JS layer deterministically, and ad-hoc signs the SDK
57 iOS simulator build (CODE_SIGN_IDENTITY=-): unsigned builds have no
application-identifier, which breaks Keychain/expo-secure-store and leaves
clerk-js loading forever.
Scenario-per-file flows under integration/tests/expo-native covering
native AuthView sign-in with native-to-JS session sync, session persistence
across restart, AuthView detach/reattach via platform-native dismissal, and
UserButton native sign-out followed by a same-process re-sign-in. Shared
steps (clean launch, email+password entry, signed-in/out assertions,
warmup) live in subflows/. run-flows.sh runs the suite locally via
pnpm test:integration:expo-native.
…kflow

Extends the existing expo-native-build matrix with run-e2e on the SDK 57
entries (other SDKs can opt in the same way), provisioning a throwaway BAPI
test user after the native build, running the Maestro suite in burn-in
mode (continue-on-error), cleaning the user up before uploading scrubbed
debug artifacts, and deleting the dead mobile-e2e workflow.
Which first factor follows the email step depends on instance config and
SDK: clerk-ios can present the email-code screen first where clerk-android
presents password first. The subflow now accepts either screen instead of
hard-gating on the password field, keeping password-then-code instances
working unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant