description: 'Generate comprehensive test strategy and runnable test files from a spec' when_to_use: "After /architect, before /dev. When a spec needs comprehensive test strategy." name: generate-tests version: 1.1.0
Dispatch
Phase 0 — Discovery (main agent, before spawning):
- Extract P-number from spec path (e.g.,
p142fromfeatures/p142_csv_export.md) - Glob for existing test files:
e2e/p{N}-*.spec.tse2e/a11y/p{N}-*.spec.tse2e/integration/p{N}-*.spec.tssrc/tests/**/p{N}-*.test.tsfeatures/uat/p{N}.md
- Read each found file
- Pass inventory (paths + contents) inline to Phase A subagent prompt
Phase A — Analyze + generate (spawn → collect → present):
Spawn Agent tool: model: "sonnet", subagent_type: "general-purpose".
Prompt: the full skill instructions below + spec path from $ARGUMENTS + existing test inventory from Phase 0. Working dir: <cp-root>.
The subagent analyzes the spec, determines test strategy, and generates all test file content — but does NOT write files yet.
When existing test inventory is provided:
- Analyze what's already covered vs. what the spec requires
- Generate ONLY additions or updates — do not regenerate adequate existing files
- If an existing test needs changes, output the full updated file (not a patch)
- Report: "Existing: [N files]. Adding: [M files]. Updating: [K files]."
When no existing tests found:
- Generate from scratch (current behavior)
Collect output (test counts, file paths, generated content). Present summary to user. Ask: "Ready to write these test files? (y/n)"
Phase B — Write files (only after user approves):
Spawn a second Agent tool: model: "sonnet", subagent_type: "general-purpose".
Prompt: write the test files using the content generated in Phase A. Pass file paths and content inline.
Report subagent output verbatim. Then update the spec's ## Test Coverage Strategy section in the main session.
/generate-tests
Generate comprehensive test strategy: unit, integration, E2E, accessibility, smoke tests, and UAT scenarios.
Announce at start: "I'm using the /generate-tests skill to create a comprehensive test strategy from the spec."
Usage
/generate-tests <path-to-spec>
Examples:
/generate-tests features/p142_csv_export.md/generate-tests features/p61_events_complete_tech_spec.md
Lean Mode
Trigger: User invokes with the word lean as an argument.
Example: /generate-tests features/p142.md lean
Decision protocol:
- Check invocation for
leanargument. - If present: announce "Lean mode — skipping A11y + visual test generation. This is a founder-asserted skip, not a verified clean run."
- Proceed with reduced scope below.
- Label output section to preserve signal/confidence distinction.
When lean is appropriate (founder judges, skill does not):
- Feature has been manually reviewed by founder
- Change is scoped + understood (copy, styling, refactor within one file)
- Founder accepts responsibility for skipped coverage
When lean is NOT appropriate:
- New data model / table / column
- New auth surface or route
- New external API call or LLM prompt
- Unfamiliar area of codebase
Lean scope reduction:
- Skipped: A11y test generation, UI/visual test scaffolds
- Retained: unit tests, basic e2e stub, uat checklist
- Output labeled:
## Test Plan (Lean — skipped A11y + visual regression)
What This Skill Does
Intelligently generates test files across the test pyramid:
- Analyzes spec — Reads business + UX + technical requirements
- Determines test strategy — What test types are needed (adaptive, not formulaic)
- Generates runnable tests:
- Unit tests (
src/tests/*.test.ts) — Utilities, services, business logic - Integration tests (
e2e/integration/*.spec.ts) — API + database interactions - E2E tests (
e2e/p{N}-*.spec.ts) — User flows, happy paths, edge cases - Accessibility tests (
e2e/a11y/p{N}-*.spec.ts) — Keyboard, screen reader support - Smoke checks (page load, no console errors) — embedded as first test in E2E feature file
- UAT scenarios (
features/uat/p{N}.md) — Manual validation checklist
- Unit tests (
- Creates test helpers (
e2e/helpers/test-*.ts) — Data factories, utilities (when needed) - Provides coverage report — What's tested (and WHY), what's NOT tested (and WHY)
What Makes This Different from /generate-uat?
| Aspect | /generate-uat (old) | /generate-tests (new) |
|--------|----------------------|-------------------------|
| Test types | UAT + E2E stubs + smoke | Unit + integration + E2E + a11y + UAT (smoke embedded in E2E) |
| Intelligence | Formulaic (always same structure) | Adaptive (analyzes spec, determines what's needed) |
| Test files | TODO stubs (filled by /dev) | Runnable tests + TODOs where appropriate |
| Coverage rationale | None | Clear explanation of what's tested/skipped and WHY |
| Test helpers | Uses existing helpers | Creates new helpers when needed |
| Test pyramid | Heavy E2E focus | Balanced pyramid (unit, integration, E2E) |
Migration: /generate-uat is now an alias to /generate-tests (backward compatible)
When to Use
In the sequential flow:
/create-spec → /ux (if UI) → /architect → /ui (if UI) → /generate-tests → /spec-review → /decompose* → /dev
Run this after:
- ✅ Business requirements approved (
/create-speccomplete) - ✅ UX design approved (
/uxcomplete, if UI feature) - ✅ Architecture approved (
/architectcomplete)
Before:
- ❌
/spec-review(spec-review needs all layers present — run after this skill) - ❌
/dev(implementation needs tests to drive development)
Output
Files generated (adaptive based on feature type):
1. Unit Tests (if utilities/services added)
File: src/tests/{name}.test.ts or src/app/data/{service}.test.ts
When generated:
- ✅ New utility functions (validators, transformers, formatters)
- ✅ New service methods (CRUD, calculations)
- ✅ Complex business logic (algorithms, state machines)
When skipped:
- ❌ Simple getters/setters (no logic)
- ❌ React components (covered by E2E)
- ❌ One-line wrappers
Example:
// src/tests/exportCSV.test.ts
describe('exportResponsesAsCSV', () => {
it('transforms responses to CSV format', () => {
// Runnable test with concrete assertions
});
it('handles empty array', () => {
// Edge case
});
it('handles large datasets (100+ responses)', () => {
// Performance edge case
});
});
2. Integration Tests (if API/database changes)
File: e2e/integration/p{N}-{layer}.spec.ts
When generated:
- ✅ API endpoints (request → response)
- ✅ Database operations (CRUD + RLS validation)
- ✅ Service interactions (auth + profiles)
- ✅ Two-party session flows — when spec references
/live,clarity_sessions,session_code,joiner, orLiveMeeting
When skipped:
- ❌ Simple database reads (covered by E2E)
- ❌ Mocked services (defeats purpose)
Two-party test rule: When the spec describes a two-party session flow, scaffold an E2E test using the two-party helpers. Read .claude/rules/tests.md (Two-Party Helpers section) and docs/technical/e2e-testing-guide.md (Two-Party Sessions section) for current fixtures, assertion patterns, and banned practices. The test MUST include: create session → partner join → trigger feature code path → assert state via waitForUIUpdate() (never page.reload()). See e2e/live-content-picker.spec.ts as reference.
Example:
// e2e/integration/p142-csv-export-api.spec.ts
test('fetches responses from database and exports CSV', async () => {
// Create test data in DB
// Fetch + transform
// Verify CSV output
});
3. E2E Tests (user flows)
File: e2e/p{N}-{feature}.spec.ts
Always generated for features with user-facing changes.
Example:
// e2e/p142-csv-export.spec.ts
test('exports sifter responses as CSV', async ({ page }) => {
// Happy path: user clicks export → CSV downloads
});
test('disables export when no responses', async ({ page }) => {
// Edge case: empty state
});
4. Accessibility Tests (if UI changes)
File: e2e/a11y/p{N}-accessibility.spec.ts
When generated:
- ✅ New UI components (buttons, forms, modals)
- ✅ Complex interactions (keyboard, focus)
- ✅ Dynamic content (screen reader announcements)
Example:
// e2e/a11y/p142-csv-export-accessibility.spec.ts
test('export button is keyboard accessible', async ({ page }) => {
// Tab to button, Enter to activate
});
test('screen reader announces export status', async ({ page }) => {
// Verify ARIA labels
});
5. Smoke Checks (embedded in E2E feature test)
Smoke-style assertions are the first test in the E2E feature file — not a separate file.
Pattern:
test.describe('P142: CSV Export', () => {
test('page loads without console errors', async ({ page }) => {
const consoleErrors: string[] = [];
page.on('console', (msg) => {
if (msg.type() === 'error') consoleErrors.push(msg.text());
});
await page.goto('/results');
await page.waitForLoadState('networkidle');
expect(consoleErrors.filter(e => !e.includes('ResizeObserver'))).toHaveLength(0);
});
// ... feature tests follow ...
});
6. UAT Scenarios (manual validation)
File: features/uat/p{N}.md
Always generated for all features.
Format: Given/When/Then scenarios with verification methods
Example:
### UAT-1.1: Export button works
**Given:** Sifter has 5 responses
**When:** User clicks "Export CSV"
**Then:** CSV file downloads with correct data
**Verify:** Playwright MCP click + download verification
7. Test Helpers (if needed)
File: e2e/helpers/test-{feature}.ts
When generated:
- ✅ Multiple tests need same setup
- ✅ Complex data factories
- ✅ Reusable assertions
Example:
// e2e/helpers/test-sifter.ts
export async function createTestSifter(
creatorId: string,
options: { withResponses?: number } = {}
): Promise<TestSifter> {
// Create sifter + optional responses
}
8. Test Coverage Report
Appended to spec: features/p{N}_{feature}.md
Contains:
- What's tested (and WHY)
- What's NOT tested (and WHY)
- Test pyramid breakdown
- Files generated
- Run time estimates
Example:
## Test Coverage Strategy
**What's Tested:**
- ✅ Core export logic (unit) — Complex transformation
- ✅ Data pipeline (integration) — DB fetch + export
- ✅ User flow (E2E) — Happy path + empty state
**What's NOT Tested:**
- ❌ Component internals — Covered by E2E
- ❌ Browser APIs — Real download in E2E
**Test Pyramid:**
/\
/ \ 1 E2E
/____\
/ 2 INT \
/__________\
/ 3 UNIT \
Total: 6 automated tests + 4 UAT scenarios
Adaptive Behavior
The skill analyzes the spec to determine what's needed:
Example 1: UI Feature (Dark Mode)
Spec has: Business + UX + Technical sections
Generates:
- ✅ Unit tests for
useTheme.tshook (state logic) - ❌ No integration tests (no API/DB)
- ✅ E2E tests for toggle interaction
- ✅ Accessibility tests (keyboard + screen reader)
- ✅ Smoke checks embedded in E2E test
- ✅ UAT scenarios
Rationale: UI feature with state logic → unit + E2E + a11y
Example 2: Backend Feature (API Endpoint)
Spec has: Business + Technical sections (no UX)
Generates:
- ✅ Unit tests for request validator
- ✅ Integration tests for API endpoint
- ❌ No E2E tests (no user-facing UI)
- ❌ No accessibility tests (no UI)
- ✅ Smoke checks embedded in E2E test
- ✅ UAT scenarios
Rationale: Backend feature → unit + integration + smoke checks
Example 3: Database Migration
Spec has: Business + Technical sections (migration script)
Generates:
- ❌ No unit tests (pure SQL)
- ✅ Integration test (MANDATORY) — schema existence + RLS check
- ❌ No E2E tests (no UI)
- ❌ No accessibility tests (no UI)
- ✅ Smoke checks embedded in integration test
- ✅ UAT scenarios (verify data migrated correctly)
Rationale: Data migration → integration + smoke + UAT
⚠️ P270 RULE — Integration test is MANDATORY for any feature adding a DB migration.
The integration test MUST include a schema existence check using the two-client pattern:
supabaseAdmin— query{table}.select('{column}')to verify column exists (fails immediately if migration not applied)- User-scoped JWT client — write/read to verify RLS allows user access (service role bypasses RLS and would miss policy bugs)
Template: Copy e2e/integration/migration-template.spec.ts — rename to e2e/integration/p{N}-{feature}-migration.spec.ts
Why this matters: P160 shipped with 44 tests, all of which mocked or bypassed the DB. The is_private column was missing and no test caught it. A single integration test with supabaseAdmin.from('clarity_sessions').select('is_private') would have failed immediately.
Edge-Case Data Seeding
When generating test stubs from acceptance criteria, detect boundary keywords and auto-generate beforeAll seeding blocks so edge-case scenarios are runnable — not skipped for "no test data."
Boundary keywords to detect (in acceptance criteria, Given/When/Then, or scenario descriptions):
empty, no items, no docs, no letters, no inbox, zero, 0 stories, disabled, first time, new user, never, none, nothing
When a boundary keyword is found:
- Generate a dedicated
test.describeblock with a fresh test user created inbeforeAll - Seed (or deliberately NOT seed) data to match the boundary condition
- Clean up in
afterAll
Pattern:
test.describe('Empty states', () => {
let emptyUser: TestUser;
test.beforeAll(async () => {
emptyUser = await createTestUser({ prefix: 'empty_' });
// No docs, no letters — tests empty state rendering
});
test.afterAll(async () => {
await deleteTestUser(emptyUser.id);
});
test('shows empty state when user has no drafts', async ({ page }) => {
await setTestSession(page, emptyUser.email);
await page.goto('/letters');
await expect(page.getByText('No drafts yet.')).toBeVisible();
});
});
For non-empty boundary conditions (e.g., "draft with 0 stories", "public letter"):
test.describe('Boundary: 0-story draft', () => {
let user: TestUser;
let emptyDoc: string;
test.beforeAll(async () => {
user = await createTestUser({ prefix: 'boundary_' });
// Create doc with no stories attached
emptyDoc = await createTestDoc(user.id, { stories: 0 });
});
test.afterAll(async () => {
await deleteTestDoc(emptyDoc);
await deleteTestUser(user.id);
});
});
Helper mapping for common boundaries:
| Boundary condition | Seeding approach |
|---|---|
| No docs/drafts/letters | createTestUser() with no further data |
| 0 stories in draft | createTestDoc() without createTestStory() |
| No inbox items | createTestUser() — never send them a letter |
| No sent letters | createTestUser() + createTestDoc() — never seal |
| Public letter | Create letter with is_private: false via service role |
| First-time user | createTestUser() — no profile completion |
When boundary seeding uses a data shape not covered by existing helpers: generate the seeding using direct service role key inserts (curl pattern from /verify Step 3a). Add a comment: // TODO: extract to helper if pattern repeats.
Quality Guarantees
All generated tests:
- ✅ Use existing test helpers (
createTestUser,setTestSession, etc.) - ✅ Follow cleanup order (delete points BEFORE users)
- ✅ Include edge cases (errors, loading, empty states)
- ✅ Seed data for boundary conditions — never generate a test that relies on pre-existing data for edge cases
- ✅ Have concrete assertions (not vague "verify it works")
- ✅ Are runnable immediately (filled in by
/dev, but structure is complete) - ✅ If spec has
## UI Contract: every string literal in test assertions (button labels, toast text, placeholders, page titles) must be copied verbatim from the UI Contract table — not paraphrased
Workflow
-
You run:
/generate-tests features/p142_csv_export.md -
Agent analyzes: Business + UX + Technical requirements
-
Agent determines: What test types are needed (unit + integration + E2E + a11y + smoke + UAT)
-
Agent generates: 7 test files + coverage report — the 6 file types are independent after analysis; dispatch them as parallel subagents for large features
-
Agent lint-fixes generated files: Run
npx eslint --fixon all generated.spec.tsand.test.tsfiles to catch unused variables, missing imports, and other auto-fixable issues before they block commit. -
Agent appends: Test strategy to spec. Retirement step: Remove
## Open Questions for /generate-testsif present. Remove## Next Stepsif all listed steps are completed (check delivery_stage) -
Agent updates frontmatter — adds generated file paths to spec frontmatter using the Edit tool (insert before the closing
---):uat_file: features/uat/p{N}.md(always)test_files:list of all generated automated test files (e2e, unit, integration, a11y, smoke)
Format:
uat_file: features/uat/p272.md test_files: - e2e/p272-live-verification.spec.ts - e2e/integration/p272-live-migration.spec.ts - e2e/a11y/p272-accessibility.spec.tsOmit any test type that was skipped (e.g., no unit tests generated → no unit test entry). Do not add
test_files:if no automated tests were generated (UAT-only features). -
You proceed:
/dev features/p142_csv_export.md
Integration with Sequential Flow
/architect → /ui (if UI) → /generate-tests → /spec-review → /decompose* → /dev
- /decompose optional — run AFTER /spec-review (not before). /decompose reads the
## Test Coverage Strategysection written here to addTests:lines to each task entry.
Before /generate-tests:
/create-spec→ Business requirements approved ✅/ux→ UX design approved ✅ (if UI)/architect→ Architecture approved ✅
After /generate-tests:
/spec-review→ Pre-dev audit (always run after/generate-tests, before/decomposeor/dev)/decompose→ (complex features only) reads Test Coverage Strategy to annotate tasks with test refs/dev→ Reads tests, implements feature, fills in TODOs, runs tests, iterates until all pass
Auto-chain. After all test files are generated and the coverage report is appended to the spec, spawn /spec-review as Phase 2 on the same spec file — do not return to the user between phases. The combined output is: test files created + spec-review findings. Return to the user only after both phases complete.
Common Questions
Q: Do I need to review the generated tests?
A: No gate required. The coverage report is appended to the spec — review it if you want. If edge cases are missing, add them to the spec and re-run /generate-tests. Then run /dev.
Q: Can I modify generated tests before /dev?
A: Yes, but usually not needed. If acceptance criteria change, update the spec and re-run /generate-tests.
Q: What if tests are missing edge cases?
A: Add edge cases to spec (UX Design section), re-run /generate-tests. Or add tests manually after /dev.
Q: Do all features need all test types?
A: No. The skill is adaptive — only generates test types that make sense for the feature. Backend features skip E2E/a11y, UI features skip integration tests, etc.
Q: How long does this take?
A: 2-5 minutes for most features (generates 5-10 test files)
Example Output
## Test Strategy Generated for P142: CSV Export
**Files created:**
- ✅ Unit tests: `src/tests/exportCSV.test.ts` (3 tests)
- ✅ Integration tests: `e2e/integration/p142-csv-export-api.spec.ts` (2 tests)
- ✅ E2E tests: `e2e/p142-csv-export.spec.ts` (2 tests)
- ✅ Accessibility tests: `e2e/a11y/p142-csv-export-accessibility.spec.ts` (2 tests)
- ✅ UAT scenarios: `features/uat/p142.md` (4 scenarios)
- ✅ Test helpers: `e2e/helpers/test-sifter.ts`
**Test pyramid:**
/\
/ \ 2 E2E tests
/
/ 2 INT
/______
/ 3 UNIT \
**Total:** 10 automated tests + 4 UAT scenarios
**Estimated run time:** ~15 seconds
**What's tested:**
- ✅ Core export logic (unit)
- ✅ Data pipeline (integration)
- ✅ User flows (E2E)
- ✅ Accessibility (keyboard + screen reader)
**What's NOT tested (rationale):**
- ❌ Component internals (covered by E2E)
- ❌ Browser APIs (real download in E2E test)
**Coverage report:** See "Test Coverage Strategy" section in spec
---
**Next step:** Run `/dev features/p142_csv_export.md` to implement feature + run tests
Related Skills
/create-spec→ Business requirements (layer 1)/ux→ UX design (layer 2, if UI)/architect→ Technical architecture (layer 3)/ui→ Component strategy (layer 3.5, if UI)/generate-tests→ Test strategy (layer 4) ← YOU ARE HERE/dev→ Implementation + testing (layer 5)
Backward Compatibility
/generate-uat is now an alias to /generate-tests:
- Old behavior preserved (still generates UAT + E2E stubs + smoke)
- New behavior added (unit + integration + a11y + helpers + coverage report)
- Features using
/generate-uatautomatically get new capabilities
Validation
This skill was validated against:
- P61 acceptance tests (UAT generation)
- P135, P131, P140 E2E tests (E2E test format)
- P142 sequential flow (test automation)
- Existing test patterns (unit, integration, E2E, a11y)
TDD Red-Green-Refactor
Testing
Skill that guides Claude through the complete TDD cycle.
Web Accessibility Audit
Testing
Performs a comprehensive web accessibility audit following WCAG standards.
UAT Test Case Generator
Testing
Generates structured and comprehensive user acceptance test cases.