full-coverage
npx skills add https://github.com/tech-stack-dev/full-coverage-skill --skill full-coverage
Agent 安装分布
Skill 文档
Full Coverage â Test Generation
Generate the right tests for every layer of the testing pyramid: unit, integration, API, and E2E. The skill analyzes the code, selects the correct layers, and implements each one following strict guidelines.
Testing Pyramid
âââââââââââââââââââââââââ
â E2E Tests â Playwright browser · user journeys
â ââââââââââââââââââââââââ£
â API Tests â Playwright HTTP · HTTP contracts
â ââââââââââââââââââââââââ£
âIntegration â Vitest + Prisma · every branch with real DB
â ââââââââââââââââââââââââ£
â Unit Tests â Vitest · isolated logic, no I/O
âââââââââââââââââââââââââ
Layer Responsibility Matrix
Each concern is owned by exactly one layer. Do not duplicate responsibilities.
| Concern | Unit | Integration | API | E2E |
|---|---|---|---|---|
| Zod field exhaustive validation | Owner | 1â2 wiring checks | 1 per endpoint | No |
| Service method branches | Owner (mocked deps) | Owner (real DB) | No | No |
| Pure utility functions | Owner | No | No | No |
| Mock call argument verification | Owner | No | No | No |
| HTTP contract (status codes, body) | No | No | Owner | No |
| Write verification (POSTâGET, DELETEâ404) | No | No | Owner | No |
| Authorization enforcement (401, 403) | No | Owner | Owner | No |
| External service calls (mocked) | Owner (vi.mock) | Owner (Wiremock) | No | No |
| DB persistence verification | No | Owner | No | No |
| Complete user journey through UI | No | No | No | Owner |
| Navigation and routing | No | No | No | Owner |
Step 1: Analyze the Code
Before selecting layers or writing any tests, read the target code.
Read these files:
- Zod schemas / DTOs (
<domain>.dto.ts) - Service class (
<domain>.service.ts) - Route handlers (
app/api/<path>/route.ts) - Utility functions (
<domain>.utils.ts) - DB schema (
prisma/schema.prisma) - Error definitions (
src/lib/server/errors.ts) - External service clients (if any)
- UI components / pages (if any â look for
data-testidattributes)
Build an inventory:
- Schemas found: list field names and rules
- Service methods found: list method names and their dependencies
- HTTP endpoints found: list METHOD /path
- Utility functions found: list exported functions
- External service calls found: list service names
- UI pages found: list page URLs
Write a one-paragraph summary: “This module has X schemas, Y service methods, Z endpoints… Recommended layers: [list].”
Step 2: Select Layers
Apply this decision tree after completing Step 1:
Does the code have Zod schemas or pure utility functions?
YES â Unit tests required (always the baseline layer)
Does the code have service methods with branches (if/else, switch, throw)?
YES â Unit tests (mocked) + Integration tests (real DB) required
Why: unit tests prove logic; integration tests prove wiring with real DB.
Together they are not redundant â they cover different failure modes.
Does the code expose HTTP endpoints?
YES â API tests required (one spec file per endpoint)
Does the code have browser UI with data-testid attributes?
YES â E2E tests required (one spec per feature area)
Common combinations:
- Pure utility library â Unit only
- Backend service, no UI â Unit + Integration + API (if endpoints exist)
- Full-stack feature â All four layers
State explicitly which layers are selected and which are skipped with a reason: “Skipping E2E: no browser UI found in this module.”
Step 3: Generate Tests, Layer by Layer
Work bottom-up. Generate unit tests first, then integration, then API, then E2E. Complete and self-validate each layer before moving to the next.
If Unit tests are selected:
Read references/unit-testing.md before writing any code.
Key steps:
- Read schemas, service, utils, errors
- Map every field à rule and every service branch as a case tree (write as comments first)
- Create
schema.helper.tsand<domain>.unit-factory.ts - Write schema tests (one
describeper field, oneit()per rule) - Write service tests (all branches mocked, exact mock argument verification)
- Write utility tests (if applicable)
- Run:
vitest run src/modules/<domain>/test/unit/ - Run self-validation checklist from the reference file
If Integration tests are selected:
Read references/integration-testing.md before writing any code.
Key steps:
- Read source + auth implementation + error response shape (determines assertion format)
- List every execution path as comments inside
describeblocks - Create
DatabaseHelper,AuthHelper, fixtures, api-utils - Write handler tests (1â2 validation wiring tests per endpoint â no exhaustive Zod rules)
- Write service layer tests (direct calls, real DB)
- Run:
yarn test:integration(or equivalent) - Run self-validation checklist from the reference file
If API tests are selected:
Read references/api-testing.md before writing any code.
Key steps:
- Read route handlers, DTOs, error definitions
- Verify/create response helpers for all error codes
- Create test-owned factory (never import backend DTOs)
- Create API utilities (one function per endpoint)
- Create cleanup utilities
- Write test specs: plan scenarios as comments first, then implement
- Run:
npx playwright test --project=api - Run self-validation checklist from the reference file
If E2E tests are selected:
Read references/e2e-testing.md before writing any code.
Key steps:
- Read PRD, page components (
data-testidattributes), existing fixtures - Identify user flows (one spec file per feature area)
- Create or update Page Object Models (locators via
data-testidonly) - Create test data factory with
counter + timestamp + randompattern - Create API-based setup helper and cleanup helper
- Write test specs (API setup, inject auth, navigate, UI interaction, assert)
- Run:
npx playwright test --project=chromium - Run self-validation checklist from the reference file
Universal Patterns
These apply at every layer. Do not repeat in reference files.
Unique test data
let counter = 0;
function uniqueSuffix(): string {
counter++;
return `${counter}-${Date.now()}-${Math.floor(Math.random() * 100000)}`;
}
// Usage: `test-user-${uniqueSuffix()}@test.com`
Why: parallel test runs share a database. Non-unique data causes false failures when one test’s cleanup deletes another test’s records.
Arrange-Act-Assert
Every test follows this exact structure:
// Arrange â set up state
const cookie = await authenticateUser(request);
const dto = generateCreateNoteDto();
// Act â execute the behavior
const response = await executePostNoteRequest(request, dto, cookie);
// Assert â verify the result
expect201Created(response);
expect(response.data.title).toBe(dto.title);
Cleanup in afterEach
// â Correct â runs even when test throws
test.afterEach(async ({ request }) => {
for (const cookie of cookiesToCleanup) {
await cleanupNotes(request, cookie);
await cleanupUser(request, cookie);
}
cookiesToCleanup.length = 0;
});
// â Wrong â skipped when test throws before reaching cleanup
test("...", async ({ request }) => {
const cookie = await authenticateUser(request);
// ...
await cleanupUser(request, cookie); // This line may never run
});
No shared state between tests
- No
beforeAllfor shared data - No shared auth sessions
- Each test creates its own user and test entities
No static waits
// â Forbidden at all layers
await new Promise(resolve => setTimeout(resolve, 1000));
await page.waitForTimeout(5000);
// â Use explicit conditions instead
// API/Integration: poll with 400ms interval, 15s timeout
// E2E: locator.waitFor(), page.waitForURL(), expect(locator).toBeVisible()
No snapshot tests
.toMatchSnapshot() and .toMatchInlineSnapshot() are forbidden at all layers. Snapshots hide intent and produce opaque diffs.
No hardcoded URLs
Always use relative paths. Playwright’s baseURL from config handles environment switching.
Reference File Guide
When generating tests for a layer, read the corresponding reference file first. Each file includes the full workflow, verbatim templates, and a self-validation checklist.
| File | Contains | Key templates |
|---|---|---|
references/unit-testing.md |
8-step workflow, Zod test patterns, mocking rules | schema.helper.ts, unit factory, service test structure |
references/integration-testing.md |
5-step workflow, parallel-safe cleanup, validation wiring | DatabaseHelper, AuthHelper (both variants), fixture structure |
references/api-testing.md |
8-step workflow, test-owned interfaces, write verification | authenticateUser(), API utilities, response helpers, per-endpoint test counts |
references/e2e-testing.md |
9-step workflow, POM rules, waiting strategy | createUserViaApi(), injectAuthCookie(), Page Object Model, 5 wait patterns |
Cross-Layer Checklist
After all layers are complete, verify the pyramid is correctly shaped:
No layer duplication:
- Unit tests cover Zod field validation exhaustively â integration/API/E2E do not
- Integration tests have only 1â2 validation wiring tests per endpoint
- API tests have only 1 validation test per endpoint
- E2E tests cover user journeys and navigation â no field validation
Pyramid shape (count tests per layer):
- Unit tests are the largest group (60â70% of total)
- Integration tests are the second largest (20â25%)
- API tests are smaller (10â15%)
- E2E tests are the fewest (5â10%)
All self-validation checklists were run:
- Unit layer checklist â
- Integration layer checklist â
- API layer checklist â
- E2E layer checklist â
Cross-Layer Examples
The same “notes” domain â showing exactly how coverage is divided, not duplicated.
Testing a title field (min 1, max 255, required)
| Layer | What to test | Test count |
|---|---|---|
| Unit | missing, undefined, null, empty string, min boundary (1 char â), max boundary (255 chars â), 256 chars â, wrong type (number) | 8+ tests |
| Integration | one representative: missing title â 400 VALIDATION_ERROR (proves Zod is wired) | 1 test |
| API | one representative: missing title â 400 (verifies HTTP contract) | 1 test |
| E2E | nothing â E2E tests do not test field validation | 0 tests |
Testing a notFound service branch
| Layer | What to test |
|---|---|
| Unit | mock prisma.note.findUnique to return null â verify Errors.notFound() thrown; verify downstream mocks NOT called |
| Integration | request with a real non-existent ID in DB â verify 404 response with correct NOT_FOUND code |
| API | GET /api/notes/:nonExistentId â verify 404 with correct error body |
| E2E | nothing â E2E tests don’t test error branches |
Testing an authorization rule
| Layer | What to test |
|---|---|
| Unit | mock prisma.note.findUnique to return a note with organizationId: "other-org" â verify Errors.forbidden() thrown; verify update mock NOT called |
| Integration | user B requests note owned by user A’s organization â verify 403 FORBIDDEN response and DB unchanged |
| API | user B requests note owned by user A â verify 403 response |
| E2E | verify user B cannot see user A’s notes in the UI (data isolation test) |
Completion
After all layers are generated, provide:
File inventory per layer:
| Layer | Files created | Run command |
|---|---|---|
| Unit | <domain>.schema.test.ts, <domain>.service.test.ts, schema.helper.ts, <domain>.unit-factory.ts |
vitest run src/modules/<domain>/test/unit/ |
| Integration | <endpoint>.test.ts (ÃN), <domain>.service.test.ts, database.helper.ts, auth.helper.ts, <domain>.fixture.ts, api-utils |
yarn test:integration |
| API | <method>-<endpoint>.spec.ts (ÃN), <domain>.factory.ts, <domain>.api-utils.ts, <domain>.cleanup.ts |
npx playwright test --project=api |
| E2E | <domain>.<feature>.spec.ts, <domain>.page.ts, <domain>.factory.ts, setup.ts, cleanup.ts |
npx playwright test --project=chromium |