Use these instructions when adding or reviewing browser tests. Prefer focused tests over full-suite runs for local logic.
Locator Strategy
Use stable, user-visible locators in priority order:
getByRole('button', { name: 'Submit' }) — best for accessibility
getByText('Welcome') — for visible text content
getByTestId('checkout-form') — when role/text is ambiguous
locator('[data-testid="..."]') — fallback for complex selectors
Avoid fragile selectors: nth-child, deep CSS paths, auto-generated class names.
Test Structure
One assertion per logical check — avoid mega-tests that assert 10 things
Use test.describe to group related scenarios
Use test.beforeEach for shared navigation, not repeated goto() calls
Name tests by user behavior: "user can add item to cart", not "test button click"
Reliability Rules
Never use page.waitForTimeout() — use expect(locator).toBeVisible() or waitForResponse()
Check console errors for UI changes: page.on('console', ...)
Use expect(page).toHaveURL() instead of checking raw URL strings
Run the smallest relevant test first — npx playwright test path/to/file.spec.ts
Screenshots and Visual Testing
Use await expect(page).toHaveScreenshot() for visual regression
Avoid whileInView animations and lazy-loaded images in screenshot tests — they produce flaky baselines
Use page.setViewportSize() for consistent screenshot dimensions
Patterns to Avoid
Timing-based waits (setTimeout, waitForTimeout)
Selectors coupled to CSS framework class names (.css-1a2b3c)
Tests that depend on external API state without mocking
Full test suite runs for single-file logic changes
Raw content
Copy this into your project — e.g. .instructions.md, .agent.md, or SKILL.md
## Overview
Use these instructions when adding or reviewing browser tests. Prefer focused tests over full-suite runs for local logic.
## Locator Strategy
Use stable, user-visible locators in priority order:
1. `getByRole('button', { name: 'Submit' })` — best for accessibility
2. `getByText('Welcome')` — for visible text content
3. `getByTestId('checkout-form')` — when role/text is ambiguous
4. `locator('[data-testid="..."]')` — fallback for complex selectors
Avoid fragile selectors: `nth-child`, deep CSS paths, auto-generated class names.
## Test Structure
- One assertion per logical check — avoid mega-tests that assert 10 things
- Use `test.describe` to group related scenarios
- Use `test.beforeEach` for shared navigation, not repeated `goto()` calls
- Name tests by user behavior: `"user can add item to cart"`, not `"test button click"`
## Reliability Rules
- Never use `page.waitForTimeout()` — use `expect(locator).toBeVisible()` or `waitForResponse()`
- Check console errors for UI changes: `page.on('console', ...)`
- Use `expect(page).toHaveURL()` instead of checking raw URL strings
- Run the smallest relevant test first — `npx playwright test path/to/file.spec.ts`
## Screenshots and Visual Testing
- Use `await expect(page).toHaveScreenshot()` for visual regression
- Avoid `whileInView` animations and lazy-loaded images in screenshot tests — they produce flaky baselines
- Use `page.setViewportSize()` for consistent screenshot dimensions
## Patterns to Avoid
- Timing-based waits (`setTimeout`, `waitForTimeout`)
- Selectors coupled to CSS framework class names (`.css-1a2b3c`)
- Tests that depend on external API state without mocking
- Full test suite runs for single-file logic changes