DevPath · Learn to code ESPTEN

Testing the complete application

E2E: the user in a real browser

What an E2E test is

An end-to-end test automates a real browser (or headless) to reproduce a complete user flow: it opens the page, types into a form, clicks, waits for the backend response and verifies what it sees. If it passes, you have a strong proof that the whole system works together.

Tools: Playwright and Cypress

// Conceptual (Playwright doesn't run in this sandbox):
await page.goto("/login");
await page.fill("#email", "ana@x.com");
await page.click("text=Sign in");
await expect(page.getByText("Welcome")).toBeVisible();

When is it worth it?

Reserve E2E for the critical business flows: signup, login, checkout, the "happy path" that must not break. Don't try to cover every edge case with E2E; that's done better with unit/integration (cheaper and more precise).

Flakiness (fragility)

A flaky test passes sometimes and fails other times without the code changing. It's the biggest enemy of E2E: it erodes confidence in the suite. Causes and remedies:

Testing in CI

In continuous integration (CI) the suite runs automatically on every push or pull request, usually with the browser in headless mode. Good practices: run the unit tests first (they fail fast and cheap), parallelize, save screenshots/videos/traces of failed E2E tests for debugging, and block the merge if the suite doesn't pass.

Examples

Wait for a condition, not a fixed time

// Bad: fragile to timing variations.
// await sleep(500); expect(visible(button));

// Good: we wait for the condition to be met.
async function waitUntil(cond, attempts = 10) {
  for (let i = 0; i < attempts; i++) {
    if (cond()) return true;
    await new Promise((r) => setTimeout(r, 10));
  }
  return false;
}
let ready = false;
setTimeout(() => { ready = true; }, 30);
console.log(await waitUntil(() => ready)); // true
Put this into practice

DevPath is a hands-on course: you read the theory here; in the app you put it into practice with exercises that really run, offline.

Start free in the app →
← Unit and integration: doubles and assertionsView the module →