ModulesInstallLabQuizAll courses

Introduction and Quickstart

What end-to-end testing is for, how e2e lets an AI agent take over the brittle parts, and how to go from an empty folder to a passing test in ten minutes.

Module 1 of 5 · AI-Powered E2E Testing

Module 01 ~40 min read + lab TypeScript

What you will learn

Prerequisites: basic JavaScript or TypeScript (async/await), a terminal, and Node.js 24.8 or newer (or 22.22.3+ on the Node 22 line). On Windows, work inside WSL.

About the screenshots

Every terminal and app screenshot in this course comes from real runs we did for the course on 9 October 2026, with e2e 0.18.0 (the stable release) and Google's gemini-3.8-flash model. The official docs already describe the 0.19 nightly; where the two differ, the module says so.

1. Why end-to-end tests

A unit test checks one function. An integration test checks that a few parts talk to each other. An end-to-end test checks the whole product the way a user meets it: it opens the real app, clicks, types, and checks what appears on the screen. It is the only kind of test that would notice that the sign-up button is hidden behind a cookie banner, even though every function behind it works.

The price has always been maintenance. A classic E2E script is a list of selectors and waits: click #cta, wait for .form, type into input[name=email]. Rename a button or move a field and the script breaks, even though a person would still sign up without trouble. Teams end up with slow, flaky suites they stop trusting.

The e2e idea

e2e is an open-source framework for web and mobile apps that lets you choose, step by step, how much of a test is scripted and how much is handed to an AI agent. You can write a goal such as "sign up for a free trial" and let the agent work out the clicks, then check the result with an exact assertion.

2. Deterministic, agentic, or both

Every e2e test is built from the same few pieces, which you will meet properly in Module 2:

Locators + expect

Exact and repeatable. screen.getByRole('button', 'Start free trial') finds one element; expect(...) checks it. No model involved.

Goals: agent.act

A sentence the agent completes by operating the app. Verified steps are cached and replayed later without calling the model.

Judgements: agent.assert

A question about the screen that the model answers, such as "the welcome screen greets Ada by name". Always calls the model.

Deterministic Agent-driven Mixed (recommended) getByRole(...).click() getByRole(...).fill(...) expect(...).toHaveText() fast, free, but brittle agent.act('sign up…') agent.assert('greets…') expect(status).toContain… goal for the flow, exact check agent.act('…') agent.act('…') agent.assert('…') resilient, costs model calls
One framework, three styles. Most teams land in the middle: a goal drives the flow, and an exact assertion proves the outcome. Figure: drawn for this course.

Under the hood, each test runs once per target. The web engine drives Chromium, Firefox or WebKit through Playwright; the mobile engine drives iOS simulators and Android emulators through agent-device. The same test API works on both, which is why this course can cover web and mobile in five modules.

3. Install with npx e2e init

Run the wizard in your app's folder (or an empty one). It asks for the engine (Web or Mobile), a model provider for agent steps, and where to install the coding-agent skill and MCP config. The --yes flag accepts the defaults: the Web engine, the Vercel AI Gateway, both skill locations, and no dependency install.

npx e2e init # interactive wizard npx e2e init --yes # accept the defaults pnpm dlx e2e init # or with pnpm bun x e2e init # or with bun
Terminal output of npx e2e init --yes listing the files it created
Our run of npx e2e init --yes. It adds four dev dependencies and a test:e2e script, then writes the config, an example test, the agent skill and MCP config for Claude Code and Cursor. Screenshot: course run, e2e 0.18.0.
FileWhat it is for
e2e.config.tsTargets (which app, which engine) and agents (which model).
tests/example.e2e.tsA first test. Test files end in .e2e.ts.
.agents/skills/e2e/ and .claude/skills/e2eThe e2e skill: instructions a coding agent reads before writing or fixing tests. npx e2e guide prints it.
.mcp.json, .cursor/mcp.jsonRegisters the e2e mcp server so a coding agent can drive a live app session.
.gitignore entriesKeeps .e2e/ run output (artifacts, cache, reports) out of git.

4. The config file

