plugins/lt-dev/skills/building-stories-with-tdd/SKILL.md
Orchestrates Test-Driven Development (TDD) workflows for user stories and features. Creates story tests first in tests/stories/, then iteratively implements until all pass. Invoke directly when a developer requests "TDD", "test-driven", "test first", "story test", "write tests before code", or feature implementation with TDD. Coordinates with generating-nest-servers (backend) and developing-lt-frontend (frontend). NOT for direct NestJS coding without TDD (use generating-nest-servers). NOT for standalone test generation (use /test-generate).
npx skillsauth add lennetech/claude-code building-stories-with-tddInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are an expert in Test-Driven Development (TDD) for NestJS applications using @lenne.tech/nest-server. You help developers implement new features by first creating comprehensive story tests, then iteratively developing the code until all tests pass.
describe, it, expect) without imports; Jest requires import { describe, it, expect } from '@jest/globals'. Mixing styles produces misleading error messages ("global not defined") that look like runtime failures. Check vitest.config.ts vs jest.config.ts first.@test.com — The cleanup regex in TestHelper uses @test.com as its deletion filter. Using @example.com or @user.de for test data leaves records in the test DB after the run ends, polluting subsequent test runs. This applies to both backend story tests and frontend Playwright fixtures.declare on test-created Models — Same gotcha as generating-nest-servers: declare removes the field at compile-time, so Typegoose decorators are lost. Test data that persists "successfully" but is missing fields in DB queries almost always traces back to a declare.tests/stories/ — The runner auto-discovers from this path. Placing them in tests/ or src/__tests__/ means they silently don't run. Backend: projects/api/tests/stories/<feature>.e2e-spec.ts. Frontend E2E: projects/app/tests/<feature>.spec.ts.TDD works in the Lerna fullstack monorepo created via lt fullstack init:
projects/api/tests/stories/): API tests for nest-server-starter / @lenne.tech/nest-serverprojects/app/tests/): Playwright tests for nuxt-base-starter / @lenne.tech/nuxt-extensionsALWAYS use this skill for:
For fullstack projects, follow this order:
Phase 1: BACKEND
├── 1. Write Backend Tests (API tests for REST/GraphQL)
└── 2. Implement Backend against tests (iterate until green)
Phase 2: FRONTEND
├── 3. Write Frontend E2E Tests (Playwright)
└── 4. Implement Frontend against tests (iterate until green)
Phase 3: VERIFICATION
└── 5. Debug with Chrome DevTools MCP (default for direct testing/debugging)
Complete workflow details: fullstack-tdd-workflow.md
When ALL of these conditions are met, use parallel test writing via coordinating-agent-teams Pattern 2 (Parallel With Handoff):
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1)projects/api/ AND projects/app/)Parallel workflow:
Phase 0: CONTRACT DEFINITION (Lead)
└── Define API contracts from story requirements (endpoints, request/response shapes)
Phase 1: PARALLEL TEST WRITING (2 teammates, simultaneous)
├── Teammate "backend-tests": Write API tests using contracts → share via message
└── Teammate "frontend-tests": Write E2E tests using contracts → consume API shapes
Phase 2: CONTRACT VALIDATION (Lead)
└── Verify backend and frontend tests reference consistent contracts
Phase 3: SEQUENTIAL IMPLEMENTATION (standard TDD)
├── Backend implementation (iterate until API tests green)
└── Frontend implementation (iterate until E2E tests green)
Key: Only test writing is parallelized. Implementation remains sequential (backend before frontend) because frontend depends on generated types from the running backend API.
Tests MUST be repeatable without side effects:
${Date.now()}-${random} patternsafterAll - Delete all created entitiesapp-test vs app-devafterAll(async () => {
// Delete test-created entities
await db.collection('entities').deleteMany({ createdBy: testUserId });
// Delete test users
await db.collection('users').deleteMany({ email: /@test\.com$/ });
});
Why this matters: Enables unlimited test runs without manual database cleanup.
BEFORE writing or running ANY test, mirror the project's existing framework and import style:
package.json for vitest or jest in dependencies/devDependenciesvitest.config.ts / vitest-e2e.config.ts for globals: true — this flips whether describe/it/expect must be importedpackage.json scripts (e.g., pnpm run test:e2e), never via npx vitest / npx jestlt stack default: @lenne.tech/nest-server and nest-server-starter use Vitest with globals: true in E2E configs — E2E specs do not import from 'vitest'. Unit tests may import explicitly — match the neighbouring file.
Migration projects: Some projects keep Jest (jest:* scripts) next to Vitest (test alias). Within one project, tests/**/*.e2e-spec.ts may use globals while src/**/*.spec.ts uses explicit Vitest imports. Always mirror the nearest existing test file.
Do NOT mix Vitest and Jest syntax in a single test file.
| User Intent | Correct Skill | |------------|---------------| | "Implement with TDD" | THIS SKILL | | "Write tests first" | THIS SKILL | | "Create story tests" | THIS SKILL | | "Create a NestJS module" (no TDD) | generating-nest-servers | | "Fix this service bug" | generating-nest-servers | | "Generate tests for existing code" | /test-generate command | | "Build a Vue page" | developing-lt-frontend |
User-facing command: /lt-dev:resolve-ticket [issue-id | story-file] — Resolves a ticket using this skill
Works closely with:
generating-nest-servers skill - For code implementation (modules, objects, properties)using-lt-cli skill - For Git operations and project initializationdeveloping-lt-frontend skill - For frontend E2E tests and implementationcoordinating-agent-teams skill - For parallel test writing in fullstack projects/lt-dev:create-ticket command - Create any ticket type (Story, Task, Bug)/lt-dev:create-story command - Create a story, then implement with TDD/lt-dev:review command - Comprehensive quality check after implementation (Step 5a)/lt-dev:backend:sec-review command - nest-server specific security reviewUse the LSP tool when available for faster and more accurate code analysis:
| Operation | Use Case in TDD |
|-----------|-----------------|
| goToDefinition | Navigate to Controller/Service/Model definitions |
| findReferences | Find all usages of a method or property |
| hover | Get type info for parameters and return types |
| documentSymbol | List all methods in a Controller or Service |
| goToImplementation | Find Service implementations of interfaces |
When to use LSP (especially Step 1 & 4):
documentSymbol on Controllerhover, goToDefinitionfindReferences, goToImplementationInstallation (if LSP not available):
claude plugins install typescript-lsp --marketplace claude-plugins-official
testHelper.rest() / testHelper.graphQl(). NEVER call Services directly or query DB in test logic. Exception: DB access only for setup/cleanup (roles, verified status).Full details: workflow.md -> Steps 1, 2, and 4
Complete workflow details: workflow.md
Process: Step 1 (Analysis) -> Step 2 (Create Test) -> Step 3 (Run Tests) -> [Step 3a: Fix Tests if needed] -> Step 4 (Implement) -> Step 5 (Validate) -> Step 5a (Quality Check) -> Step 5b (Final Validation)
Details: workflow.md -> Step 1
Details: workflow.md -> Step 2
CRITICAL: Test through API only - NEVER direct Service/DB access!
testHelper.rest() or testHelper.graphQl()Test Data Rules (parallel execution):
@test.com (use: user-${Date.now()}-${Math.random().toString(36).substring(2, 8)}@test.com)afterAllDetails: workflow.md -> Step 3
# NODE_ENV=e2e is set in package.json scripts for local test execution
pnpm test # Or: pnpm test -- tests/stories/your-story.story.test.ts
Decide: Test bugs -> Step 3a | Implementation missing -> Step 4
If this step requires a live dev server (e.g. Playwright E2E against nuxt dev, or an API server for REST/GraphQL probes): follow the managing-dev-servers skill. For lt-projects: use lt dev up (stable HTTPS URLs, no 3000/3001 collision with other parallel sessions) and lt dev down between or after iterations. For non-lt-projects: run_in_background: true + pkill afterwards. Never leave dev servers orphaned between TDD iterations.
Details: workflow.md -> Step 3a
Fix test logic/errors. NEVER "fix" by removing security. Return to Step 3 after fixing.
Details: workflow.md -> Step 4
Use generating-nest-servers skill for: Module/object creation, understanding existing code
Critical Rules:
ENGLISH (GERMAN) when user provides German commentscurrentUser), NOT all options@UseGuards(AuthGuard(...)) - automatically activated by @Roles()database-indexes.md)Details: workflow.md -> Step 5
pnpm test
All pass -> Step 5a | Fail -> Return to Step 3
Details: workflow.md -> Step 5a
Review: Code quality (code-quality.md), Database indexes (database-indexes.md), Security (security-review.md). Run /lt-dev:review for general security scan. Run tests after changes.
Details: workflow.md -> Step 5b
Run all tests, verify quality checks, generate final report. DONE!
Complete details: handling-existing-tests.md
When your changes break existing tests:
git show HEAD, git diff), fix to satisfy both old & new testsRemember: Existing tests document expected behavior - preserve backward compatibility!
NEVER create git commits unless explicitly requested by the developer.
Your responsibility:
You may remind in final report: "Implementation complete - review and commit when ready."
Complete details: security-review.md Extended with OWASP practices: Error Handling & Logging, Cryptographic Practices, Session & Token Management
@Restricted() or @Roles() decoratorssecurityCheck() to bypass security@UseGuards(AuthGuard(...)) manually (automatically activated by @Roles())When tests fail due to security: Create proper test users with appropriate roles, NEVER remove security decorators.
Complete details: code-quality.md
Must follow:
Test quality:
NEVER use declare keyword - it prevents decorators from working!
Work autonomously: Create tests, run tests, fix code, iterate Steps 3-5, use nest-server-generator skill
Only ask when: Story ambiguous, security changes needed, new packages, architectural decisions, persistent failures
When all tests pass, provide comprehensive report including:
/lt-dev:review results (general security scan findings)Complete patterns and examples: examples.md and reference.md
Study existing tests first! Common patterns:
/auth/signin, set roles/verified via DBtestHelper.rest('/api/...', { method, payload, token, statusCode })testHelper.graphQl({ name, type, arguments, fields }, { token })describe blocks for Happy Path, Error Cases, Edge CasesDuring Step 4 (Implementation), use generating-nest-servers skill for:
lt server module)lt server object)lt server addProp)Best Practice: Invoke skill for NestJS component work rather than manual editing.
development
Single source of truth for the lenne.tech fullstack production-readiness checklist. Defines the eight pillars (configuration & secrets, observability & logging, health & lifecycle, security hardening, data durability, resilience under load, deployment hygiene, runbook & rollback) with concrete file/line evidence requirements per pillar, severity classification (Critical / Major / Minor), and a canonical machine-parseable report block. Activates whenever an agent or command needs to gate a release on production-readiness — currently used by /lt-dev:production-ready, lt-dev:production-readiness-orchestrator, and the devops-reviewer (read-only). NOT for OWASP-style code-level security review (use security-reviewer). NOT for npm dependency audits (use maintaining-npm-packages).
development
Single source of truth for executing GitLab CI/CD pipelines locally with the same image, env vars, and service containers as the real runner — so pipeline failures are caught before push. Defines pipeline discovery (.gitlab-ci.yml + includes), per-job execution via gitlab-runner exec, service-container orchestration (Mongo, Redis, MailHog), env injection without secrets, cache/artifact handling, and a job-by-job verdict report. Also describes the GitHub Actions equivalent via act for projects that mirror to GitHub. Activates whenever an agent or command needs to validate that the CI pipeline will pass — currently used by /lt-dev:production-ready and lt-dev:production-readiness-orchestrator. NOT for running the local check script (use running-check-script). NOT for writing or refactoring CI configs (use the devops agent).
development
Single source of truth for designing, running, and interpreting k6 load tests against lenne.tech fullstack APIs. Defines installation paths (brew, docker, npm), the three canonical scenarios (smoke / load / soak), endpoint discovery from the generated SDK, realistic Better-Auth login flows, threshold defaults for ~10 concurrent users (p95 < 500ms, error rate < 1%, http_req_failed < 1%), result interpretation, and the optimisation ladder when the system fails (DB indices, query rewrites, caching, connection pool sizing, rate-limit relaxation, payload trimming). Activates whenever an agent or command needs to validate that the API is stable for ~10 concurrent users performing many actions in short time, or to detect performance regressions via k6. Currently used by /lt-dev:production-ready, lt-dev:production-readiness-orchestrator, and lt-dev:performance-reviewer. NOT for Lighthouse frontend performance (use a11y-reviewer). NOT for unit performance assertions (use the test runner directly).
tools
Migrates lenne.tech projects from the legacy jest+eslint+prettier toolchain to the current vitest+oxlint+oxfmt baseline used by nest-server-starter and nuxt-base-starter. Covers swc decoratorMetadata config, the @Prop union-type fix for SWC, supertest default-import correction, ESM/CJS interop, the Nitro PORT-vs-NITRO_PORT bug, ANSI escape stripping in workspace runners (lerna/nx), free-port logic for check-server-start.sh, the offers-pattern config.env.ts (NSC__-only + fail-fast + auto-derived appUrl), and the multi-phase check-envs.sh smoke test. Activates whenever someone is migrating an existing project to the new toolchain, debugging "Cannot determine a type for the X field" Mongoose errors, ERR_SOCKET_BAD_PORT crashes from check-server-start, or wants to align an existing project with the current starter conventions.