Playwright E2E Tests
Uses browser driven journeys to verify important user flows across the application interface.
Scenario
You maintain a web application with Playwright tests covering critical user journeys.
The E2E suite focuses on workflows such as:
- sign in;
- create a project;
- invite a team member;
- complete checkout.
The suite is intentionally smaller than the unit and integration test suites because browser tests are slower and more expensive to maintain.
You want coding agents to add E2E coverage deliberately rather than turning every UI detail into a browser test.
Repository Structure
web-app/
├── src/
├── tests/
│ ├── unit/
│ └── e2e/
│ ├── auth.spec.ts
│ ├── projects.spec.ts
│ └── checkout.spec.ts
├── playwright.config.ts
├── package.json
└── AGENTS.md
AGENTS.md
# Project Instructions
## E2E Testing
Use Playwright for critical user journeys and behavior that requires the application to run as a user would experience it.
Add or update E2E tests when changes affect:
- critical multi-step workflows;
- routing between important screens;
- authentication flows;
- browser behavior not adequately covered at lower test levels.
## Selectors
- Prefer accessible selectors such as role, label, and visible name.
- Use test IDs when a stable semantic selector is not practical.
- Avoid selectors based on fragile DOM structure or generated CSS classes.
## Test Behavior
- Test user-visible outcomes rather than internal React state.
- Keep tests independent.
- Use existing authentication and test-data helpers.
- Do not add arbitrary fixed waits to make a flaky test pass.
## Validation
During development, run the affected Playwright spec.
For changes to critical workflows, run the relevant E2E suite before completion.
What This Does
This tells the agent what belongs in the E2E layer.
For example, a checkout test may perform:
Sign in
↓
Add product
↓
Open cart
↓
Checkout
↓
See confirmation
This verifies a workflow from the user's perspective.
The test does not need to know which React hooks, services, or reducers were involved.
What This Does NOT Do
The file does not encourage writing E2E tests for every component.
For example, testing every visual variant of:
Button
Badge
Input
through Playwright would usually be inefficient.
Those behaviors may be better covered through:
unit tests
component tests
visual tests
depending on the repository.
The instructions also reject a common flaky-test workaround:
await page.waitForTimeout(5000);
Adding a large fixed delay may hide synchronization problems rather than solve them.
Why These Instructions Matter
Browser tests can become fragile when they depend on implementation details.
Consider:
page.locator(".css-1a2b3c > div:nth-child(2)")
A harmless markup or styling change can break the test.
A more user-oriented selector might be:
page.getByRole("button", { name: "Create project" })
This describes the UI through an accessible user-facing contract.
The same principle applies to assertions.
Prefer:
await expect(
page.getByText("Project created successfully"),
).toBeVisible();
over checking internal application state.
Key Decisions
Reserve E2E tests for valuable journeys
Browser tests provide broad confidence but have higher execution and maintenance costs.
Use them where that confidence is valuable.
Prefer semantic selectors
Selectors based on:
role
label
name
test ID
are usually more stable than DOM position or styling implementation.
Avoid arbitrary waits
Wait for the actual condition:
await expect(page.getByText("Dashboard")).toBeVisible();
rather than guessing how long the application needs.
Test from the user's perspective
The E2E layer should answer:
Can the user complete the workflow?
not:
Did a particular internal function execute?
When to Use This Pattern
Use this pattern when:
- the application has critical browser workflows;
- multiple frontend/backend systems interact;
- authentication or routing matters;
- browser behavior needs verification;
- lower-level tests cannot provide enough confidence.
Keep the E2E suite focused on high-value behavior rather than duplicating every lower-level test.