skip to content

Quickstart

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

videoGetting Started with Agentic e2e in 4 MinutesIn this video, Kacper takes a simple Next.js app from zero to a working agentic test suite. (opens in a new tab)

Set up with your coding agent

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

agent prompt

Set up e2e end-to-end tests in this project. Docs: https://e2e.com/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.

The agent installs the e2e skill, so later prompts such as “add a test for checkout” need no more setup.

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

Set up manually

Run your first test

  1. 1
    Create the test project

    In your app’s directory:

    npx e2e init

    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.

    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.

    Example web config and test

    This config uses Vercel AI Gateway. The wizard configures the provider you chose.

    e2e.config.ts
    import type { E2EConfig } from 'e2e';
    import { web } from '@e2e-dev/web';
    import { gateway } from 'ai';
    
    export default {
      agents: { default: { model: gateway('openai/gpt-6-luna-fast') } },
      targets: [{ engine: web(), app: { url: 'http://localhost:3000' } }],
    } satisfies E2EConfig;
    tests/example.e2e.ts
    import { test } from '@e2e-dev/web';
    import { expect } from 'e2e';
    
    test('app opens', async ({ app, browser }) => {
      await app.open('/');
      await expect(browser.locator('body')).toBeVisible();
    });
  2. 2
    Run the example
    npx e2e run

    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.

npx e2e init asks a few questions, then shows every change before it writes anything.

Use a subscription or API key

PlanHow to connect
ChatGPT Plus or Pronpx e2e login openai
GitHub Copilotnpx 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.

Copilot uses your GitHub CLI login if you have one. See Subscriptions.

Add an agent step

Give agent.act one atomic goal per call, then check the result. Adapt the example to a flow in your app:

tests/agent.e2e.ts
import { test } from '@e2e-dev/web';
import { expect } from 'e2e';

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: '[email protected]' },
  });

  await agent.assert('the welcome screen greets Ada by name');
  await expect(screen.getByRole('status')).toContainText('trial');
});

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

npx e2e run tests/agent.e2e.ts

If you chose None in the wizard, add a model 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:

ToSetSee
point at your appapp.url, or app.bundleId on mobileThe app under test
start the app with the runapp.commandStarting your app
use a modelagents.default.modelModels
test several browsers or devicesone targets entry each, with a nametargets
give tests more timetimeout, actionTimeout, assertionTimeouttimeout
retry failed testsretries, 1 in CIretries
run tests in parallelworkers, 1 in CIworkers
pick the test filesteststests
keep traces and videostrace, videoRecording
write a JUnit reportreporters: ['list', 'junit']reporters
sign in and pass API keyscredentials, secretsAuthentication
write the replay cache in CIcache: 'read-write'Caching
Example config with common options
e2e.config.ts
import type { E2EConfig } from 'e2e';
import { web } from '@e2e-dev/web';
import { gateway } from 'ai';

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.

Next

was this page helpful?