Generate production-ready Playwright tests from a user story, URL, component name, or feature description.
$ARGUMENTS contains what to test. Examples:
"user can log in with email and password"
"the checkout flow"
"src/components/UserProfile.tsx"
"the search page with filters"
Parse $ARGUMENTS to determine:
Use the Explore subagent to gather context:
playwright.config.ts for testDir, baseURL, projects
testDir for patterns, fixtures, and conventionspages/
fixtures/
auth.setup.ts or storageState config)Check templates/ in this plugin for matching patterns:
| If testing... | Load template from |
|---|---|
| Login/auth flow | templates/auth/login.md |
| CRUD operations | templates/crud/ |
| Checkout/payment | templates/checkout/ |
| Search/filter UI | templates/search/ |
| Form submission | templates/forms/ |
| Dashboard/data | templates/dashboard/ |
| Settings page | templates/settings/ |
| Onboarding flow | templates/onboarding/ |
| API endpoints | templates/api/ |
| Accessibility | templates/accessibility/ |
Adapt the template to the specific app — replace {{placeholders}} with actual selectors, URLs, and data.
Follow these rules:
Structure:
import { test, expect } from '@playwright/test';
// Import custom fixtures if the project uses them
test.describe('Feature Name', () => {
// Group related behaviors
test('should <expected behavior>', async ({ page }) => {
// Arrange: navigate, set up state
// Act: perform user action
// Assert: verify outcome
});
});
Locator priority (use the first that works):
getByRole() — buttons, links, headings, form elementsgetByLabel() — form fields with labelsgetByText() — non-interactive text contentgetByPlaceholder() — inputs with placeholder textgetByTestId() — when semantic options aren't availableAssertions — always web-first:
// GOOD — auto-retries
await expect(page.getByRole('heading')).toBeVisible();
await expect(page.getByRole('alert')).toHaveText('Success');
// BAD — no retry
const text = await page.textContent('.msg');
expect(text).toBe('Success');
Never use:
page.waitForTimeout()
page.$(selector) or page.$$(selector)
page.evaluate() for things locators can doAlways include:
await on every Playwright callbaseURL-relative navigation (page.goto('/') not page.goto('http://...')).spec.ts
.spec.js with require() importstest-data/
Run the generated test:
npx playwright test <generated-file> --reporter=list
If it fails: