| name | playwright-debugging |
| description | Guide for writing, running, and debugging Playwright E2E tests. |
Playwright Debugging
Guide for writing, running, and debugging Playwright E2E tests.
Core Principles
- Failing tests indicate real bugs. The tests interact with the real app. If a test fails, the app is broken — investigate the app, not the test.
- Debug locally first. Read error messages, check screenshots/video, check browser console logs. Most issues are obvious once you look at the artifacts.
- Fix the app, not the test. If the test exposes a real bug, fix the production code. Only change the test if the test itself is wrong (wrong selector, wrong expectation, race condition in the test).
- Tests must be independent. Each test should manage its own state. Never depend on state from another test.
Debugging Approach
When a test fails, follow this sequence:
1. Read the Error Message
Playwright error messages are descriptive. They tell you exactly what selector failed and why. Start there.
2. Check Page Structure Output
Failed tests generate test-results/<test-name>/error-context.md with a YAML representation of the page structure:
- heading "Dashboard" [level=1] [ref=e10]
- paragraph [ref=e11]: Enter your section code to get started
- textbox "Section Join Code" [active] [ref=e15]
- button "Join Section" [disabled] [ref=e16]
This shows the actual DOM state at failure time — often more useful than screenshots for understanding what elements are rendered and their states.
3. Check Failure Artifacts
On failure, Playwright captures:
- Screenshots —
test-results/<test-name>/ — shows what the page looked like
- Video — same directory — shows the full test interaction leading up to the failure
- Trace — if enabled, provides a full timeline of actions, network requests, and DOM snapshots
Open the HTML report:
npx playwright show-report
4. Check API Responses
Look for non-200 responses or unexpected error bodies in the browser console logs or network tab of the trace viewer.
5. Trace Back to the Bug
Common failure patterns:
- Element not found — check if the selector changed, or if the page didn't load (API error, auth issue)
- Timeout waiting for element — usually means the feature is broken or the page never navigated
- Text mismatch — check if the API returned unexpected data
- Setup failures — API or database setup failed; check that backend services are running
6. Run in Headed Mode
For interactive debugging:
npx playwright test e2e/your-test.spec.ts --headed
npx playwright test e2e/your-test.spec.ts --debug
Running Tests
Full Suite
npx playwright test
Single Test File
npx playwright test e2e/your-test.spec.ts
Single Test by Name
npx playwright test -g "test name substring"
Writing Tests
Test Structure
Every test file follows this pattern:
import { test, expect } from '@playwright/test';
test.describe('Feature Name', () => {
test('what it does', async ({ page }) => {
await page.goto('/some-page');
await expect(page.locator('h1')).toHaveText('Expected Title');
});
});
Key Patterns
- Setup via API helpers, not UI clicks. Creating test data through API calls is faster and more reliable. Only use UI interactions to test the UI flow you're actually verifying.
- Separate browser contexts for multi-user tests. Use
browser.newContext() when testing interactions between different users.
- Use Playwright auto-waiting.
expect(...).toBeVisible(), page.waitForURL() etc. handle retries automatically. Avoid waitForTimeout except for debounce windows.
- Set explicit timeouts for long operations.
test.setTimeout(60000) for complex multi-step tests; { timeout: 15000 } for slow assertions.
Multi-User Tests
Use separate browser contexts for different users:
test('multi-user flow', async ({ page, browser }) => {
const userBContext = await browser.newContext();
const userBPage = await userBContext.newPage();
try {
} finally {
await userBContext.close();
}
});
What This Skill Does NOT Do
- Increase timeouts as a fix (if something takes 30 seconds, there's a bug)
- Skip verifying something that should be happening
- Ignore assertions that seem "flaky"
- Push to CI to debug (always debug locally first)