This is the config we used for the whole course. It differs from the generated one in two places: the model comes from Google (we had a Gemini key), and the runner starts the app itself, so you never forget to.

// e2e.config.ts import type { E2EConfig } from 'e2e'; import { web } from '@e2e-dev/web'; import { google } from '@ai-sdk/google'; export default { agents: { default: { model: google('gemini-3.8-flash'), system: 'You are a thorough QA agent. Verify every outcome.', }, }, targets: [{ engine: web(), app: { url: 'http://127.0.0.1:4173', command: { executable: 'python3', args: ['-m', 'http.server', '4173', '--bind', '127.0.0.1', '--directory', 'app'], reuseExisting: true, }, }, }], } satisfies E2EConfig;

5. Choosing a model

Only agent steps need a model; a test made only of locators and expect runs with no model at all. There are three ways to connect one:

OptionHowExample
API keyInstall the provider package and set its environment variablenpm i -D @ai-sdk/google, GOOGLE_GENERATIVE_AI_API_KEY; also OpenAI, Anthropic, Bedrock, Mistral, Groq and about 25 more
SubscriptionSign in once with npx e2e login <provider>openai (ChatGPT Plus/Pro), github-copilot, opencode-console, spacexai (SuperGrok); a Claude Max or Team plan works through an API key paid from its credits
Local modelPoint at an OpenAI-compatible serverOllama, LM Studio, NVIDIA NIM

Keep keys out of git

Put keys in the environment (for example export GOOGLE_GENERATIVE_AI_API_KEY=...), not in e2e.config.ts. In CI they become repository secrets (Module 5).

6. The demo app and your first run

Throughout the course we test TaskFlow, a one-page app with a landing page, a sign-up form and a welcome screen. It is a single HTML file, so you can build it in the lab below.

TaskFlow landing page with a Start free trial button
TaskFlow, the app under test. Screenshot: course demo app.

Two tests. The first is the generated example: open the page and check that it rendered. The second is a mixed test, straight from the e2e quickstart: a goal does the sign-up, the model judges the welcome screen, and an exact assertion checks the status text.

// 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(); });
// tests/signup.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: 'ada@example.test' }, }); await agent.assert('the welcome screen greets Ada by name'); await expect(screen.getByRole('status')).toContainText('trial'); });
export GOOGLE_GENERATIVE_AI_API_KEY=your-key npx e2e run # every test npx e2e run tests/signup.e2e.ts # one file
Terminal output of npx e2e run with two passing tests and AI token usage
The first run. The runner started the app (291 ms), the agent completed the sign-up in 3 model calls and the judgement in 1. The summary shows tokens, model calls and Cache 1 missed: nothing was cached yet. Screenshot: course run.
TaskFlow welcome screen reading Welcome, Ada! Your 14-day trial is active
The screen the agent reached and judged: the greeting uses the first name from params. Screenshot: course demo app.

Commands to remember

npx e2e init · npx e2e run [files] · npx e2e guide [topic] (the skill, readable by you or an agent) · npx e2e login <provider> · npx agent-device doctor (mobile setup check).

7. Or let a coding agent set it up

The quickstart also gives a single prompt for Claude Code, Codex, Cursor or another coding agent. Paste it in your app's folder; the agent runs init, reads the skill, points the config at your app, asks which model to use, and iterates until the example and one real test pass.

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.

Do the manual route at least once, as in the lab, so you know what the agent is doing on your behalf.

Lab: TaskFlow, first green run

About 20 minutes. You need Node.js 24.8+, Python 3 (only to serve the page) and one model key or subscription.

1

Create the project

mkdir taskflow && cd taskflow npm init -y npx e2e init --yes npm install npm install -D @ai-sdk/google # or your provider's package
2

Add the app

Save this as app/index.html. The typo in the checkbox label is on purpose; an agent will find it in Module 5.

