The initial app is no longer generated by a separate command. /plan-milestones now always makes milestone 01 'App Shell Generation' (target platform asked in the single question round): theme from design tokens, one screen per blueprint entry, routes, reusable components — no feature logic — plus Playwright setup and the e2e/app-shell.spec.ts smoke spec. It is executed like any other milestone via /execute-milestones (which loads platform-ui-generation for it) or /add-feature. Milestone 02 becomes the MVP core. All workflow diagrams, skills, docs READMEs, CLAUDE.md, and README updated; docs/design README also gains the screen-inventory.md entry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
119 lines
5.1 KiB
Markdown
119 lines
5.1 KiB
Markdown
---
|
|
name: e2e-testing
|
|
description: Guide for writing and running Playwright end-to-end tests as part of every verification step. Use when verifying a feature, milestone, or generated app shell, or when setting up Playwright in the repository.
|
|
allowed-tools: Read, Write, Edit, Bash
|
|
---
|
|
|
|
# E2E Testing Skill (Playwright)
|
|
|
|
This skill defines how end-to-end tests are written and run in this project. **Every verification step includes E2E tests**: a feature, milestone, or app shell is not "verified" until its Playwright tests pass alongside unit tests, lint, and typecheck.
|
|
|
|
## Core Principles
|
|
|
|
1. **E2E is part of verification, not an extra**: the standard verification sequence is `npm test` → `npm run lint` → `npm run typecheck` → `npm run test:e2e`. All four must pass.
|
|
2. **Tests are derived from acceptance criteria**: every feature's acceptance criteria (from its phase file or steering `requirements.md`) map to E2E assertions. If a criterion cannot be asserted in an E2E test, note why in the tasklist.
|
|
3. **Blueprint-driven selectors**: screens, routes, and actions come from `docs/design/ui-blueprint.json`. Tests navigate by the blueprint's routes and interact via the blueprint's actions.
|
|
4. **One spec file per feature** plus one smoke spec for the app shell.
|
|
5. **Web-first**: Playwright covers the `web` target. For `flutter` use `integration_test`, for `winui3` use the platform's UI automation — apply the same acceptance-criteria mapping; note in the tasklist when Playwright does not apply.
|
|
|
|
## Setup (run once, on demand)
|
|
|
|
If Playwright is not yet set up in the repository (no `@playwright/test` in `package.json`), set it up before the first E2E run:
|
|
|
|
```bash
|
|
npm install -D @playwright/test
|
|
npx playwright install --with-deps chromium
|
|
```
|
|
|
|
Create `playwright.config.ts`:
|
|
|
|
```typescript
|
|
import { defineConfig } from '@playwright/test';
|
|
|
|
export default defineConfig({
|
|
testDir: './e2e',
|
|
fullyParallel: true,
|
|
retries: process.env.CI ? 2 : 0,
|
|
reporter: [['list'], ['html', { open: 'never' }]],
|
|
use: {
|
|
baseURL: process.env.E2E_BASE_URL ?? 'http://localhost:3000',
|
|
trace: 'retain-on-failure',
|
|
screenshot: 'only-on-failure',
|
|
},
|
|
webServer: {
|
|
command: 'npm run dev', // adjust to the project's start command
|
|
url: 'http://localhost:3000', // adjust to the project's port
|
|
reuseExistingServer: !process.env.CI,
|
|
},
|
|
});
|
|
```
|
|
|
|
Add the script to `package.json`:
|
|
|
|
```json
|
|
"test:e2e": "playwright test"
|
|
```
|
|
|
|
Adjust `baseURL`, `webServer.command`, and the port to the project's actual dev server (see `docs/architecture.md`). Add `e2e/` artifacts (`playwright-report/`, `test-results/`) to `.gitignore`.
|
|
|
|
## Test Layout
|
|
|
|
```
|
|
e2e/
|
|
├── app-shell.spec.ts # smoke: shell renders, every blueprint route navigates
|
|
├── [feature-name].spec.ts # one spec per feature
|
|
└── helpers/ # shared fixtures/utilities (only when duplicated 3+ times)
|
|
```
|
|
|
|
## Writing Feature Specs
|
|
|
|
For each feature, create `e2e/[kebab-case-feature-name].spec.ts`:
|
|
|
|
- One `test.describe` block per feature; one `test` per acceptance criterion (or a tight group of criteria).
|
|
- Navigate using the route of the affected screen from `ui-blueprint.json`.
|
|
- Prefer semantic locators: `getByRole`, `getByLabel`, `getByText` — matching the blueprint's component types and labels. Avoid CSS/XPath selectors tied to implementation details.
|
|
- No fixed waits (`waitForTimeout`); rely on Playwright's auto-waiting and explicit `expect(...).toBeVisible()` style assertions.
|
|
- Keep tests independent: each test sets up its own state and does not depend on execution order.
|
|
|
|
Example:
|
|
|
|
```typescript
|
|
import { test, expect } from '@playwright/test';
|
|
|
|
test.describe('Edit user profile', () => {
|
|
test('saves a changed display name', async ({ page }) => {
|
|
await page.goto('/profile');
|
|
await page.getByLabel('Display name').fill('New Name');
|
|
await page.getByRole('button', { name: 'Save' }).click();
|
|
await expect(page.getByText('Profile updated')).toBeVisible();
|
|
});
|
|
});
|
|
```
|
|
|
|
## Writing the App-Shell Smoke Spec
|
|
|
|
Created by the App Shell milestone (milestone 01, web target). `e2e/app-shell.spec.ts` must verify:
|
|
|
|
- The app starts and the entry screen renders.
|
|
- Every route in `ui-blueprint.json` is reachable and renders its screen title.
|
|
- Primary navigation (from the blueprint's nav component) works.
|
|
|
|
## Running
|
|
|
|
```bash
|
|
npm run test:e2e
|
|
```
|
|
|
|
- If a test fails, analyze the trace/screenshot in `test-results/`, fix the code (or the test if the spec was wrong against the acceptance criteria), and re-run until green.
|
|
- Never delete or skip a failing test to make verification pass; a skipped test requires a written reason in the tasklist, same as a struck task.
|
|
|
|
## Verification Checklist
|
|
|
|
Used by `/add-feature` Step 7 and `/execute-milestones` Step 2.6 (including the App Shell milestone):
|
|
|
|
- [ ] Playwright is set up (`test:e2e` script exists) — set it up via this skill if missing.
|
|
- [ ] Every implemented feature has `e2e/[feature].spec.ts` covering its acceptance criteria.
|
|
- [ ] The app-shell smoke spec still passes.
|
|
- [ ] `npm test`, `npm run lint`, `npm run typecheck`, and `npm run test:e2e` all pass.
|
|
- [ ] No test was skipped or deleted without a written reason.
|