End-to-end tests verify the application from the user's perspective in a real browser. They are especially valuable for critical workflows such as login, checkout, payments, employee creation, and report generation.
What E2E testing verifies
An E2E test can start at the login page, authenticate, navigate through the application, submit a form, call the backend, and verify the resulting screen.
flowchart TD
A[Browser] --> B[Login]
B --> C[Dashboard]
C --> D[Create order]
D --> E[Backend]
E --> F[Database]
F --> G[Confirmation]
G --> A
Playwright example
import { test, expect } from "@playwright/test";
test("user can create an order", async ({ page }) => {
await page.goto("/login");
await page.getByLabel("Email")
.fill("ravi@example.com");
await page.getByLabel("Password")
.fill("Password123!");
await page.getByRole("button", {
name: "Login"
}).click();
await page.getByRole("link", {
name: "Orders"
}).click();
await page.getByRole("button", {
name: "Create Order"
}).click();
await expect(
page.getByText("Order created")
).toBeVisible();
});
Cypress style
describe("Orders", () => {
it("creates an order", () => {
cy.visit("/login");
cy.get("[name=email]")
.type("ravi@example.com");
cy.get("[name=password]")
.type("Password123!");
cy.contains("Login").click();
cy.contains("Orders").click();
cy.contains("Create Order").click();
cy.contains("Order created")
.should("be.visible");
});
});
Playwright vs Cypress
| Area | Playwright | Cypress |
|---|---|---|
| Browser automation | Strong multi-browser automation | Strong browser-focused testing |
| Language options | Multiple language support | JavaScript/TypeScript focused |
| Parallelism | Strong built-in capabilities | Strong CI workflows |
| Network control | Rich routing/mocking APIs | Rich interception/stubbing |
| Best choice | Depends on team and project needs | Depends on team and project needs |
Avoid brittle selectors
Prefer role and accessible-name selectors where possible. Avoid selectors based on generated CSS classes because a visual refactor should not break an unrelated E2E test.
Authentication in E2E
For a large suite, repeatedly performing a full login can make tests slow. Playwright supports reusable authenticated browser state, while Cypress projects commonly use custom commands or session helpers.
Critical workflow example
Test:
Login
↓
Dashboard
↓
Create employee
↓
Fill required fields
↓
Save
↓
Success message
↓
Employee appears in list
Output
E2E: employee creation
✓ login successful
✓ employee form opened
✓ validation passed
✓ employee saved
✓ success message visible
1 passed
Common mistakes
- Using E2E tests for every tiny UI detail.
- Using fixed sleeps instead of waiting for observable conditions.
- Sharing state between tests unexpectedly.
- Depending on production data.
- Using fragile selectors.
Interview questions
- Unit vs integration vs E2E?
- Playwright vs Cypress?
- How do you make E2E tests stable?
- How do you handle authentication in E2E?
- What should be covered by E2E tests?