Glossary · Testing fundamentals
End-to-end test
Also called: E2E, E2E test, E2E tests, end-to-end tests
Definition
A test that drives a complete user journey through the real, fully deployed system, from the UI or public API down to the database and back.
An end-to-end (E2E) test exercises the system the way a user does, with every layer real: browser, front end, back-end services, database, queues and, where practical, third-party integrations. It answers the question the lower levels cannot: does the whole thing actually work together for a real journey? E2E tests sit at the top of the test pyramid because they give the most realistic confidence at the highest cost.
Example (Playwright)
import { test, expect } from '@playwright/test';
test('guest can buy a product', async ({ page }) => {
await page.goto('/');
await page.getByRole('searchbox', { name: 'Search' }).fill('desk lamp');
await page.keyboard.press('Enter');
await page.getByRole('link', { name: 'Desk Lamp' }).click();
await page.getByRole('button', { name: 'Add to cart' }).click();
await page.getByRole('link', { name: 'Checkout' }).click();
await page.getByLabel('Email').fill('guest@example.com');
await page.getByRole('button', { name: 'Place order' }).click();
await expect(page.getByRole('heading', { name: 'Thank you for your order' })).toBeVisible();
});
One test crosses search, catalog, cart, checkout and order services. If the cart service serializes prices wrongly, this test catches it even when every service’s unit tests pass.
Why keep them few
- Slow. Seconds to minutes each, against milliseconds for unit tests.
- Prone to flakiness. More moving parts mean more timing issues, shared data and environment instability.
- Poor diagnosis. “Checkout failed” could be any of a dozen services.
- Expensive to maintain. UI changes ripple through many tests.
So reserve E2E tests for critical business journeys, such as sign-up, purchase and core workflows, and cover variations (every validation rule, every discount type) at the unit and API levels.
Making them reliable
- Use condition-based waiting, such as Playwright’s auto-waiting and web-first assertions or Selenium’s
WebDriverWait, never fixed sleeps. - Create test data through APIs in setup instead of clicking through the UI, and give each test its own data.
- Use stable locators: roles, labels and test IDs rather than layout-dependent XPath.
- Structure the code with page objects or similar so a UI change is fixed in one place.
“End-to-end” and “system test” overlap: system testing is the test level, E2E describes the style of test that goes through every layer.