> ## Documentation Index
> Fetch the complete documentation index at: https://e2e.tester.army/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Set up e2e with one prompt to your coding agent, or step by step.

export const setupPrompt = `Set up e2e end-to-end tests in this project. Docs: \`https://e2e.tester.army/docs/quickstart.md\`

1. Run \`npx e2e init --yes\` (or the pnpm or bun equivalent for this project). It writes a web config using Vercel AI Gateway, an example test, the e2e skill, and MCP config. It installs nothing yet.
2. Read the e2e skill (\`npx e2e guide\` prints it, \`npx e2e guide <topic>\` prints a topic) and follow it for every step below.
3. Point the target at this app. For a web app, set its URL and the command that starts its dev server. For an iOS or Android app, replace @e2e-dev/web with @e2e-dev/mobile and rewrite the example test for the mobile engine.
4. Ask me which model to use for agent steps: a ChatGPT, GitHub Copilot, OpenCode Console, or SuperGrok subscription, an API key, or a local model. Configure it with its provider package. If it needs a sign-in, give me the \`npx e2e login\` command and wait until I confirm.
5. Install dependencies, run the example test, and fix setup errors until it passes.
6. Write one test for the most important user flow in this app, run it, and iterate until it passes.`;

<VideoCard
  id="4_9z6QWShLc"
  title="Getting Started with Agentic e2e in 4 Minutes"
  subtitle="In this video, Kacper takes a simple Next.js app from zero to a working agentic test suite."
/>

## Set up with your coding agent

Paste this prompt into Claude Code, Codex, Cursor, or another coding agent
in your app's directory:

<SetupPrompt>

<Prompt description={setupPrompt} children={setupPrompt} actions={["copy", "cursor"]} />

</SetupPrompt>

