e2e ยท diff
git:20260815.5a2e1cd to git:20261007.4ac807e
131 added, 101 removed. Audit A to B.
---
name: e2e
- description: Run Release Catalog OTA verification for `examples/v0.85.0` with the route-based example and `agent-device`. Use for release builds, Release/Bundle selection, catalog policy, artifact install, rollout, runtime channels, and crash recovery.
+ description: Agentic end-to-end tests with e2e, the e2e runner. Covers scaffolding e2e.config.ts, picking the Playwright browser engine or the agent-device mobile engine, starting the app under test from the config, driving flows with agent.act, judging with agent.assert, agent.waitFor, and agent.extract, pinning values with screen, app, browser, and expect, shaping the agent (context, system prompt, tools, personas), the replay cache, the e2e CLI, reading .e2e/report.json, and bug bashes (parallel explore runs proven with repro tests). Use when a project depends on e2e, when asked for end-to-end, browser, mobile, or agentic UI tests, to bug bash or hunt for bugs, or when an e2e run fails.
---
- # Hot Updater V0.85 Release Catalog E2E
-
- Use this skill only for `examples/v0.85.0`. Always load and follow
- [$agent-device](../agent-device/SKILL.md), then read
- [references/runtime-targets.md](references/runtime-targets.md).
-
- The caller supplies the scenario. Keep its intent and choose assertions at the
- correct identity layer: Release for selection/policy, Bundle for bytes,
- patches, manifests, storage, and crash history.
-
- ## Rules
+ # e2e: agentic end-to-end tests in TypeScript
- - Run iOS and Android sequentially with release binaries. Never overlap runs or
- validate through Metro/debug builds.
- - Run `pnpm -w build` and rebuild the native app after native package changes.
- - Deploy only through `pnpm hot-updater deploy`; never seed Bundle or Release
- rows directly.
- - Capture both `bundleId` and the Release created for it. The Bundle ID remains
- available in `dist/manifest.json`; resolve the Release through `hot-updater
- release list/show --json` or the Detox deploy result.
- - Use `agent-device snapshot -i`; use screenshots only when asked.
- - Public launch statuses are exactly `UNCHANGED | UPDATE_APPLIED | RECOVERED`.
- Directional identity is `fromReleaseId`, `fromBundleId`, `toReleaseId`, and
- `toBundleId`. Do not expect `STABLE`, `PROMOTED`, or `crashedBundleId`.
- - `notifyAppReady` is read-only. It must not affect crash detection, rollback,
- or receipt promotion.
- - Crash bundles must throw at module scope. Do not use `useEffect`, component
- rendering, or a UI action for the crash.
+ e2e runs UI tests with agent goals and exact assertions. `agent.act` drives
+ one goal; `agent.assert`, `agent.waitFor`, and `agent.extract` judge the
+ screen. `screen`, `app`, `browser`, and `expect` make exact interactions and
+ checks. The replay cache reruns verified actions and checks their recorded end
+ state without a model call; agent judgments still run live. UI targets use
+ `@e2e-dev/web` for browsers or `@e2e-dev/mobile` for iOS simulators,
+ Android emulators, and connected phones. A test that takes only `app` can check an API with `fetch`
+ and `expect` (topic `writing-tests`). Model sign-in commands are in
+ [setup](references/setup.md#subscriptions-and-api-keys).
- ## Fixed Targets And Build Commands
+ ```ts
+ // e2e.config.ts
+ import type { E2EConfig } from 'e2e';
+ import { web } from '@e2e-dev/web';
+ import { gateway } from 'ai';
- Use the exact commands and app identifiers in `references/runtime-targets.md`.
- The standalone server readiness URL is
- `http://localhost:3007/hot-updater/version`.
+ export default {
+ targets: [
+ {
+ engine: web(),
+ app: {
+ url: 'http://127.0.0.1:3000',
+ command: { executable: 'pnpm', args: ['dev'], log: '.e2e/logs/app.log' },
+ },
+ },
+ ],
+ // The model behind every agent.* step: an AI SDK instance; gateway() from 'ai' reads AI_GATEWAY_API_KEY or a Vercel OIDC token.
+ agents: {
+ default: {
+ model: gateway('openai/gpt-6-luna-fast'),
+ system: 'You are a thorough QA agent. Verify every outcome on screen.',
+ },
+ },
+ } satisfies E2EConfig;
+ ```
- Deploy from `<repo-root>/examples/v0.85.0`:
+ ```ts
+ // tests/billing.e2e.ts
+ import { test } from '@e2e-dev/web';
+ import { expect } from 'e2e';
- ```bash
- pnpm hot-updater deploy -p ios -t 1.0.x
- pnpm hot-updater deploy -p android -t 1.0.x
+ test('a member upgrades to Pro', async ({ app, agent, screen, browser }) => {
+ await app.open('/settings/billing');
+ await agent.act('upgrade the workspace to the Pro plan');
+ await expect(screen.getByRole('status')).toContainText('Pro');
+ await expect(browser).toHaveURL('/settings/billing');
+ });
```
- ## Route-Based Example Contract
+ ## Topics
- The example has one focused target per deep-link route. Open the route that
- owns the assertion and take a fresh snapshot; do not search a scroll-heavy
- main page.
+ Read the topic for the job before writing code. The files sit next to this
+ one; the installed CLI prints the same text with `npx e2e guide <topic>`
+ (`e2e guide` alone prints this page). For anything the topics do not cover,
+ the full documentation ships in the `docs/` directory of the installed `e2e`
+ package (`node_modules/e2e/docs` in a single-package project); a link such as
+ `/reference/cli` is `docs/reference/cli.mdx`. Complete projects for Vite,
+ Next.js, Expo, and SwiftUI, each with its config, scripts, and a passing
+ suite, are in https://github.com/tester-army/e2e/tree/main/examples.
- | Evidence | Deep link | testID |
+ | Topic | File | Read it when |
| --- | --- | --- |
- | Bundle identity | `hotupdaterexample://e2e/runtime-bundle` | `runtime-bundle-id` |
- | Release receipt, selection kind, authority, scope, generation, high-water, channel, context | `hotupdaterexample://e2e/runtime-release-state` | `runtime-release-state` |
- | Manifest bytes | `hotupdaterexample://e2e/runtime-large-asset` | `runtime-large-e2e-asset` |
- | Scenario marker | `hotupdaterexample://e2e/runtime-marker` | `runtime-scenario-marker` |
- | Launch status | `hotupdaterexample://e2e/launch-status` | `launch-status-result` |
- | Directional launch IDs | `hotupdaterexample://e2e/launch-transition` | `launch-transition-result` |
- | Crash history count | `hotupdaterexample://e2e/crash-history-count` | `crash-history-count` |
- | Install current channel | `hotupdaterexample://e2e/action/install-current-channel-update` | `action-install-current-channel-update` |
- | Install runtime channel | `hotupdaterexample://e2e/action/install-runtime-channel-update` | `action-install-runtime-channel-update` |
- | Update action result | `hotupdaterexample://e2e/update-action-result` | `update-action-result` |
-
- The action text distinguishes `installed Release <R> / Bundle <B>`, `adopted
- Release <R> / Bundle <B>`, `selected EMBEDDED Release <R>`, `selected
- BUILTIN`, `no-update`, and `skipped`.
-
- ## Detox Control Contract
-
- When driving the repository harness, use:
-
- - deploy: `POST /e2e/jobs/deploy-bundle`, returning `bundleId`, `releaseId`,
- `authorityId`, `scopeKey`, and `generation`;
- - Release policy: `POST /e2e/jobs/patch-release` with `releaseId`;
- - rollout samples: `POST /e2e/compute-rollout-sample` with `releaseId`;
- - Bundle artifact assertions: keep using Bundle IDs;
- - metadata waits/assertions: require Release receipts and catalog high-water;
- - launch reports: assert directional Release and Bundle IDs;
- - proxy controls: `/e2e/proxy-control`, `/e2e/proxy-state`, and
- `/e2e/assert-proxy` for counts, exact-generation capture/freeze/replay, path
- cardinality, zero-artifact assertions, and catalog/artifact delays.
+ | `setup` | [references/setup.md](references/setup.md) | Adding e2e to a project, writing `e2e.config.ts`, starting the app from the config, mobile targets |
+ | `writing-tests` | [references/writing-tests.md](references/writing-tests.md) | Writing or fixing tests: fixtures, locators, actions, matchers, sign-in sessions, the `browser` fixture |
+ | `agent` | [references/agent.md](references/agent.md) | Adding `agent.*` steps, picking a model, cost and budgets, the replay cache |
+ | `running` | [references/running.md](references/running.md) | CLI flags, reporters, `.e2e/report.json`, exit codes, CI |
+ | `explore` | [references/explore.md](references/explore.md) | Exploring an app toward a goal without a test file: `e2e explore`, its budgets, verdict, and `run.explore` |
+ | `debugging` | [references/debugging.md](references/debugging.md) | A run failed: error codes and their fixes, `--headed`, `--debug`, `--ai-trace` |
+ | `mcp` | [references/mcp.md](references/mcp.md) | Driving the live app from a coding agent over MCP: `e2e mcp`, its tools, and the explore-then-write loop |
+ | `bug-bash` | [references/bug-bash.md](references/bug-bash.md) | Asked to bug bash, QA, or hunt for bugs across an app or a branch: parallel `e2e explore` charters, merging findings, proving each with a repro test |
- Catalog URLs are shared scope URLs and must not contain current/minimum Release
- or Bundle IDs, install ID, cohort, or crash state.
+ ## Workflow
- ## Assertions
+ 1. Look at what exists: `e2e.config.ts` or `e2e.config.mts`, the `tests` glob
+ (default `tests/**/*.e2e.ts`), `e2e` in `package.json`. Nothing there:
+ follow `setup`.
+ 2. Learn the screens before writing a test: routes, labels, roles, button
+ text. Semantic locators need the accessible names the app renders, so read
+ the components, open the page with `--headed`, or drive the live app over
+ the registered `e2e mcp` server (topic `mcp`): `open_session`, `observe`,
+ and `locate` show exact names and check a locator before you write it.
+ 3. Write `tests/<feature>.e2e.ts`. Drive the flow with `agent.act`, one goal
+ per call, and pin each outcome right after with `expect` or `agent.assert`.
+ Exact values go through `screen`: a sign-in form in a setup test, a field
+ that must receive one specific string, a count that must be one number.
+ 4. Run one file: `npx e2e run tests/<feature>.e2e.ts`. Agent steps need a
+ model in the config and that provider's authentication (a saved
+ subscription login, an API key); a local endpoint may need none. Tests
+ without agent steps need no model.
+ 5. Read the failure: the reporter prints the error code, message, and a code
+ frame; `.e2e/report.json` has every step and artifact path. Fix the
+ locator, the expectation, or the app. Never add a sleep.
- - Assert Release ID plus receipt fields for selection or policy behavior.
- - Assert Bundle ID plus manifest/storage evidence for byte behavior.
- - For same-Bundle adoption, assert a new Release receipt, no artifact request,
- and no reload.
- - For BUILTIN/EMBEDDED, assert the persisted selection kind and full receipt;
- Bundle slots may be empty.
- - For crash recovery, assert Bundle-keyed crash history, full restored receipt,
- retained high-water, and directional Release+Bundle launch report.
- - For rollout/target changes, keep the Release ID stable while catalog
- generation advances and local context selection changes.
- - For force update, observe the configured automatic reload; do not tap a
- manual install/reload action.
+ ## Rules
- ## Crash Patch Pattern
+ - Run the CLI as `npx e2e ...` (or `pnpm exec e2e ...`).
+ - The config is `export default { ... } satisfies E2EConfig` with
+ `import type { E2EConfig } from 'e2e'`. `targets` is required; a UI target
+ names an engine and declares the app beside it: `{ engine: web(), app: { url, command } }`.
+ A tools-only target can omit the engine and set `platform`.
+ - Import `test`, `describe`, the hooks, `expect`, `credentials`, and
+ `secrets` from `e2e`. A test that uses the `browser` fixture imports `test`,
+ `describe`, and the hooks from `@e2e-dev/web`: the same runtime functions,
+ typed with `browser`.
+ - Config and tests are ES modules whatever `package.json` sets as `type`.
+ - Locators resolve when used. Actions wait for readiness and `expect` retries
+ assertions. Reads such as `textContent()` fail at once on zero matches and
+ `count()` answers from the current screen; nothing waits for a value to
+ change, so use a matcher when a value has to settle.
+ - A locator that matches two nodes fails with `LOCATOR_AMBIGUOUS`; narrow it
+ (topic `writing-tests`).
+ - Secrets never appear in test code. Declare accounts under `credentials` and
+ every other sensitive value under `secrets` in the config; resolve with
+ `credentials.user(name).password` or `secrets.get(name)` (separate
+ namespaces: `secrets.get` never returns a password), and hand the opaque
+ `Secret` only to `fill()` or `agent.act` params.
+ - Agent instructions: one goal per `act`, the wording on screen, real values
+ in params. Judge meaning, not phrasing: `toContain('Pro')`, not an exact
+ sentence a model produced.
+ - Check each agent goal's outcome. A passing `act` with a recorded check can
+ be cached and replayed without model calls (topic `agent`).
+ - Shape the agent for this app: `context` for vocabulary the screens use,
+ `system` for how it works, tools for a test API, named personas under
+ `agents`. When a step fails, tighten the goal first, then the context, then
+ the agent.
+ - `.e2e/` is output (`report.json`, `artifacts/`, `cache/`, `logs/`; the
+ config's `output` moves the report and artifacts, never `cache/` or the
+ app's log). Read it, never edit it.
- Use a temporary module-scope patch and revert it immediately after deploy:
+ ## Feedback
- ```ts
- const E2E_SAFE_BUNDLE_IDS = new Set([
- "<built-in-bundle-id>",
- "<stable-bundle-id>",
- ]);
+ When e2e itself gets in your way, tell the e2e team: a command or API that
+ broke (`bug`), docs or this skill that misled you (`docs`), or a capability
+ you needed and did not find (`feature`). Send it once per problem, after you
+ worked around it or gave up, never for failures of the app under test.
- if (!E2E_SAFE_BUNDLE_IDS.has(HotUpdater.getBundleId())) {
- throw new Error("hot-updater e2e crash bundle");
- }
+ ```bash
+ npx e2e feedback --type bug -m "<one or two sentences>" \
+ --task "<what you were doing>" --expected "<...>" --actual "<error code and message>" \
+ --approach "<what you tried>" --command "<e2e command>" --agent "<agent / model>"
```
- ## Reporting
-
- Report platform, release binary, deployed Release/Bundle pairs, final receipt
- (kind/authority/scope/generation/high-water/channel/context), public status,
- directional IDs, crash history, artifact evidence, and whether each assertion
- came from a route snapshot, native metadata, or both.
+ Describe e2e's behavior only: never paste app content, page text, test files,
+ URLs of private apps, or credentials. Secret-named environment variables and
+ common token shapes are redacted, but do not rely on it. `--dry-run` prints
+ what would be sent. Tell the user you sent it and give them the reference id
+ it prints.