diff --git a/.changeset/expo-native-use-settings.md b/.changeset/expo-native-use-settings.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/expo-native-use-settings.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.claude/skills/verify-clerk-expo/SKILL.md b/.claude/skills/verify-clerk-expo/SKILL.md index 1bb6e4c1514..cb7dcb56b67 100644 --- a/.claude/skills/verify-clerk-expo/SKILL.md +++ b/.claude/skills/verify-clerk-expo/SKILL.md @@ -11,7 +11,7 @@ The tests are an ordinary e2e project. `e2e.config.ts` and `specs/` run under `n No change to `@clerk/expo` or `@clerk/expo-native-components` UI or auth behavior is done until a simulator or emulator shows the changed behavior, on each platform the change touches. A `run` on the test app is one way to show it. An app of your own that exercises the change is just as good. -Run every command from the repo root. In the prose below, `doctor`, `up`, `run`, `screen`, `attach`, and `down` are verbs of that CLI. The tests and the CLI are the Node package `integration/expo-native/`, and paths that begin `specs/`, `src/`, `test/`, or `.verify/` are inside it. `features/` and `references/` are beside this file. Every verb but `attach` takes `--platform ios|android`, and iOS is the default. Every error prints a `fix` line. Every verb takes `--json`, and [CLI output](references/output.md) has its shape, the exit codes, and the error codes. +Run every command from the repo root. In the prose below, `doctor`, `up`, `run`, `screen`, `attach`, `down`, and `settings` are verbs of that CLI. The tests and the CLI are the Node package `integration/expo-native/`, and paths that begin `specs/`, `src/`, `test/`, or `.verify/` are inside it. `features/` and `references/` are beside this file. Every verb but `attach` and `settings` takes `--platform ios|android`, and iOS is the default. Every error prints a `fix` line. Every verb takes `--json`, and [CLI output](references/output.md) has its shape, the exit codes, and the error codes. The test app links `@clerk/expo`, `@clerk/expo-native-components`, `@clerk/expo-biometrics`, and `@clerk/expo-google-signin` from the workspace. It does not install `@clerk/expo-passkeys`, so the skill cannot verify passkeys. @@ -61,7 +61,7 @@ The package is outside the pnpm workspace, so `npm ci` installs its pinned `e2e` On a local device a JS change in `packages/expo/src` or in the test app reaches the app with no build. A JS change in `packages/expo-native-components/src`, where AuthView, UserButton, and UserProfileView are, makes the next `up` or `run` rebuild that package first. Before the specs start, `run` waits until the watch build has caught up and Metro serves the current code, and it fails with `NOT_READY` and the path of the Metro log when Metro never does. [How a change reaches the app](references/freshness.md) has the native inputs, the checks, the ports, and the logs. It also says what to do after a change to another workspace package, such as `@clerk/clerk-js` or `@clerk/shared`. While Metro runs, never run `pnpm --filter @clerk/expo build` or a build of a package that `@clerk/expo` depends on, because the build deletes the `dist` that Metro serves. -A worktree can hold one lane of each platform. The two lanes share the watch build and the application, and each has its own Metro. Run them one after the other. The application serves one run at a time, because a run can change its settings. A `run` that starts while a run on the other platform is driving leases its device and then fails with `DEVICE_BUSY`, and its fix is to let that run finish and rerun. +A worktree can hold one lane of each platform. The two lanes share the watch build and the application, and each has its own Metro. Run them one after the other. The application serves one run at a time, because a test in a run can change its settings. A `run` that starts while a run on the other platform is driving leases its device and then fails with `DEVICE_BUSY`, and its fix is to let that run finish and rerun. A Mac has four iOS lanes and two Android lanes, shared by every worktree on it. When all are taken, `up` and `run` fail with `POOL_FULL`, and `--wait ` on either verb waits for a lane. The CLI drives only the simulators and emulators that it creates. [Local devices](references/devices.md) says how to find a lane's UDID or serial. @@ -112,7 +112,7 @@ $ integration/expo-native/bin/control-clerk-expo run native-auth-view native-js- $ integration/expo-native/bin/control-clerk-expo screen --platform ios # the UI tree that is on screen now; --png adds a screenshot ``` -`run --all` runs every committed spec. `run` also takes `--grep `, `--retries `, `--max-failures `, `--no-video`, and `--wait `. `--retries ` runs a test again, up to `n` more times, when an assertion failed, the test threw an error, or the test ran out of time. A test that e2e reports as a machine failure, such as an `ENGINE_FAILURE` when an `open` or a screenshot times out in agent-device, gets one attempt whatever `n` is. A driver error e2e reports as a test error, such as a stale node or an action that timed out, is retried like any other. The default is 0, so a run of your own change shows exactly what happened. `--max-failures ` stops a settings group once `n` of its tests have failed. A test that the limit stopped before it started prints `FAIL` with `not run: failure-limit`, and `run` exits 1. Without the flag, a run has no limit. The wait covers a free lane and another `run` in this worktree that holds the device. A spec limited to one platform with `test(title, { platforms: ['ios'] }, fn)` reports as skipped on the other. +`run --all` runs every committed spec. `run` also takes `--grep `, `--retries `, `--max-failures `, `--no-video`, and `--wait `. `--retries ` runs a test again, up to `n` more times, when an assertion failed, the test threw an error, or the test ran out of time. A test that e2e reports as a machine failure, such as an `ENGINE_FAILURE` when an `open` or a screenshot times out in agent-device, gets one attempt whatever `n` is. A driver error e2e reports as a test error, such as a stale node or an action that timed out, is retried like any other. The default is 0, so a run of your own change shows exactly what happened. `--max-failures ` stops the run once `n` of its tests have failed. A test that the limit stopped before it started prints `FAIL` with `not run: failure-limit`, and `run` exits 1. Without the flag, a run has no limit. The wait covers a free lane and another `run` in this worktree that holds the device. A spec limited to one platform with `test(title, { platforms: ['ios'] }, fn)` reports as skipped on the other. For a JS change on a local device, edit the source and `run` the spec, with no `up` in between. For a change to a native input, the same `run` rebuilds the dev client first. On a remote device, commit and push, then `run`. @@ -156,7 +156,7 @@ The test app has a screen or a small flow of its own only where the native views On iOS, locate nodes of the native views with the SDK's identifiers, such as `screen.getByTestId('clerk.auth.start.identifier')`. The clerk-android release that `@clerk/expo-native-components` pins sets the same `clerk.*` names as resource ids, but `specs/native.ts` still finds the Android native views by text. The home has `e2e.*` testIDs, which `host.app` holds, and the test app's other screens have `verify.*` testIDs, on both platforms. All of these identifiers are internal test hooks, not public API, and they can change. Every spec keeps at least one exact assertion on an identifier or on visible text. To assert on the text of a node, use `await expect(locator).toHaveText('...')`. -A spec file that needs other settings than the standard ones has a settings file beside it, with the same name and `.settings.json` in place of `.e2e.ts`. `run` puts the application on those settings before the tests in that spec file start. Any other JSON file under `specs/` stops every run. [Test instances](references/instances.md) has the rules for a declaration. +Every test starts on the standard settings. A test that needs other settings calls `host.useSettings({ config, environment? })`, and the CLI puts every leaf it changed back when the test ends. [Test instances](references/instances.md) has the call, the restore, and the leaves that tests often change. To see which settings are on or off, run `integration/expo-native/bin/control-clerk-expo settings `, such as `settings auth_multi_factor`. ### Check your work @@ -184,7 +184,7 @@ Every `run` writes `.verify/runs//` and prints its path. | File | What it holds | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `run.json` | The record: `results` per spec, `platform`, `backend`, `gitHead`, `dirty`, `build`, `device`, `identities`, `settings`, and `tainted` | +| `run.json` | The record: `results` per spec, `platform`, `backend`, `gitHead`, `dirty`, `build`, `device`, `identities`, `settings` (one entry per `host.useSettings` call), and `tainted` | | `video.mp4` | The run, from the first `host.launch` to the end, recorded by `simctl io recordVideo` on iOS or `adb shell screenrecord` on Android. Just before that launch, `run` closes the app and starts the recorder, so the video opens on the device's home screen for a moment and then on the app being launched. A run in which no test calls `host.launch` has no video, and `run` prints a `video` line that says so | | `evidence-marks.jsonl` | When each `host.evidence` block started and ended, and when and where each `host.tap` and `host.fill` tapped, in a run that records evidence. `run.json` keeps them as `evidenceSpans` and `evidenceTaps`, in seconds of the video | | `video-cut.mp4` | What `attach --video` last posted for this run: the marked part of `video.mp4`. `video.mp4` stays as recorded | @@ -192,7 +192,7 @@ Every `run` writes `.verify/runs//` and prints its path. | `app.log` | Device log lines. On Android they include the app's `[verify]` console lines. On a local iOS device they are native lines only, and the `[verify]` lines are in `.verify/runtime/metro-.log`. The test app writes one `[verify]` line each time its screen, user, session, or launch error changes, with the `launchId` that a failed `host.launch` names. No spec reads these lines. They are for diagnosing a failure that the screen does not explain | | `e2e/`, `e2e.log` | e2e's `report.json` and `junit.xml`, its failure pages, and its console output | | `driver/` | `summary.txt`, which says what agent-device state the run found and what it copied, and the part of agent-device's `daemon.log`, and on iOS of the XCTest runner's `runner.log`, that the run added. The copies leave out typed text. They are for a failure that the driver caused, such as a daemon that did not start or a screen read that hung | -| `specs/` | A copy of every spec the run used, with its settings file when it has one | +| `specs/` | A copy of every spec the run used | A proof drives the real user path. The video and the screenshots show the action and its result as a user sees them. It checks side effects where the app shows them, such as the user ID and the session ID on the home, not only that the last screen appeared. @@ -233,7 +233,7 @@ To make the before run, `run` the spec of your change on the build without the c For screenshots, show each screen the change touches, and each state of a screen that it touches, in a before and after of its own. That includes a state the change should leave as it was, because its pair shows that it did. Write one spec file with one test per state, each ending in its own `host.screenshot(label)`. On each platform you show, run it once without the change and once with it, and pass every label to one `attach`, one `--screenshot