1---2name: playwright-generate-test-23description: Generate, save, run, and stabilize Playwright TypeScript tests from a user scenario using Playwright MCP exploration evidence. Use this skill when the user asks to create a Playwright test, generate an @playwright/test spec from a scenario, automate a browser flow, or turn Playwright MCP history into a passing test.4---56# Playwright test generation78Generate a Playwright TypeScript test from a user scenario by first exercising the scenario with Playwright MCP, then writing the spec into the `tests` directory, executing it, and iterating until it passes.910## When to invoke1112- "Generate a Playwright test for this checkout flow."13- "Use Playwright MCP to create a test from this scenario."14- "Turn the browser interactions into an @playwright/test spec."15- "Save a Playwright test in the tests directory and make it pass."16- "Automate this UI scenario with Playwright."1718## Prerequisites and context1920- A concrete scenario is required: target URL or route, starting state, actions, and expected result. If the user provides no scenario, request one before generating code.21- Use Playwright MCP for browser navigation and interaction evidence before writing test code.22- Use the project's existing Playwright setup; do not add a new runner when `@playwright/test` is already present.23- Save generated specs under the existing `tests` directory. If the repository uses a nested Playwright convention such as `tests/e2e`, follow the existing convention inside `tests`.2425## Procedure26271. Parse the scenario into preconditions, actions, assertions, and any data dependencies.282. Open the app with Playwright MCP and perform the scenario one step at a time. Do not generate test code prematurely or solely from the written scenario.293. Capture durable selector evidence from the explored UI: accessible roles, labels, text, test ids, URLs, and visible state changes.304. Convert the completed interaction history into a Playwright TypeScript test using `@playwright/test`.315. Save the generated test file in the `tests` directory with a descriptive `.spec.ts` name.326. Execute the new test file with the existing project command when available, or with `npx playwright test <test-file>` when the project has Playwright installed.337. Fix selector, timing, setup, or assertion issues and rerun the same test until it passes or a real product defect blocks it.3435## Scenario extraction3637| Scenario part | Capture | Test representation |38| --- | --- | --- |39| Entry point | URL, route, fixture, auth state, viewport if relevant | `await page.goto('<url>')` or existing test fixture setup |40| User action | Clicks, fills, selections, keyboard input, uploads, navigation | `page.getByRole`, `getByLabel`, `getByText`, `locator`, `selectOption`, `press` |41| Observable result | URL change, visible message, table row, enabled control, network-driven UI state | `await expect(...).toBeVisible()`, `toHaveURL`, `toContainText`, `toBeEnabled` |42| Required wait | UI transition, navigation, async rendering | Prefer web-first assertions; avoid arbitrary sleeps |43| Test data | Unique names, emails, IDs, clean-up needs | Generate deterministic or unique data inside the test without hardcoded shared secrets |4445## Selector strategy4647| Preference | Use | Avoid |48| --- | --- | --- |49| Accessible role | `page.getByRole('button', { name: 'Save' })` | CSS class chains tied to styling |50| Form labels | `page.getByLabel('Email')` | Index-based selectors like `locator('input').nth(2)` |51| Stable test ids | `page.getByTestId('submit-order')` when the project uses them | Adding test ids without user approval unless already conventional |52| Visible text | `page.getByText('Order submitted')` for user-facing outcomes | Text that is dynamic, localized, or incidental |53| Structural locator | Scoped `locator()` only when accessible selectors are unavailable | XPath copied from browser devtools |5455## Test construction5657- Import from `@playwright/test`: `import { test, expect } from '@playwright/test';`.58- Name the test after the user-visible behavior, not the implementation detail.59- Keep the generated file focused on the requested scenario unless the user asks for a suite.60- Use `test.describe` only when grouping multiple related tests in the same file.61- Assert the final business outcome and at least one intermediate state when it prevents false positives.62- Prefer Playwright web-first assertions over `page.waitForTimeout`.63- Keep credentials, tokens, and private data out of the test. Use existing fixtures or environment-driven auth when the project already provides them.6465## Common defects6667| Defect | Why it fails | Correction |68| --- | --- | --- |69| Code before exploration | The test encodes assumptions and misses actual labels, routing, or timing | Complete all Playwright MCP steps before emitting code |70| Brittle selector | Styling or DOM order changes break the test without behavior changing | Use role, label, text, or test id selectors |71| Missing assertion | The test only clicks through the flow and can pass while the feature is broken | Assert visible outcome, URL, or persisted UI state |72| Arbitrary sleep | Slow or fast environments make `waitForTimeout` flaky | Use `await expect(locator).to...` |73| Unscoped data | Shared fixed values collide across runs | Generate unique data or clean up through existing helpers |7475## Troubleshooting7677| Symptom | Likely cause | Resolution |78| --- | --- | --- |79| Test cannot find a locator | The selected locator was not stable or the element appears later | Re-open the page with Playwright MCP, inspect accessible names, and replace with a web-first locator plus assertion |80| Test passes locally but fails in CI | Timing, viewport, auth state, or test data differs | Remove sleeps, assert readiness, use existing storage state or fixtures, and avoid shared data |81| Navigation assertion times out | The action does not navigate or the URL pattern is too strict | Assert the actual post-action UI state, or use a looser `toHaveURL` pattern backed by exploration evidence |82| Browser is not installed | Playwright dependency exists but browsers are missing | Run the project's documented install command, commonly `npx playwright install`, only when dependency setup is expected |8384## Output template8586```markdown87## Playwright test generation result8889**Status:** passed | blocked90**Scenario:** <one-sentence scenario summary>91**Test file:** `tests/<name>.spec.ts`9293### Exploration evidence94| Step | Interaction | Selector or URL | Observed outcome |95| --- | --- | --- | --- |96| 1 | <action> | `<selector-or-url>` | <visible result> |9798### Generated test99- Framework: `@playwright/test`100- Command: `<test command>`101- Result: pass | fail102103### Remaining work104- <none, or blocker with evidence>105```106107## Quality gate108109- [ ] A user scenario was provided or explicitly requested before code generation.110- [ ] Playwright MCP was used step by step before emitting the test.111- [ ] The emitted test imports from `@playwright/test`.112- [ ] The test file is saved under the `tests` directory.113- [ ] Selectors prefer roles, labels, text, or stable test ids over brittle DOM structure.114- [ ] Assertions verify the user-visible outcome of the scenario.115- [ ] The generated test file was executed.116- [ ] Failures were iterated until the test passed or a blocker was reported with evidence.