| name | generate-playwright-tests |
| description | Generates Playwright E2E test scripts from user story Issues covering complete user journeys. Use when asked to generate E2E tests, Playwright tests, browser tests, or end-to-end test scripts. |
Skill — Generate Playwright Tests
What You Do
Read the [PLAYWRIGHT] GitHub Issue and produce Playwright E2E test scripts
that verify complete user journeys in the browser.
Steps
- Read the [PLAYWRIGHT] GitHub Issue — identify the user journey
- Read
docs/design/design-doc.md — get data-testid values
- Read
src/frontend/src/ — understand component structure
- Generate test files in
e2e/
- Raise PR with test files
Selector Convention — Non-Negotiable
Always use data-testid attributes. Never use CSS classes or text content.
page.locator('[data-testid="add-to-cart-button"]')
page.locator('.btn-primary')
page.locator('text=Add to Cart')
If a component is missing data-testid — note it in the PR description
so the UI Dev can add it before tests are run.
Test File Structure
import { test, expect } from '@playwright/test'
test.describe('{Feature Name}', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login')
await page.fill('[data-testid="email-input"]', 'test@foodorder.com')
await page.fill('[data-testid="password-input"]', 'password123')
await page.click('[data-testid="login-button"]')
await page.waitForURL('**/home')
})
test('{journey description}', async ({ page }) => {
})
})
Assertion Rules
Every action must be followed by an assertion. Never fire and forget.
| What to check | Playwright assertion |
|---|
| Element visible | expect(locator).toBeVisible() |
| Element count | expect(locator).toHaveCount(n) |
| Text content | expect(locator).toHaveText('text') |
| URL changed | expect(page).toHaveURL('/path') |
| Input value | expect(locator).toHaveValue('value') |
| Not visible | expect(locator).not.toBeVisible() |
Journey Mapping
Break the Issue journey into discrete test cases.
One test per distinct assertion point — not one giant test.
WRONG — one giant test
test('full cart journey', async ({ page }) => {
// 20 steps and 10 assertions in one test
// if step 5 fails you don't know where
})
CORRECT — focused tests
test('should add item and update cart count', ...)
test('should show item in cart drawer', ...)
test('should remove item from cart', ...)
Run Instructions to Include in PR
cd src/backend && npm run dev
cd src/frontend && npm run dev
npx playwright test
npx playwright test --ui
npx playwright show-report
On Missing data-testid
If a required data-testid is missing from a component:
- Write the test as if it exists
- Add a comment:
// Requires data-testid="{value}" on {ComponentName}
- Note in PR description which components need updating
Example Tests (Add to Cart)
test('should add item to cart and show count', async ({ page }) => {
await page.goto('/restaurants/1/menu')
await page.locator('[data-testid="add-to-cart-button"]').first().click()
await expect(page.locator('[data-testid="cart-count"]')).toHaveText('1')
})
test('should open drawer and show added item', async ({ page }) => {
await page.goto('/restaurants/1/menu')
await page.locator('[data-testid="add-to-cart-button"]').first().click()
await page.locator('[data-testid="cart-icon"]').click()
await expect(page.locator('[data-testid="cart-drawer"]')).toBeVisible()
await expect(page.locator('[data-testid="cart-item"]')).toHaveCount(1)
})
test('should remove item and reset count', async ({ page }) => {
await page.goto('/restaurants/1/menu')
await page.locator('[data-testid="add-to-cart-button"]').first().click()
await page.locator('[data-testid="cart-icon"]').click()
await page.locator('[data-testid="remove-item-button"]').first().click()
await expect(page.locator('[data-testid="cart-item"]')).toHaveCount(0)
await expect(page.locator('[data-testid="cart-count"]')).toHaveText('0')
})