All examples

Testing Clerk's Android SDK with e2e

Sign-in, sign-up, MFA, and organization flows of Clerk's Android SDK in a Jetpack Compose host app, on an Android emulator.

Community examples aren't actively verified by the e2e team so exercise extra caution when running.

The tests in specs/ are an ordinary e2e project. e2e.config.ts and the files under specs/ run with npx e2e run when the environment names three things: a device, a build of the :e2e app, and a Clerk development instance.

The CLI in bin/ and src/ sits on top of that project. It makes those three things for a run, and it adds what a pull request needs. The tests never import the CLI. test/seam.test.ts fails when a file under specs/ or e2e.config.ts names a path outside specs/.

To prove a change, use the CLI. .claude/skills/verify-clerk-android/SKILL.md has the steps. Run a test by hand when you want e2e alone, for example to work on a test with e2e's own flags.

Run a test by hand

You need Node 24.8 or newer on 24, the Android SDK, JDK 21, and a running emulator, and the publishable key and secret key of a Clerk development instance.

Terminal
cd e2e-tests
npm ci
(cd .. && ./gradlew :e2e:assembleDebug)
adb devices
export CLERK_E2E_DEVICE=<the serial of a running emulator, from the list above, such as emulator-5554>
export CLERK_E2E_APP_PATH=../e2e/build/outputs/apk/debug/e2e-debug.apk
export CLERK_PUBLISHABLE_KEY=pk_test_...
export CLERK_SECRET_KEY=sk_test_...
npx e2e run specs/features/sign-in-email-code/complete.e2e.ts

--video on, --retries, --grep, and --output are e2e's own flags. e2e writes its report and its screenshots to .e2e/, which git ignores.

SettingNeededWhat it is
CLERK_E2E_DEVICEyesThe serial of a running emulator, as adb devices prints it, such as emulator-5554. Only an emulator-<port> serial is accepted. The name of an AVD, a host:port address, and the serial of a phone are refused.
CLERK_E2E_APP_PATHnoThe debug APK of :e2e. The first launch of a run installs it. Leave it unset when the app is already on the emulator.
CLERK_PUBLISHABLE_KEYyesThe pk_test_ key of a development instance.
CLERK_SECRET_KEYyesThe sk_test_ key of the same instance. The tests create users and sign-in tickets with it. A pk_live_ or sk_live_ key is refused.

The instance

The tests expect the settings in src/core/instances/base.json of @clerk/internal-mobile-e2e, which the CLI puts on the application it creates. On an instance with those settings, every test file that has no settings file beside it passes by hand.

An instance left at Clerk's defaults passes only part of the suite. The tests that sign in with a ticket, or sign up with an email address and a password, pass. The tests that need a phone number, an email code at sign-in, organizations, or a second account on the device fail, because a new instance has none of those turned on.

Every run creates users with addresses like maya.7c1e+clerk_test@example.com and never deletes them. The address is a first name and the last four characters of the run id, here r20261002-141210-7c1e. No two tests of a run on one machine get the same name. A development instance holds 100 users. Use an instance that you can empty.

Test files that need the CLI

These test files have a .settings.json file beside them, and pass only on an instance with those settings:

  • specs/features/session-tasks/choose-organization.e2e.ts
  • specs/features/session-tasks/complete-setup-mfa.e2e.ts
  • specs/features/session-tasks/setup-mfa.e2e.ts
  • specs/features/session-tasks/sign-up-setup-mfa.e2e.ts

The CLI's run puts the instance on the declared settings before the file starts, and e2e alone does not. Run them through the CLI, for example e2e-tests/bin/control-clerk-android run session-tasks from the repo root.

What a run by hand does not do

  • It creates no Clerk application, changes no instance settings, and replaces no instance that is filling up.
  • It leases and locks no device. Run one test process per device at a time.
  • It does not rebuild the app when the sources change.
  • It records no video of the whole run. --video on records one per attempt.
  • It keeps no sealed run directory, scans nothing for secrets, redacts no log, and posts nothing to a pull request.
  • It leaves the agent-device daemon that e2e started running. npx agent-device daemon stop stops it.

Layout

  • e2e.config.ts and specs/ are the e2e project. specs/features/ has the tests, specs/fixtures.ts has the host fixture they use, specs/app.ts names the test app, and @clerk/internal-mobile-e2e/specs/support/ is the tests' support code. Its inputs.ts is the only file that reads the settings above.
  • bin/ and src/ are the CLI. Under the CLI the test process gets the same settings, with one difference: in place of the secret key it gets the address and token of a stand-in that the CLI runs on this machine. The stand-in forwards the three Backend API calls the tests make, for this run's test users only, so the test process never holds the key.
  • test/ has the unit tests of both. npm test runs them, with no device, key, or network.
  • The CLI core and the test support code are the package @clerk/internal-mobile-e2e, which clerk-ios and clerk/javascript also use. package.json pins it to a commit of clerk/internal-mobile-e2e, and .npmrc lets npm install it from git.