Playwright Pro
Use this skill to design, generate, review, debug, and stabilize production-grade Playwright test suites. It is the higher-discipline complement to a basic browser automation skill: focus on reliable assertions, maintainable fixtures, CI behavior, coverage strategy, and regression confidence.
When to Use
- Creating a new Playwright suite for a web app.
- Generating E2E tests from user stories, acceptance criteria, URLs, or existing manual QA steps.
- Fixing flaky Playwright tests in local runs or CI.
- Migrating Cypress, Selenium, Puppeteer, or manual smoke tests to Playwright.
- Adding regression tests for a bug fix.
- Reviewing test quality before merge.
- Testing authentication, checkout, forms, dashboards, uploads, permissions, onboarding, search, settings, or real-time flows.
- Adding visual, accessibility, API-assisted, or cross-browser checks.
- Integrating Playwright into GitHub Actions, CircleCI, Buildkite, Azure Pipelines, or other CI systems.
Skip When
- The task only needs quick page inspection or a one-off screenshot.
- Unit tests or integration tests would verify the behavior more cheaply and reliably.
- There is no runnable app or stable target environment and the user does not want setup work.
- The user explicitly asks to avoid browser automation.
Core Capabilities
- Bootstrap a maintainable Playwright configuration.
- Generate tests with resilient locators and web-first assertions.
- Design fixtures for auth, test data, API setup, and cleanup.
- Diagnose flakiness by timing, isolation, network, data, and selector stability.
- Review tests for anti-patterns and weak assertions.
- Migrate legacy suites while preserving behavior coverage.
- Integrate reports, traces, screenshots, and videos into CI.
- Build regression strategy around user-critical flows.
Recommended Workflow
1. Init: inspect framework, routes, auth, package manager, and test conventions.
2. Generate: write the smallest high-value tests for critical user paths.
3. Review: check locators, assertions, isolation, data setup, and failure diagnostics.
4. Run: execute locally in headless mode first, then headed for debugging if needed.
5. Stabilize: remove sleeps, isolate state, and add deterministic waits.
6. CI: shard, report, upload traces, and set retry policy.
7. Maintain: add regression tests for every escaped bug.
Project Setup Checklist
- Install
@playwright/test with the repo's package manager.
- Keep Playwright config in the established test directory style.
- Use one base URL per environment.
- Store credentials and test secrets in environment variables.
- Use
webServer for local app startup when appropriate.
- Enable traces on first retry.
- Capture screenshots and videos only on failure unless visual review needs more.
- Add HTML or blob report artifacts in CI.
- Define projects for Chromium, Firefox, WebKit, mobile, or branded browsers only when they provide real coverage.
- Keep timeouts explicit and conservative.
Example Config
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests/e2e',
timeout: 30_000,
expect: { timeout: 5_000 },
retries: process.env.CI ? 2 : 0,
reporter: process.env.CI ? [['blob'], ['html', { open: 'never' }]] : 'list',
use: {
baseURL: process.env.PLAYWRIGHT_BASE_URL ?? 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
],
webServer: process.env.CI ? undefined : {
command: 'npm run dev',
url: 'http://localhost:3000',
reuseExistingServer: true,
},
});
Test Generation Pattern
Write tests from user intent, not DOM structure.
import { test, expect } from '@playwright/test';
test('user can sign in and reach the dashboard', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('demo@example.com');
await page.getByLabel('Password').fill(process.env.E2E_DEMO_PASSWORD!);
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page).toHaveURL(/dashboard/);
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});
Prefer getByRole, getByLabel, getByText, and getByTestId over brittle CSS selectors. Add test IDs only where accessible locators are not stable or meaningful.
Locator Rules
- Use user-facing locators first.
- Prefer role plus accessible name for controls.
- Avoid long CSS chains and nth-child selectors.
- Avoid text locators for dynamic copy unless copy is the behavior under test.
- Use
data-testid for non-semantic UI, repeated rows, charts, or canvas-adjacent controls.
- Keep locators close to assertions so failures are readable.
- Do not locate hidden elements unless testing hidden state explicitly.
Assertion Rules
- Use web-first assertions:
toBeVisible, toHaveText, toHaveURL, toBeEnabled, toHaveCount.
- Assert the user-visible outcome, not just that a button was clicked.
- For API effects, assert through UI or a controlled API check.
- Avoid arbitrary sleeps.
- Avoid snapshots for highly dynamic content unless normalized.
- Make negative assertions bounded and intentional.
- Test one user behavior per test where practical.
Flaky Test Diagnosis
Classify the failure before fixing:
- Timing: missing web-first assertion, racing navigation, animation, delayed API.
- Selector: unstable text, generated class, wrong element, hidden duplicate.
- Data: shared account state, order dependence, dirty database, clock dependency.
- Network: third-party dependency, slow API, mock mismatch, environment outage.
- Browser: viewport, locale, permissions, storage state, cross-browser behavior.
- CI: CPU starvation, missing fonts, sandbox, port conflict, parallel collision.
Use evidence:
npx playwright test tests/e2e/login.spec.ts --trace on
npx playwright show-trace test-results/**/trace.zip
npx playwright test --headed --debug
Fixing Flakiness
- Replace
waitForTimeout with an assertion on the awaited state.
- Wait for URL, response, element state, or app-specific ready marker.
- Isolate auth with
storageState fixtures.
- Create unique test data per test run.
- Clean up data through API or database helpers.
- Disable or control animations when they are not under test.
- Mock unstable third-party services.
- Use retries only as a signal capture tool, not as the fix.
Migration from Cypress or Selenium
- Map each legacy test to a user behavior and expected outcome.
- Drop tests that assert implementation details with no product value.
- Replace implicit waits with Playwright web-first assertions.
- Convert page objects only if they reduce duplication and stay readable.
- Preserve critical coverage first: auth, payments, destructive actions, permissions, and core workflows.
- Run old and new suites in parallel until parity is clear.
CI Integration
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Run E2E tests
run: npx playwright test
- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: playwright-report/
In larger suites, shard by CI node and keep trace artifacts for failures.
Review Checklist
- Tests map to real user requirements.
- Locators are accessible and resilient.
- No arbitrary sleeps.
- Each test has deterministic setup and cleanup.
- Auth state is safe and isolated.
- Assertions verify visible outcomes or durable side effects.
- CI artifacts make failures diagnosable.
- Retries are not hiding persistent bugs.
- The suite can run locally without undocumented steps.
- Visual tests have stable baselines and masking for dynamic regions.
Anti-Patterns
- Testing implementation classes instead of user behavior.
- Sharing one mutable test account across the whole suite.
- Using
page.locator('button').nth(3).
- Waiting for network idle as a universal solution in apps with polling.
- Overusing end-to-end tests for logic better covered by unit tests.
- Ignoring failed trace artifacts.
- Making the suite serial because data isolation is missing.
- Testing third-party services live in every CI run.
Output Format
## Test Plan
- Critical flows:
- Fixtures/data:
- Browser matrix:
- CI artifacts:
## Generated or Changed Tests
- ...
## Flake Risks
- ...
## Commands Run
- ...
Boundaries
Do not store real credentials in tests. Do not hit production systems unless the user explicitly confirms the target and safety controls. Prefer local, staging, or mocked services for repeatable automation.
1---2name: playwright-pro3description: Production-grade Playwright testing skill for E2E suites, flaky test diagnosis, browser automation, migration from Cypress/Selenium, CI integration, visual checks, and regression validation.4license: MIT5---6
7# Playwright Pro
8
9Use this skill to design, generate, review, debug, and stabilize production-grade Playwright test suites. It is the higher-discipline complement to a basic browser automation skill: focus on reliable assertions, maintainable fixtures, CI behavior, coverage strategy, and regression confidence.
10
11## When to Use
12
13- Creating a new Playwright suite for a web app.
14- Generating E2E tests from user stories, acceptance criteria, URLs, or existing manual QA steps.
15- Fixing flaky Playwright tests in local runs or CI.
16- Migrating Cypress, Selenium, Puppeteer, or manual smoke tests to Playwright.
17- Adding regression tests for a bug fix.
18- Reviewing test quality before merge.
19- Testing authentication, checkout, forms, dashboards, uploads, permissions, onboarding, search, settings, or real-time flows.
20- Adding visual, accessibility, API-assisted, or cross-browser checks.
21- Integrating Playwright into GitHub Actions, CircleCI, Buildkite, Azure Pipelines, or other CI systems.
22
23## Skip When
24
25- The task only needs quick page inspection or a one-off screenshot.
26- Unit tests or integration tests would verify the behavior more cheaply and reliably.
27- There is no runnable app or stable target environment and the user does not want setup work.
28- The user explicitly asks to avoid browser automation.
29
30## Core Capabilities
31
321. Bootstrap a maintainable Playwright configuration.
332. Generate tests with resilient locators and web-first assertions.
343. Design fixtures for auth, test data, API setup, and cleanup.
354. Diagnose flakiness by timing, isolation, network, data, and selector stability.
365. Review tests for anti-patterns and weak assertions.
376. Migrate legacy suites while preserving behavior coverage.
387. Integrate reports, traces, screenshots, and videos into CI.
398. Build regression strategy around user-critical flows.
40
41## Recommended Workflow
42
43```text
441. Init: inspect framework, routes, auth, package manager, and test conventions.
452. Generate: write the smallest high-value tests for critical user paths.
463. Review: check locators, assertions, isolation, data setup, and failure diagnostics.
474. Run: execute locally in headless mode first, then headed for debugging if needed.
485. Stabilize: remove sleeps, isolate state, and add deterministic waits.
496. CI: shard, report, upload traces, and set retry policy.
507. Maintain: add regression tests for every escaped bug.
51```
52
53## Project Setup Checklist
54
55- Install `@playwright/test` with the repo's package manager.
56- Keep Playwright config in the established test directory style.
57- Use one base URL per environment.
58- Store credentials and test secrets in environment variables.
59- Use `webServer` for local app startup when appropriate.
60- Enable traces on first retry.
61- Capture screenshots and videos only on failure unless visual review needs more.
62- Add HTML or blob report artifacts in CI.
63- Define projects for Chromium, Firefox, WebKit, mobile, or branded browsers only when they provide real coverage.
64- Keep timeouts explicit and conservative.
65
66## Example Config
67
68```ts
69import { defineConfig, devices } from '@playwright/test';
70
71export default defineConfig({
72 testDir: './tests/e2e',
73 timeout: 30_000,
74 expect: { timeout: 5_000 },
75 retries: process.env.CI ? 2 : 0,
76 reporter: process.env.CI ? [['blob'], ['html', { open: 'never' }]] : 'list',
77 use: {
78 baseURL: process.env.PLAYWRIGHT_BASE_URL ?? 'http://localhost:3000',
79 trace: 'on-first-retry',
80 screenshot: 'only-on-failure',
81 video: 'retain-on-failure',
82 },
83 projects: [
84 { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
85 ],
86 webServer: process.env.CI ? undefined : {
87 command: 'npm run dev',
88 url: 'http://localhost:3000',
89 reuseExistingServer: true,
90 },
91});
92```
93
94## Test Generation Pattern
95
96Write tests from user intent, not DOM structure.
97
98```ts
99import { test, expect } from '@playwright/test';
100
101test('user can sign in and reach the dashboard', async ({ page }) => {
102 await page.goto('/login');
103 await page.getByLabel('Email').fill('demo@example.com');
104 await page.getByLabel('Password').fill(process.env.E2E_DEMO_PASSWORD!);
105 await page.getByRole('button', { name: 'Sign in' }).click();
106
107 await expect(page).toHaveURL(/dashboard/);
108 await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
109});
110```
111
112Prefer `getByRole`, `getByLabel`, `getByText`, and `getByTestId` over brittle CSS selectors. Add test IDs only where accessible locators are not stable or meaningful.
113
114## Locator Rules
115
116- Use user-facing locators first.
117- Prefer role plus accessible name for controls.
118- Avoid long CSS chains and nth-child selectors.
119- Avoid text locators for dynamic copy unless copy is the behavior under test.
120- Use `data-testid` for non-semantic UI, repeated rows, charts, or canvas-adjacent controls.
121- Keep locators close to assertions so failures are readable.
122- Do not locate hidden elements unless testing hidden state explicitly.
123
124## Assertion Rules
125
126- Use web-first assertions: `toBeVisible`, `toHaveText`, `toHaveURL`, `toBeEnabled`, `toHaveCount`.
127- Assert the user-visible outcome, not just that a button was clicked.
128- For API effects, assert through UI or a controlled API check.
129- Avoid arbitrary sleeps.
130- Avoid snapshots for highly dynamic content unless normalized.
131- Make negative assertions bounded and intentional.
132- Test one user behavior per test where practical.
133
134## Flaky Test Diagnosis
135
136Classify the failure before fixing:
137
138- Timing: missing web-first assertion, racing navigation, animation, delayed API.
139- Selector: unstable text, generated class, wrong element, hidden duplicate.
140- Data: shared account state, order dependence, dirty database, clock dependency.
141- Network: third-party dependency, slow API, mock mismatch, environment outage.
142- Browser: viewport, locale, permissions, storage state, cross-browser behavior.
143- CI: CPU starvation, missing fonts, sandbox, port conflict, parallel collision.
144
145Use evidence:
146
147```bash
148npx playwright test tests/e2e/login.spec.ts --trace on
149npx playwright show-trace test-results/**/trace.zip
150npx playwright test --headed --debug
151```
152
153## Fixing Flakiness
154
155- Replace `waitForTimeout` with an assertion on the awaited state.
156- Wait for URL, response, element state, or app-specific ready marker.
157- Isolate auth with `storageState` fixtures.
158- Create unique test data per test run.
159- Clean up data through API or database helpers.
160- Disable or control animations when they are not under test.
161- Mock unstable third-party services.
162- Use retries only as a signal capture tool, not as the fix.
163
164## Migration from Cypress or Selenium
165
166- Map each legacy test to a user behavior and expected outcome.
167- Drop tests that assert implementation details with no product value.
168- Replace implicit waits with Playwright web-first assertions.
169- Convert page objects only if they reduce duplication and stay readable.
170- Preserve critical coverage first: auth, payments, destructive actions, permissions, and core workflows.
171- Run old and new suites in parallel until parity is clear.
172
173## CI Integration
174
175```yaml
176- name: Install Playwright browsers
177 run: npx playwright install --with-deps
178
179- name: Run E2E tests
180 run: npx playwright test
181
182- name: Upload Playwright report
183 if: always()
184 uses: actions/upload-artifact@v4
185 with:
186 name: playwright-report
187 path: playwright-report/
188```
189
190In larger suites, shard by CI node and keep trace artifacts for failures.
191
192## Review Checklist
193
194- Tests map to real user requirements.
195- Locators are accessible and resilient.
196- No arbitrary sleeps.
197- Each test has deterministic setup and cleanup.
198- Auth state is safe and isolated.
199- Assertions verify visible outcomes or durable side effects.
200- CI artifacts make failures diagnosable.
201- Retries are not hiding persistent bugs.
202- The suite can run locally without undocumented steps.
203- Visual tests have stable baselines and masking for dynamic regions.
204
205## Anti-Patterns
206
207- Testing implementation classes instead of user behavior.
208- Sharing one mutable test account across the whole suite.
209- Using `page.locator('button').nth(3)`.
210- Waiting for network idle as a universal solution in apps with polling.
211- Overusing end-to-end tests for logic better covered by unit tests.
212- Ignoring failed trace artifacts.
213- Making the suite serial because data isolation is missing.
214- Testing third-party services live in every CI run.
215
216## Output Format
217
218```markdown
219## Test Plan
220- Critical flows:
221- Fixtures/data:
222- Browser matrix:
223- CI artifacts:
224
225## Generated or Changed Tests
226- ...
227
228## Flake Risks
229- ...
230
231## Commands Run
232- ...
233```
234
235## Boundaries
236
237Do not store real credentials in tests. Do not hit production systems unless the user explicitly confirms the target and safety controls. Prefer local, staging, or mocked services for repeatable automation.