The agent installs the [e2e skill](https://e2e.tester.army/docs/coding-agents), so later prompts such as
"add a test for checkout" need no more setup.

<Note>
Use Node.js 24.8 or newer (22.22.3 or newer on Node.js 22). On Windows, run inside WSL. Mobile tests also
need Xcode with an iOS simulator runtime, or the Android SDK with an emulator.
</Note>

## Set up manually

### Run your first test

<Steps>
  <Step title="Create the test project">
  In your app's directory:

  <CodeGroup>
  ```bash npm
  npx e2e init
  ```

  ```bash pnpm
  pnpm dlx e2e init
  ```

  ```bash bun
  bunx e2e init
  ```
  </CodeGroup>

  Choose **Web (Playwright)** or **Mobile (iOS/Android)**, then a
  subscription, a model provider, or **None** for tests without AI. The
  wizard writes a config and an example test, adds dependencies, and offers
  to set up your coding agent. It keeps existing files.

  <Tabs>
    <Tab title="Web">
    Start your app's dev server at `http://localhost:3000`, or set its address
    in `e2e.config.ts`. You can also [let e2e start it](https://e2e.tester.army/docs/web#starting-your-app).

    <Accordion title="Example web config and test">
    This config uses Vercel AI Gateway. The wizard configures the provider you chose.

```ts title="e2e.config.ts"

export default {
  agents: { default: { model: gateway('openai/gpt-6-luna-fast') } },
  targets: [{ engine: web(), app: { url: 'http://localhost:3000' } }],
} satisfies E2EConfig;
```

```ts title="tests/example.e2e.ts"

test('app opens', async ({ app, browser }) => {
  await app.open('/');
  await expect(browser.locator('body')).toBeVisible();
});
```
    </Accordion>
    </Tab>
    <Tab title="Mobile">
    Run `npx e2e doctor` to check your setup. The wizard picks iOS on macOS
    and Android elsewhere. The example opens the Settings app.

    <Accordion title="Example iOS config and test">
    This config uses Vercel AI Gateway. For Android, the wizard sets
    `platform: 'android'` and `app: { bundleId: 'com.android.settings' }`.

```ts title="e2e.config.ts"

export default {
  agents: { default: { model: gateway('openai/gpt-6-luna-fast') } },
  targets: [{ name: 'ios', engine: mobile({ platform: 'ios' }), app: { bundleId: 'Settings' } }],
  workers: 1,
} satisfies E2EConfig;
```

```ts title="tests/example.e2e.ts"

test('Settings opens', async ({ app, screen }) => {
  await app.open();
  await expect(screen.getByRole('button', 'General')).toBeVisible();
});
```
    </Accordion>

    See [Mobile](https://e2e.tester.army/docs/mobile) to use your own app.
    </Tab>
  </Tabs>

  <Accordion title="Use JavaScript instead of TypeScript">
  Rename `e2e.config.ts` to `e2e.config.js` and `tests/example.e2e.ts` to
  `tests/example.e2e.js`. In the config, delete the
  `import type { E2EConfig } from 'e2e';` line and `satisfies E2EConfig`.
  Then add a JSDoc type and set `tests`:

```js title="e2e.config.js"
/** @type {import('e2e').E2EConfig} */
export default {
  tests: 'tests/**/*.e2e.js',
  // ...the rest of the config, unchanged
};
```

  The example test has no types to remove. Name later tests `*.e2e.js`. See
  [JavaScript](https://e2e.tester.army/docs/reference/config#javascript) for type checks and mixing
  JavaScript with TypeScript.
  </Accordion>
  </Step>
  <Step title="Run the example">
  <CodeGroup>
  ```bash npm
  npx e2e run
  ```

  ```bash pnpm
  pnpm exec e2e run
  ```

  ```bash bun
  bunx e2e run
  ```
  </CodeGroup>

  e2e downloads a browser or boots the simulator or emulator, checks that
  the app opens, and prints the result. The example makes no model calls,
  so it needs no sign-in or API key.
  </Step>
</Steps>

<Video>
  <video src="/images/init.mp4" aria-label="npx e2e init asks for an engine, a model gateway, and coding agent setup, then lists the files it will write." muted loop playsInline controls />

  `npx e2e init` asks a few questions, then shows every change before it writes anything.
</Video>

### Use a subscription or API key

<Tabs>
  <Tab title="Subscription">
  | Plan | How to connect |
  | --- | --- |
  | ChatGPT Plus or Pro | `npx e2e login openai` |
  | GitHub Copilot | `npx e2e login github-copilot` |
  | OpenCode Console (OpenCode Zen and OpenCode Go) | `npx e2e login opencode-console` |
  | SuperGrok or X Premium+ | `npx e2e login spacexai` |
  | Claude Max or Team (Claude Code) | API key from the plan's monthly API credits. See [Claude Max or Team](https://e2e.tester.army/docs/subscriptions#claude-max-or-team). |

  Copilot uses your GitHub CLI login if you have one. See
  [Subscriptions](https://e2e.tester.army/docs/subscriptions).
  </Tab>
  <Tab title="API key">
  Select your provider. Install its package and set the variables it reads,
  if any, in the terminal where you run e2e.

  <ModelProvider show="select" />

  <ModelProvider show="install" />

  <ModelProvider show="env" />

  The wizard writes the config for Vercel AI Gateway, OpenRouter, and
  OpenAI-compatible endpoints. For another provider, replace the model import
  and `model` value in `e2e.config.ts`, and use `agent` as `agents.default`:

  <ModelProvider show="model" />

  See [Models](https://e2e.tester.army/docs/models) for local models and more options.
  </Tab>
</Tabs>

### Add an agent step

Give `agent.act` one [atomic goal](https://e2e.tester.army/docs/core-concepts#goals) per call, then
check the result. Adapt the example to a flow in your app:

<Tabs>
  <Tab title="Web">
```ts title="tests/agent.e2e.ts"

test('a visitor signs up for a trial', async ({ app, agent, screen }) => {
  await app.open('/');

  await agent.act('sign up for a free trial as {name} with email {email}', {
    params: { name: 'Ada Lovelace', email: 'ada@example.test' },
  });

  await agent.assert('the welcome screen greets Ada by name');
  await expect(screen.getByRole('status')).toContainText('trial');
});
```
  </Tab>
  <Tab title="Mobile (iOS)">
```ts title="tests/agent.e2e.ts"

test('the agent opens General', async ({ agent, app, device }) => {
  await app.open();
  await agent.act('open {section} settings', { params: { section: 'General' } });

  await agent.assert('the General settings screen is showing');
  await expect(device.locator('role=navigation-bar id=General')).toBeVisible();
});
```

  `app.open()` launches the app fresh. Without it, a test starts where the
  previous one left the device. `device.locator` takes
  [agent-device selectors](https://e2e.tester.army/docs/mobile#the-device-fixture).
  </Tab>
</Tabs>

`params` fill the goal's placeholders. `agent.assert` judges the screen.
`expect` checks an exact value.

<CodeGroup>
```bash npm
npx e2e run tests/agent.e2e.ts
```

```bash pnpm
pnpm exec e2e run tests/agent.e2e.ts
```

```bash bun
bunx e2e run tests/agent.e2e.ts
```
</CodeGroup>

If you chose **None** in the wizard, [add a model](https://e2e.tester.army/docs/models) first. Add
`--headed` to watch a web test. Add `--no-cache` to skip cached actions.

### Configure the project

`e2e.config.ts` holds the options. These are the ones most projects change
after `init`:

| To | Set | See |
| --- | --- | --- |
| point at your app | `app.url`, or `app.bundleId` on mobile | [The app under test](https://e2e.tester.army/docs/reference/config#the-app-under-test) |
| start the app with the run | `app.command` | [Starting your app](https://e2e.tester.army/docs/web#starting-your-app) |
| use a model | `agents.default.model` | [Models](https://e2e.tester.army/docs/models) |
| test several browsers or devices | one `targets` entry each, with a `name` | [targets](https://e2e.tester.army/docs/reference/config#targets) |
| give tests more time | `timeout`, `actionTimeout`, `assertionTimeout` | [timeout](https://e2e.tester.army/docs/reference/config#timeout) |
| retry failed tests | `retries`, `1` in CI | [retries](https://e2e.tester.army/docs/reference/config#retries) |
| run tests in parallel | `workers`, `1` in CI | [workers](https://e2e.tester.army/docs/reference/config#workers) |
| pick the test files | `tests` | [tests](https://e2e.tester.army/docs/reference/config#tests) |
| keep traces and videos | `trace`, `video` | [Recording](https://e2e.tester.army/docs/reference/config#recording) |
| write a JUnit report | `reporters: ['list', 'junit']` | [reporters](https://e2e.tester.army/docs/reference/config#reporters) |
| sign in and pass API keys | `credentials`, `secrets` | [Signing in](https://e2e.tester.army/docs/authentication) |
| write the replay cache in CI | `cache: 'read-write'` | [Caching](https://e2e.tester.army/docs/cache) |

<Accordion title="Example config with common options">
```ts title="e2e.config.ts"

const app = {
  url: process.env.APP_URL ?? 'http://localhost:3000',
  command: { executable: 'npm', args: ['run', 'dev'], reuseExisting: true },
};

export default {
  agents: { default: { model: gateway('openai/gpt-6-luna-fast') } },
  targets: [
    { name: 'chromium', engine: web({ viewport: { width: 1440, height: 900 } }), app },
    { name: 'firefox', engine: web({ browser: 'firefox' }), app },
  ],
  timeout: 180_000,
  workers: 4,
  reporters: ['list', 'junit'],
  video: 'retain-on-failure',
} satisfies E2EConfig;
```

`--target firefox` runs one target. Targets that share one `command` share
one server process.
</Accordion>

## Next

<CardGroup cols={2}>
  <Card title="Core concepts" icon="pen-to-square" href="/core-concepts">
    Goals, assertions, and locators.
  </Card>
  <Card title="Signing in" icon="key" href="/authentication">
    Reuse an app login and keep passwords out of model input.
  </Card>
  <Card title="Debugging" icon="bug" href="/debugging">
    Read failures, screenshots, and traces.
  </Card>
  <Card title="Continuous integration" icon="code-branch" href="/ci">
    Run your tests on GitHub Actions, Expo Workflows, Bitrise, or Codemagic.
  </Card>
</CardGroup>
