| name | generate-e2e-tests |
| description | Use Playwright MCP to explore a feature, analyze existing tests, and generate/update E2E tests. Prioritizes user journey scenarios over individual element tests. |
| user-invocable | true |
| allowed-tools | ["Read","Write","Edit","Grep","Glob","Bash","mcp__playwright__browser_navigate","mcp__playwright__browser_snapshot","mcp__playwright__browser_click","mcp__playwright__browser_type","mcp__playwright__browser_select_option","mcp__playwright__browser_close"] |
Generate E2E Tests
Convert manual Playwright MCP verification into automated Playwright tests. This skill explores the UI, analyzes existing test coverage, and proposes scenario-based tests.
Philosophy
Prioritize scenarios over individual element tests:
- Good: "user can navigate from sidebar to resource list and view details"
- Bad: "sidebar button is visible", "table header exists", "row count is correct"
Tests should represent user journeys - sequences of actions a user would take to accomplish a goal. Multiple assertions within a single test scenario are preferred over separate tests for each assertion.
Process
Phase 1: Context Gathering
-
Understand the feature from conversation context or ask the user:
- What feature was just implemented?
- What page/route is it on?
- What are the key user interactions?
-
Start mock server and dev server if not running:
docker compose -f e2e/docker-compose.yml up -d
Phase 2: Exploration with Playwright MCP
-
Navigate to the feature using mcp__playwright__browser_navigate
-
Capture snapshots using mcp__playwright__browser_snapshot to understand:
- Page structure and available elements
- Interactive elements (buttons, links, inputs)
- Data displayed from mock server
-
Interact with the feature using:
mcp__playwright__browser_click for buttons/links
mcp__playwright__browser_type for inputs
mcp__playwright__browser_select_option for dropdowns
-
Document the user journey as you explore:
- Starting state
- Actions taken
- Expected outcomes after each action
- Final state
Phase 3: Analyze Existing Tests
-
Read existing test files in e2e/ directory:
e2e/*.spec.ts
-
Identify coverage gaps:
- What scenarios are already tested?
- What new scenarios does this feature introduce?
- Can existing tests be extended rather than creating new ones?
Phase 4: Propose Test Plan
- Present the plan to the user in this format:
## E2E Test Plan for [Feature Name]
### Existing Coverage
- [List what's already tested that relates to this feature]
### Proposed Changes
#### Option A: Extend Existing Test (Preferred if applicable)
**File:** `e2e/[existing].spec.ts`
**Test:** `[existing test name]`
**Add assertions for:**
- [New assertion 1]
- [New assertion 2]
#### Option B: New Test Scenario
**File:** `e2e/[new-or-existing].spec.ts`
**Scenario:** `[descriptive scenario name]`
**User Journey:**
1. [Action 1] → [Expected outcome]
2. [Action 2] → [Expected outcome]
3. [Action 3] → [Expected outcome]
### Recommendation
[Which option and why]
- Wait for user approval before proceeding
Phase 5: Implement Tests
- Write or update tests following these patterns:
test('user can browse resources and view details', async ({ page }) => {
await page.goto('/dashboard')
await page.getByRole('button', { name: 'Pod' }).click()
await expect(page).toHaveURL(/kind=Pod/)
await expect(page.getByRole('table')).toBeVisible()
await expect(page.getByRole('row')).toHaveCount(5)
await page.getByRole('link', { name: 'nginx-pod' }).click()
await expect(page.getByRole('heading', { name: 'nginx-pod' })).toBeVisible()
})
test('sidebar has Pod button', ...)
test('clicking Pod updates URL', ...)
test('table is visible', ...)
test('rows exist', ...)
-
Use beforeEach for common setup (login, navigation to starting point)
-
Prefer extending existing test.describe blocks when the feature fits
Phase 6: Run and Verify
- Run the tests:
npx playwright test e2e/[file].spec.ts --reporter=line
- If tests fail, analyze the error and fix:
- Check if selectors need adjustment
- Verify mock data matches expected values
- Ensure proper wait conditions
- Report results to the user:
- Tests passed/failed
- Coverage added
- Any issues encountered
Test Writing Guidelines
Selectors (in order of preference)
getByRole() - Most reliable, semantic
getByLabel() - For form fields
getByText() - For static text
getByTestId() - Last resort, requires code changes
Assertions
- Use
toBeVisible() for elements that should be seen
- Use
toBeAttached() for elements in DOM but possibly hidden
- Use
toHaveURL() for navigation verification
- Use
toHaveCount() for lists/tables
- Use
toContainText() for partial text matching
Handling Async
Mock Data Awareness
- Tests run against mock server data
- Don't assert on specific counts unless mock data is deterministic
- Prefer assertions like "at least one" over exact counts when possible
Example Invocation
User: "I just finished implementing the resource detail page. Can you generate tests for it?"
Claude would then:
- Use Playwright MCP to navigate to the dashboard
- Click through to a resource detail page
- Capture the page structure
- Check existing tests in
e2e/dashboard.spec.ts
- Propose extending the "clicking resource kind shows resource list" test to include clicking through to details
- Wait for approval
- Implement and run the tests