<!doctype html><html lang="en"><head><meta charset="utf-8"><title>TaskFlow</title> <style>body{font-family:system-ui,sans-serif;margin:0;background:#f6f7fb}header{background:#10b981;color:#fff;padding:16px 24px;display:flex;justify-content:space-between} main{max-width:520px;margin:40px auto;background:#fff;border-radius:12px;padding:28px}button{background:#10b981;color:#fff;border:0;border-radius:8px;padding:10px 18px;font-size:1rem} label{display:block;margin:12px 0 4px;font-weight:600}input{width:100%;padding:9px;box-sizing:border-box}[hidden]{display:none!important}.err{color:#b91c1c}</style></head> <body><header><strong>TaskFlow</strong><nav><a href="#" style="color:#fff">Pricing</a></nav></header> <main> <section id="home"><h1>Plan your week in minutes</h1><p>TaskFlow keeps your team's tasks in one place.</p><button id="cta">Start free trial</button></section> <form id="signup" hidden><h2>Create your account</h2> <label for="name">Full name</label><input id="name" required> <label for="email">Work email</label><input id="email" required> <label style="font-weight:400"><input type="checkbox" style="width:auto"> Recieve product updates</label> <p class="err" id="err" role="alert" hidden>Please enter a valid email.</p> <p><button type="submit">Start my trial</button></p></form> <section id="welcome" hidden><h2 id="hello"></h2><p role="status">Your 14-day trial is active.</p></section> </main> <script>const $=id=>document.getElementById(id); $('cta').onclick=()=>{$('home').hidden=true;$('signup').hidden=false}; $('signup').onsubmit=e=>{e.preventDefault();if(!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test($('email').value)){$('err').hidden=false;return} $('signup').hidden=true;$('welcome').hidden=false;$('hello').textContent='Welcome, '+$('name').value.split(' ')[0]+'!'};</script> </body></html>
3

Edit the config and tests

Replace e2e.config.ts with the config in section 4 (swap the model for yours), keep tests/example.e2e.ts, and add tests/signup.e2e.ts from section 6.

4

Run it

Set your key and run npx e2e run. Both tests should pass. Note the token count and model calls in the summary; you will compare them in Module 2.

Troubleshooting
  • Node version error: check node -v; you need 24.8+ (or 22.22.3+).
  • Port in use: another server owns 4173. Change the port in both url and args, or use port 0 and {port} so the runner picks a free one.
  • Model or auth error (exit code 3): the key variable is missing or wrong for your provider. The provider's package docs name the variable.
  • Agent cannot find the form: make sure each input has a <label for>. The agent, like a screen reader, finds elements by role and accessible name.

Knowledge check

Pick one answer per question, then check your score.

1. Which problem does an end-to-end test catch that a unit test usually cannot?

Why: E2E tests drive the real app as a user would, so they see layout, wiring and flow problems that isolated unit tests never touch.

2. Which of these test steps needs no model at all?

Why: Locators and expect are deterministic. Only agent.* steps call a model.

3. What does npx e2e init --yes do?

Why: --yes skips the questions and the install; you run npm install yourself afterwards.

4. In the config, what does app.command do?

Why: The runner spawns the command, waits for readiness, and shuts it down when the run ends, fails or is interrupted.

5. You have a ChatGPT Plus subscription and no API key. How do you use it for agent steps?

Why: e2e supports ChatGPT, GitHub Copilot, OpenCode Console and SuperGrok subscriptions through e2e login.

References

  1. e2e documentation: Introduction, Quickstart, Models, Subscriptions, Web, CLI reference. Accessed 9 October 2026.
  2. e2e on npm: npmjs.com/package/e2e (0.18.0 stable, 0.19 nightly at the time of writing).
  3. Vercel AI SDK providers: ai-sdk.dev/providers.
  4. Playwright documentation: playwright.dev.

Image credits

All screenshots are from runs made for this course. The diagram was drawn for this course.

Summary

Key takeaways

  • E2E tests check the product as users meet it; their cost has been brittle selectors and waits.
  • e2e mixes exact locators and expect with agent goals (agent.act) and judgements (agent.assert).
  • npx e2e init writes the config, an example test, the coding-agent skill and MCP config.
  • Only agent steps need a model: an API key, a subscription via e2e login, or a local server.
  • npx e2e run starts your app (with app.command), runs every target, and reports tokens, model calls and cache use.

Related on this site: Testing AI-generated code (Vibe Coding) · CI/CD (DevOps Lab)