specweave 0.23.18 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/.claude-plugin/marketplace.json +144 -45
  2. package/CLAUDE.md +137 -4
  3. package/dist/src/cli/helpers/ado-area-path-mapper.d.ts +89 -0
  4. package/dist/src/cli/helpers/ado-area-path-mapper.d.ts.map +1 -0
  5. package/dist/src/cli/helpers/ado-area-path-mapper.js +213 -0
  6. package/dist/src/cli/helpers/ado-area-path-mapper.js.map +1 -0
  7. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.d.ts +29 -0
  8. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.d.ts.map +1 -0
  9. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js +109 -0
  10. package/dist/src/cli/helpers/issue-tracker/ado-auto-discover.js.map +1 -0
  11. package/dist/src/cli/helpers/issue-tracker/ado.d.ts +1 -0
  12. package/dist/src/cli/helpers/issue-tracker/ado.d.ts.map +1 -1
  13. package/dist/src/cli/helpers/issue-tracker/ado.js +2 -0
  14. package/dist/src/cli/helpers/issue-tracker/ado.js.map +1 -1
  15. package/dist/src/cli/helpers/smart-filter.d.ts +83 -0
  16. package/dist/src/cli/helpers/smart-filter.d.ts.map +1 -0
  17. package/dist/src/cli/helpers/smart-filter.js +265 -0
  18. package/dist/src/cli/helpers/smart-filter.js.map +1 -0
  19. package/dist/src/core/qa/quality-gate-decider.d.ts +1 -1
  20. package/dist/src/core/qa/quality-gate-decider.js +2 -2
  21. package/dist/src/core/qa/quality-gate-decider.js.map +1 -1
  22. package/dist/src/core/qa/risk-calculator.d.ts +2 -2
  23. package/dist/src/core/qa/risk-calculator.js +2 -2
  24. package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
  25. package/dist/src/core/repo-structure/repo-structure-manager.js +76 -43
  26. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  27. package/dist/src/core/validators/ac-presence-validator.d.ts +56 -0
  28. package/dist/src/core/validators/ac-presence-validator.d.ts.map +1 -0
  29. package/dist/src/core/validators/ac-presence-validator.js +149 -0
  30. package/dist/src/core/validators/ac-presence-validator.js.map +1 -0
  31. package/dist/src/integrations/ado/area-path-mapper.d.ts +137 -0
  32. package/dist/src/integrations/ado/area-path-mapper.d.ts.map +1 -0
  33. package/dist/src/integrations/ado/area-path-mapper.js +267 -0
  34. package/dist/src/integrations/ado/area-path-mapper.js.map +1 -0
  35. package/dist/src/integrations/jira/filter-processor.d.ts +126 -0
  36. package/dist/src/integrations/jira/filter-processor.d.ts.map +1 -0
  37. package/dist/src/integrations/jira/filter-processor.js +207 -0
  38. package/dist/src/integrations/jira/filter-processor.js.map +1 -0
  39. package/dist/src/integrations/jira/jira-client.d.ts +13 -0
  40. package/dist/src/integrations/jira/jira-client.d.ts.map +1 -1
  41. package/dist/src/integrations/jira/jira-client.js +33 -0
  42. package/dist/src/integrations/jira/jira-client.js.map +1 -1
  43. package/dist/src/utils/ac-embedder.d.ts +63 -0
  44. package/dist/src/utils/ac-embedder.d.ts.map +1 -0
  45. package/dist/src/utils/ac-embedder.js +217 -0
  46. package/dist/src/utils/ac-embedder.js.map +1 -0
  47. package/dist/src/utils/env-manager.d.ts +86 -0
  48. package/dist/src/utils/env-manager.d.ts.map +1 -0
  49. package/dist/src/utils/env-manager.js +188 -0
  50. package/dist/src/utils/env-manager.js.map +1 -0
  51. package/package.json +1 -1
  52. package/plugins/specweave/.claude-plugin/plugin.json +1 -1
  53. package/plugins/specweave/agents/AGENTS-INDEX.md +1 -1
  54. package/plugins/specweave/agents/increment-quality-judge-v2/AGENT.md +9 -9
  55. package/plugins/specweave/commands/specweave-do.md +37 -0
  56. package/plugins/specweave/commands/specweave-done.md +159 -0
  57. package/plugins/specweave/commands/specweave-embed-acs.md +446 -0
  58. package/plugins/specweave/commands/specweave-next.md +148 -3
  59. package/plugins/specweave/commands/specweave-qa.md +2 -2
  60. package/plugins/specweave/hooks/pre-increment-start.sh +168 -0
  61. package/plugins/specweave/skills/SKILLS-INDEX.md +1 -1
  62. package/plugins/specweave-ado/.claude-plugin/plugin.json +1 -1
  63. package/plugins/specweave-ado/commands/specweave-ado-import-projects.md +331 -0
  64. package/plugins/specweave-alternatives/.claude-plugin/plugin.json +10 -0
  65. package/plugins/specweave-alternatives/commands/alternatives-analyze.md +336 -0
  66. package/plugins/specweave-alternatives/skills/architecture-alternatives/SKILL.md +651 -0
  67. package/plugins/specweave-alternatives/skills/bmad-method/SKILL.md +420 -0
  68. package/plugins/specweave-alternatives/skills/spec-kit-expert/SKILL.md +487 -0
  69. package/plugins/specweave-backend/commands/api-scaffold.md +80 -0
  70. package/plugins/specweave-backend/commands/crud-generate.md +109 -0
  71. package/plugins/specweave-backend/commands/migration-generate.md +139 -0
  72. package/plugins/specweave-confluent/commands/connector-deploy.md +154 -0
  73. package/plugins/specweave-confluent/commands/ksqldb-query.md +179 -0
  74. package/plugins/specweave-confluent/commands/schema-register.md +123 -0
  75. package/plugins/specweave-core/.claude-plugin/plugin.json +21 -0
  76. package/plugins/specweave-core/commands/architecture-review.md +288 -0
  77. package/plugins/specweave-core/commands/code-review.md +213 -0
  78. package/plugins/specweave-core/commands/refactor-plan.md +249 -0
  79. package/plugins/specweave-core/skills/code-quality/SKILL.md +157 -0
  80. package/plugins/specweave-core/skills/design-patterns/SKILL.md +244 -0
  81. package/plugins/specweave-core/skills/software-architecture/SKILL.md +83 -0
  82. package/plugins/specweave-cost-optimizer/.claude-plugin/plugin.json +22 -0
  83. package/plugins/specweave-cost-optimizer/commands/cost-analyze.md +360 -0
  84. package/plugins/specweave-cost-optimizer/commands/cost-optimize.md +480 -0
  85. package/plugins/specweave-cost-optimizer/skills/aws-cost-expert/SKILL.md +416 -0
  86. package/plugins/specweave-cost-optimizer/skills/cloud-pricing/SKILL.md +325 -0
  87. package/plugins/specweave-cost-optimizer/skills/cost-optimization/SKILL.md +337 -0
  88. package/plugins/specweave-diagrams/.claude-plugin/plugin.json +1 -1
  89. package/plugins/specweave-diagrams/commands/diagrams-generate.md +168 -0
  90. package/plugins/specweave-docs/.claude-plugin/plugin.json +10 -0
  91. package/plugins/specweave-docs/commands/docs-generate.md +441 -0
  92. package/plugins/specweave-docs/commands/docs-init.md +334 -0
  93. package/plugins/specweave-docs/skills/docusaurus/SKILL.md +581 -0
  94. package/plugins/specweave-docs/skills/spec-driven-brainstorming/SKILL.md +689 -0
  95. package/plugins/specweave-docs/skills/technical-writing/SKILL.md +1039 -0
  96. package/plugins/specweave-docs-preview/.claude-plugin/plugin.json +1 -1
  97. package/plugins/specweave-figma/.claude-plugin/plugin.json +23 -0
  98. package/plugins/specweave-figma/commands/figma-import.md +690 -0
  99. package/plugins/specweave-figma/commands/figma-to-react.md +834 -0
  100. package/plugins/specweave-figma/commands/figma-tokens.md +815 -0
  101. package/plugins/specweave-frontend/.claude-plugin/plugin.json +21 -0
  102. package/plugins/specweave-frontend/agents/frontend-architect/AGENT.md +408 -0
  103. package/plugins/specweave-frontend/agents/frontend-architect/README.md +385 -0
  104. package/plugins/specweave-frontend/agents/frontend-architect/examples.md +590 -0
  105. package/plugins/specweave-frontend/agents/frontend-architect/templates/component-template.tsx +152 -0
  106. package/plugins/specweave-frontend/agents/frontend-architect/templates/hook-template.ts +311 -0
  107. package/plugins/specweave-frontend/agents/frontend-architect/templates/page-template.tsx +228 -0
  108. package/plugins/specweave-frontend/commands/component-generate.md +510 -0
  109. package/plugins/specweave-frontend/commands/design-system-init.md +494 -0
  110. package/plugins/specweave-frontend/commands/frontend-scaffold.md +207 -0
  111. package/plugins/specweave-frontend/commands/nextjs-setup.md +396 -0
  112. package/plugins/specweave-frontend/skills/design-system-architect/SKILL.md +278 -0
  113. package/plugins/specweave-frontend/skills/frontend/SKILL.md +420 -0
  114. package/plugins/specweave-frontend/skills/nextjs/SKILL.md +546 -0
  115. package/plugins/specweave-github/.claude-plugin/plugin.json +1 -1
  116. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +212 -0
  117. package/plugins/specweave-infrastructure/.claude-plugin/plugin.json +1 -1
  118. package/plugins/specweave-jira/.claude-plugin/plugin.json +1 -1
  119. package/plugins/specweave-jira/commands/import-projects.js +183 -0
  120. package/plugins/specweave-jira/commands/import-projects.md +97 -0
  121. package/plugins/specweave-jira/commands/import-projects.ts +288 -0
  122. package/plugins/specweave-jira/commands/specweave-jira-import-projects.md +298 -0
  123. package/plugins/specweave-kafka/.claude-plugin/plugin.json +1 -1
  124. package/plugins/specweave-kafka-streams/.claude-plugin/plugin.json +1 -1
  125. package/plugins/specweave-kubernetes/commands/cluster-setup.md +262 -0
  126. package/plugins/specweave-kubernetes/commands/deployment-generate.md +242 -0
  127. package/plugins/specweave-kubernetes/commands/helm-scaffold.md +333 -0
  128. package/plugins/specweave-ml/.claude-plugin/plugin.json +1 -1
  129. package/plugins/specweave-mobile/commands/app-scaffold.md +233 -0
  130. package/plugins/specweave-mobile/commands/build-config.md +256 -0
  131. package/plugins/specweave-mobile/commands/screen-generate.md +289 -0
  132. package/plugins/specweave-n8n/.claude-plugin/plugin.json +1 -1
  133. package/plugins/specweave-payments/commands/stripe-setup.md +931 -0
  134. package/plugins/specweave-payments/commands/subscription-flow.md +1193 -0
  135. package/plugins/specweave-payments/commands/subscription-manage.md +386 -0
  136. package/plugins/specweave-payments/commands/webhook-setup.md +295 -0
  137. package/plugins/specweave-plugin-dev/.claude-plugin/plugin.json +13 -12
  138. package/plugins/specweave-plugin-dev/commands/plugin-create.md +333 -0
  139. package/plugins/specweave-plugin-dev/commands/plugin-publish.md +339 -0
  140. package/plugins/specweave-plugin-dev/commands/plugin-test.md +293 -0
  141. package/plugins/specweave-plugin-dev/skills/claude-sdk/SKILL.md +162 -0
  142. package/plugins/specweave-plugin-dev/skills/marketplace-publishing/SKILL.md +263 -0
  143. package/plugins/specweave-plugin-dev/skills/plugin-development/SKILL.md +316 -0
  144. package/plugins/specweave-release/.claude-plugin/plugin.json +1 -1
  145. package/plugins/specweave-release/commands/specweave-release-npm.md +110 -0
  146. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +168 -0
  147. package/plugins/specweave-testing/.claude-plugin/plugin.json +21 -0
  148. package/plugins/specweave-testing/agents/qa-engineer/AGENT.md +818 -0
  149. package/plugins/specweave-testing/agents/qa-engineer/README.md +443 -0
  150. package/plugins/specweave-testing/agents/qa-engineer/templates/playwright-e2e-test.ts +470 -0
  151. package/plugins/specweave-testing/agents/qa-engineer/templates/test-data-factory.ts +507 -0
  152. package/plugins/specweave-testing/agents/qa-engineer/templates/vitest-unit-test.ts +400 -0
  153. package/plugins/specweave-testing/agents/qa-engineer/test-strategies.md +726 -0
  154. package/plugins/specweave-testing/commands/e2e-setup.md +1081 -0
  155. package/plugins/specweave-testing/commands/test-coverage.md +979 -0
  156. package/plugins/specweave-testing/commands/test-generate.md +1156 -0
  157. package/plugins/specweave-testing/commands/test-init.md +409 -0
  158. package/plugins/specweave-testing/skills/e2e-playwright/SKILL.md +769 -0
  159. package/plugins/specweave-testing/skills/tdd-expert/SKILL.md +934 -0
  160. package/plugins/specweave-testing/skills/unit-testing-expert/SKILL.md +1011 -0
  161. package/plugins/specweave-tooling/.claude-plugin/plugin.json +22 -0
  162. package/plugins/specweave-tooling/commands/specweave-tooling-skill-create.md +691 -0
  163. package/plugins/specweave-tooling/commands/specweave-tooling-skill-package.md +751 -0
  164. package/plugins/specweave-tooling/commands/specweave-tooling-skill-validate.md +858 -0
  165. package/plugins/specweave-ui/.claude-plugin/plugin.json +10 -0
  166. package/plugins/specweave-ui/commands/ui-automate.md +199 -0
  167. package/plugins/specweave-ui/commands/ui-inspect.md +70 -0
  168. package/plugins/specweave-ui/skills/browser-automation/SKILL.md +314 -0
  169. package/plugins/specweave-ui/skills/ui-testing/SKILL.md +716 -0
  170. package/plugins/specweave-ui/skills/visual-regression/SKILL.md +728 -0
  171. package/plugins/specweave/commands/check-hooks.md +0 -257
  172. package/plugins/specweave/commands/specweave-archive-increments.md +0 -82
  173. package/plugins/specweave-plugin-dev/skills/plugin-expert/SKILL.md +0 -1231
  174. /package/plugins/specweave/{agents/code-reviewer.md → skills/code-reviewer/SKILL.md} +0 -0
@@ -0,0 +1,934 @@
1
+ ---
2
+ name: tdd-expert
3
+ description: Test-Driven Development (TDD) expertise covering red-green-refactor cycle, behavior-driven development, test-first design, refactoring with confidence, TDD best practices, TDD workflow, unit testing strategies, mock-driven development, test doubles, TDD patterns, SOLID principles through testing, emergent design, incremental development, TDD anti-patterns, and production-grade TDD practices. Activates for TDD, test-driven development, red-green-refactor, test-first, behavior-driven, BDD, refactoring, test doubles, mock-driven, test design, SOLID principles, emergent design, incremental development, TDD workflow, TDD best practices, TDD patterns, Kent Beck, Robert Martin, Uncle Bob, test-first design.
4
+ ---
5
+
6
+ # Test-Driven Development (TDD) Expert
7
+
8
+ ## Core Philosophy
9
+
10
+ Test-Driven Development is a software development approach where tests are written BEFORE the implementation code. This forces better design, ensures testability, and provides a safety net for refactoring.
11
+
12
+ **Core Principle**: "Red, Green, Refactor"
13
+
14
+ ## The TDD Cycle
15
+
16
+ ### 1. Red Phase: Write a Failing Test
17
+
18
+ **Goal**: Define expected behavior through a test that fails
19
+
20
+ ```typescript
21
+ import { describe, it, expect } from 'vitest';
22
+ import { Calculator } from './Calculator';
23
+
24
+ describe('Calculator', () => {
25
+ it('should add two numbers', () => {
26
+ const calculator = new Calculator();
27
+
28
+ // This test WILL fail because Calculator doesn't exist yet
29
+ expect(calculator.add(2, 3)).toBe(5);
30
+ });
31
+ });
32
+ ```
33
+
34
+ **Red Phase Checklist**:
35
+ - [ ] Test describes ONE specific behavior
36
+ - [ ] Test fails for the RIGHT reason (not syntax error)
37
+ - [ ] Test is readable and understandable
38
+ - [ ] Expected behavior is clear from test name
39
+
40
+ **Common Mistakes in Red Phase**:
41
+ - Writing multiple assertions in one test
42
+ - Testing implementation details instead of behavior
43
+ - Writing tests that pass immediately (no value!)
44
+ - Unclear test names
45
+
46
+ ### 2. Green Phase: Make It Pass (Minimal Implementation)
47
+
48
+ **Goal**: Write the simplest code that makes the test pass
49
+
50
+ ```typescript
51
+ // Calculator.ts
52
+ export class Calculator {
53
+ add(a: number, b: number): number {
54
+ return 5; // Hardcoded! But test passes
55
+ }
56
+ }
57
+ ```
58
+
59
+ **Wait, hardcoded 5?** Yes! This is intentional. The green phase is about making tests pass with minimal code. The next test will force us to generalize.
60
+
61
+ **Add another test** (triangulation):
62
+ ```typescript
63
+ it('should add different numbers', () => {
64
+ const calculator = new Calculator();
65
+ expect(calculator.add(10, 20)).toBe(30); // Now hardcoded 5 fails!
66
+ });
67
+ ```
68
+
69
+ **Now implement properly**:
70
+ ```typescript
71
+ export class Calculator {
72
+ add(a: number, b: number): number {
73
+ return a + b; // Generalized solution
74
+ }
75
+ }
76
+ ```
77
+
78
+ **Green Phase Checklist**:
79
+ - [ ] All tests pass
80
+ - [ ] Implementation is minimal (no premature optimization)
81
+ - [ ] No extra features beyond what tests require
82
+ - [ ] Code is simple and direct
83
+
84
+ **Common Mistakes in Green Phase**:
85
+ - Over-engineering the solution
86
+ - Adding features not covered by tests
87
+ - Premature optimization
88
+ - Skipping the refactor phase
89
+
90
+ ### 3. Refactor Phase: Improve Code Quality
91
+
92
+ **Goal**: Improve code structure while keeping all tests green
93
+
94
+ ```typescript
95
+ // Before refactoring
96
+ export class Calculator {
97
+ add(a: number, b: number): number {
98
+ return a + b;
99
+ }
100
+
101
+ subtract(a: number, b: number): number {
102
+ return a - b;
103
+ }
104
+
105
+ multiply(a: number, b: number): number {
106
+ return a * b;
107
+ }
108
+
109
+ divide(a: number, b: number): number {
110
+ if (b === 0) {
111
+ throw new Error('Division by zero');
112
+ }
113
+ return a / b;
114
+ }
115
+ }
116
+ ```
117
+
118
+ **Refactored with better design**:
119
+ ```typescript
120
+ // Extract operation interface
121
+ interface Operation {
122
+ execute(a: number, b: number): number;
123
+ }
124
+
125
+ class AddOperation implements Operation {
126
+ execute(a: number, b: number): number {
127
+ return a + b;
128
+ }
129
+ }
130
+
131
+ class DivideOperation implements Operation {
132
+ execute(a: number, b: number): number {
133
+ if (b === 0) {
134
+ throw new Error('Division by zero');
135
+ }
136
+ return a / b;
137
+ }
138
+ }
139
+
140
+ export class Calculator {
141
+ private operations: Map<string, Operation> = new Map([
142
+ ['add', new AddOperation()],
143
+ ['divide', new DivideOperation()],
144
+ ]);
145
+
146
+ perform(operation: string, a: number, b: number): number {
147
+ const op = this.operations.get(operation);
148
+ if (!op) {
149
+ throw new Error(`Unknown operation: ${operation}`);
150
+ }
151
+ return op.execute(a, b);
152
+ }
153
+ }
154
+ ```
155
+
156
+ **Refactor Phase Checklist**:
157
+ - [ ] All tests still pass
158
+ - [ ] Code is more readable
159
+ - [ ] Duplication removed (DRY principle)
160
+ - [ ] Code follows SOLID principles
161
+ - [ ] Better separation of concerns
162
+ - [ ] No new functionality added
163
+
164
+ **Refactoring Patterns**:
165
+ - Extract Method/Function
166
+ - Extract Class
167
+ - Introduce Parameter Object
168
+ - Replace Conditional with Polymorphism
169
+ - Extract Interface
170
+ - Rename for clarity
171
+
172
+ ## TDD Best Practices
173
+
174
+ ### 1. Test Behavior, Not Implementation
175
+
176
+ **❌ BAD: Testing implementation details**
177
+ ```typescript
178
+ it('should call internal helper method', () => {
179
+ const spy = vi.spyOn(calculator, '_internalHelper');
180
+ calculator.add(2, 3);
181
+ expect(spy).toHaveBeenCalled(); // Brittle! Breaks on refactor
182
+ });
183
+ ```
184
+
185
+ **✅ GOOD: Testing behavior**
186
+ ```typescript
187
+ it('should return sum of two numbers', () => {
188
+ expect(calculator.add(2, 3)).toBe(5); // Robust!
189
+ });
190
+ ```
191
+
192
+ ### 2. One Assertion Per Test (When Possible)
193
+
194
+ **❌ BAD: Multiple unrelated assertions**
195
+ ```typescript
196
+ it('should validate user', () => {
197
+ expect(user.name).toBe('John');
198
+ expect(user.email).toBe('john@example.com');
199
+ expect(user.isActive).toBe(true);
200
+ expect(user.roles).toContain('admin');
201
+ });
202
+ ```
203
+
204
+ **✅ GOOD: Focused tests**
205
+ ```typescript
206
+ it('should have correct name', () => {
207
+ expect(user.name).toBe('John');
208
+ });
209
+
210
+ it('should have valid email', () => {
211
+ expect(user.email).toBe('john@example.com');
212
+ });
213
+
214
+ it('should be active by default', () => {
215
+ expect(user.isActive).toBe(true);
216
+ });
217
+
218
+ it('should include admin role', () => {
219
+ expect(user.roles).toContain('admin');
220
+ });
221
+ ```
222
+
223
+ ### 3. Test Edge Cases and Boundaries
224
+
225
+ **Test pyramid for a single function**:
226
+ 1. Happy path (normal input)
227
+ 2. Edge cases (empty, null, boundary values)
228
+ 3. Error cases (invalid input)
229
+
230
+ ```typescript
231
+ describe('divide', () => {
232
+ // Happy path
233
+ it('should divide two positive numbers', () => {
234
+ expect(calculator.divide(10, 2)).toBe(5);
235
+ });
236
+
237
+ // Edge cases
238
+ it('should handle division resulting in decimal', () => {
239
+ expect(calculator.divide(5, 2)).toBe(2.5);
240
+ });
241
+
242
+ it('should handle negative numbers', () => {
243
+ expect(calculator.divide(-10, 2)).toBe(-5);
244
+ });
245
+
246
+ it('should handle zero dividend', () => {
247
+ expect(calculator.divide(0, 5)).toBe(0);
248
+ });
249
+
250
+ // Error case
251
+ it('should throw error for division by zero', () => {
252
+ expect(() => calculator.divide(10, 0)).toThrow('Division by zero');
253
+ });
254
+ });
255
+ ```
256
+
257
+ ### 4. Use Descriptive Test Names
258
+
259
+ **Pattern**: `should [expected behavior] when [condition]`
260
+
261
+ ```typescript
262
+ // ✅ GOOD: Clear and descriptive
263
+ it('should return empty array when no users exist', () => { ... });
264
+ it('should throw ValidationError when email is invalid', () => { ... });
265
+ it('should apply discount when user has premium membership', () => { ... });
266
+
267
+ // ❌ BAD: Vague and unclear
268
+ it('works', () => { ... });
269
+ it('test user creation', () => { ... });
270
+ it('returns data', () => { ... });
271
+ ```
272
+
273
+ ### 5. Follow AAA Pattern (Arrange-Act-Assert)
274
+
275
+ ```typescript
276
+ it('should calculate total with discount', () => {
277
+ // ARRANGE: Set up test data and dependencies
278
+ const cart = new ShoppingCart();
279
+ cart.addItem({ name: 'Book', price: 20 });
280
+ cart.addItem({ name: 'Pen', price: 5 });
281
+ const discountCode = 'SAVE10';
282
+
283
+ // ACT: Execute the behavior under test
284
+ const total = cart.calculateTotal(discountCode);
285
+
286
+ // ASSERT: Verify the result
287
+ expect(total).toBe(22.5); // 25 * 0.9 = 22.5
288
+ });
289
+ ```
290
+
291
+ ### 6. Test Isolation (No Shared State)
292
+
293
+ **❌ BAD: Shared state between tests**
294
+ ```typescript
295
+ let user: User; // SHARED STATE!
296
+
297
+ beforeAll(() => {
298
+ user = new User('John'); // Created once
299
+ });
300
+
301
+ it('should update name', () => {
302
+ user.updateName('Jane'); // MUTATES SHARED STATE
303
+ expect(user.name).toBe('Jane');
304
+ });
305
+
306
+ it('should have original name', () => {
307
+ expect(user.name).toBe('John'); // FAILS! Name is 'Jane' from previous test
308
+ });
309
+ ```
310
+
311
+ **✅ GOOD: Isolated tests**
312
+ ```typescript
313
+ describe('User', () => {
314
+ let user: User;
315
+
316
+ beforeEach(() => {
317
+ user = new User('John'); // FRESH instance for each test
318
+ });
319
+
320
+ it('should update name', () => {
321
+ user.updateName('Jane');
322
+ expect(user.name).toBe('Jane');
323
+ });
324
+
325
+ it('should have original name', () => {
326
+ expect(user.name).toBe('John'); // PASSES! Fresh instance
327
+ });
328
+ });
329
+ ```
330
+
331
+ ## TDD Workflow Examples
332
+
333
+ ### Example 1: Building a User Validator
334
+
335
+ **Step 1: RED - Write failing test**
336
+ ```typescript
337
+ describe('UserValidator', () => {
338
+ it('should validate email format', () => {
339
+ const validator = new UserValidator();
340
+ expect(validator.validateEmail('user@example.com')).toBe(true);
341
+ });
342
+ });
343
+ ```
344
+
345
+ **Step 2: GREEN - Minimal implementation**
346
+ ```typescript
347
+ export class UserValidator {
348
+ validateEmail(email: string): boolean {
349
+ return true; // Hardcoded! But test passes
350
+ }
351
+ }
352
+ ```
353
+
354
+ **Step 3: Add negative test (triangulation)**
355
+ ```typescript
356
+ it('should reject invalid email', () => {
357
+ const validator = new UserValidator();
358
+ expect(validator.validateEmail('invalid')).toBe(false); // Forces real implementation
359
+ });
360
+ ```
361
+
362
+ **Step 4: GREEN - Real implementation**
363
+ ```typescript
364
+ export class UserValidator {
365
+ validateEmail(email: string): boolean {
366
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
367
+ }
368
+ }
369
+ ```
370
+
371
+ **Step 5: REFACTOR - Extract regex**
372
+ ```typescript
373
+ export class UserValidator {
374
+ private static EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
375
+
376
+ validateEmail(email: string): boolean {
377
+ return UserValidator.EMAIL_REGEX.test(email);
378
+ }
379
+ }
380
+ ```
381
+
382
+ **Step 6: Add more edge cases**
383
+ ```typescript
384
+ it('should reject empty email', () => {
385
+ expect(validator.validateEmail('')).toBe(false);
386
+ });
387
+
388
+ it('should reject null email', () => {
389
+ expect(validator.validateEmail(null as any)).toBe(false);
390
+ });
391
+
392
+ it('should reject email without domain', () => {
393
+ expect(validator.validateEmail('user@')).toBe(false);
394
+ });
395
+ ```
396
+
397
+ **Final refactored implementation**:
398
+ ```typescript
399
+ export class UserValidator {
400
+ private static EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
401
+
402
+ validateEmail(email: string | null | undefined): boolean {
403
+ if (!email || typeof email !== 'string') {
404
+ return false;
405
+ }
406
+ return UserValidator.EMAIL_REGEX.test(email);
407
+ }
408
+ }
409
+ ```
410
+
411
+ ### Example 2: Building a Shopping Cart
412
+
413
+ **RED: Test adding items**
414
+ ```typescript
415
+ describe('ShoppingCart', () => {
416
+ it('should add item to cart', () => {
417
+ const cart = new ShoppingCart();
418
+ cart.addItem({ id: 1, name: 'Book', price: 20 });
419
+
420
+ expect(cart.getItemCount()).toBe(1);
421
+ });
422
+ });
423
+ ```
424
+
425
+ **GREEN: Minimal implementation**
426
+ ```typescript
427
+ interface CartItem {
428
+ id: number;
429
+ name: string;
430
+ price: number;
431
+ }
432
+
433
+ export class ShoppingCart {
434
+ private items: CartItem[] = [];
435
+
436
+ addItem(item: CartItem): void {
437
+ this.items.push(item);
438
+ }
439
+
440
+ getItemCount(): number {
441
+ return this.items.length;
442
+ }
443
+ }
444
+ ```
445
+
446
+ **RED: Test calculating total**
447
+ ```typescript
448
+ it('should calculate total price', () => {
449
+ const cart = new ShoppingCart();
450
+ cart.addItem({ id: 1, name: 'Book', price: 20 });
451
+ cart.addItem({ id: 2, name: 'Pen', price: 5 });
452
+
453
+ expect(cart.getTotal()).toBe(25);
454
+ });
455
+ ```
456
+
457
+ **GREEN: Implement total**
458
+ ```typescript
459
+ export class ShoppingCart {
460
+ // ... previous code ...
461
+
462
+ getTotal(): number {
463
+ return this.items.reduce((sum, item) => sum + item.price, 0);
464
+ }
465
+ }
466
+ ```
467
+
468
+ **RED: Test removing items**
469
+ ```typescript
470
+ it('should remove item from cart', () => {
471
+ const cart = new ShoppingCart();
472
+ cart.addItem({ id: 1, name: 'Book', price: 20 });
473
+ cart.removeItem(1);
474
+
475
+ expect(cart.getItemCount()).toBe(0);
476
+ });
477
+ ```
478
+
479
+ **GREEN: Implement remove**
480
+ ```typescript
481
+ export class ShoppingCart {
482
+ // ... previous code ...
483
+
484
+ removeItem(itemId: number): void {
485
+ this.items = this.items.filter(item => item.id !== itemId);
486
+ }
487
+ }
488
+ ```
489
+
490
+ **REFACTOR: Extract calculations**
491
+ ```typescript
492
+ export class ShoppingCart {
493
+ private items: CartItem[] = [];
494
+
495
+ addItem(item: CartItem): void {
496
+ this.items.push(item);
497
+ }
498
+
499
+ removeItem(itemId: number): void {
500
+ this.items = this.items.filter(item => item.id !== itemId);
501
+ }
502
+
503
+ getItemCount(): number {
504
+ return this.items.length;
505
+ }
506
+
507
+ getTotal(): number {
508
+ return this.calculateTotal(this.items);
509
+ }
510
+
511
+ private calculateTotal(items: CartItem[]): number {
512
+ return items.reduce((sum, item) => sum + item.price, 0);
513
+ }
514
+
515
+ isEmpty(): boolean {
516
+ return this.items.length === 0;
517
+ }
518
+ }
519
+ ```
520
+
521
+ ## TDD with Mocks and Test Doubles
522
+
523
+ ### Types of Test Doubles
524
+
525
+ 1. **Dummy**: Objects passed but never used
526
+ 2. **Stub**: Returns predefined values
527
+ 3. **Spy**: Records information about calls
528
+ 4. **Mock**: Verifies interactions
529
+ 5. **Fake**: Working implementation (simplified)
530
+
531
+ ### Example: Testing with Mocks
532
+
533
+ **RED: Test user creation with email service**
534
+ ```typescript
535
+ describe('UserService', () => {
536
+ it('should send welcome email when user created', async () => {
537
+ const emailService = createMockEmailService();
538
+ const userService = new UserService(emailService);
539
+
540
+ await userService.createUser({ name: 'John', email: 'john@example.com' });
541
+
542
+ expect(emailService.sendWelcomeEmail).toHaveBeenCalledWith('john@example.com');
543
+ });
544
+ });
545
+ ```
546
+
547
+ **GREEN: Implementation with dependency injection**
548
+ ```typescript
549
+ interface EmailService {
550
+ sendWelcomeEmail(email: string): Promise<void>;
551
+ }
552
+
553
+ export class UserService {
554
+ constructor(private emailService: EmailService) {}
555
+
556
+ async createUser(userData: { name: string; email: string }): Promise<User> {
557
+ const user = new User(userData);
558
+ await this.emailService.sendWelcomeEmail(user.email);
559
+ return user;
560
+ }
561
+ }
562
+
563
+ // Test helper
564
+ function createMockEmailService(): EmailService {
565
+ return {
566
+ sendWelcomeEmail: vi.fn().mockResolvedValue(undefined),
567
+ };
568
+ }
569
+ ```
570
+
571
+ ## TDD and SOLID Principles
572
+
573
+ TDD naturally leads to SOLID design:
574
+
575
+ ### 1. Single Responsibility Principle (SRP)
576
+
577
+ **TDD forces SRP** because classes with multiple responsibilities are hard to test.
578
+
579
+ ```typescript
580
+ // ❌ BAD: Multiple responsibilities (hard to test!)
581
+ class UserManager {
582
+ createUser() { /* ... */ }
583
+ sendEmail() { /* ... */ }
584
+ saveToDatabase() { /* ... */ }
585
+ validateInput() { /* ... */ }
586
+ }
587
+
588
+ // ✅ GOOD: Single responsibility (easy to test!)
589
+ class UserCreator {
590
+ createUser() { /* ... */ }
591
+ }
592
+
593
+ class EmailSender {
594
+ sendEmail() { /* ... */ }
595
+ }
596
+
597
+ class UserRepository {
598
+ save() { /* ... */ }
599
+ }
600
+
601
+ class UserValidator {
602
+ validate() { /* ... */ }
603
+ }
604
+ ```
605
+
606
+ ### 2. Open/Closed Principle (OCP)
607
+
608
+ **TDD encourages extension through abstraction**
609
+
610
+ ```typescript
611
+ // Extension through interfaces
612
+ interface PaymentProcessor {
613
+ process(amount: number): Promise<PaymentResult>;
614
+ }
615
+
616
+ class StripeProcessor implements PaymentProcessor {
617
+ async process(amount: number): Promise<PaymentResult> {
618
+ // Stripe implementation
619
+ }
620
+ }
621
+
622
+ class PayPalProcessor implements PaymentProcessor {
623
+ async process(amount: number): Promise<PaymentResult> {
624
+ // PayPal implementation
625
+ }
626
+ }
627
+
628
+ // Tests can easily mock PaymentProcessor
629
+ describe('OrderService', () => {
630
+ it('should process payment', async () => {
631
+ const mockProcessor: PaymentProcessor = {
632
+ process: vi.fn().mockResolvedValue({ success: true }),
633
+ };
634
+
635
+ const orderService = new OrderService(mockProcessor);
636
+ await orderService.completeOrder(100);
637
+
638
+ expect(mockProcessor.process).toHaveBeenCalledWith(100);
639
+ });
640
+ });
641
+ ```
642
+
643
+ ### 3. Liskov Substitution Principle (LSP)
644
+
645
+ **TDD ensures LSP through contract testing**
646
+
647
+ ```typescript
648
+ // Base class contract
649
+ abstract class Shape {
650
+ abstract area(): number;
651
+ }
652
+
653
+ // Implementations must satisfy contract
654
+ class Rectangle extends Shape {
655
+ constructor(private width: number, private height: number) {
656
+ super();
657
+ }
658
+
659
+ area(): number {
660
+ return this.width * this.height;
661
+ }
662
+ }
663
+
664
+ class Circle extends Shape {
665
+ constructor(private radius: number) {
666
+ super();
667
+ }
668
+
669
+ area(): number {
670
+ return Math.PI * this.radius ** 2;
671
+ }
672
+ }
673
+
674
+ // Test contract for all shapes
675
+ function testShapeContract(createShape: () => Shape) {
676
+ it('should have positive area', () => {
677
+ const shape = createShape();
678
+ expect(shape.area()).toBeGreaterThan(0);
679
+ });
680
+
681
+ it('should return number', () => {
682
+ const shape = createShape();
683
+ expect(typeof shape.area()).toBe('number');
684
+ });
685
+ }
686
+
687
+ describe('Rectangle', () => {
688
+ testShapeContract(() => new Rectangle(10, 5));
689
+ });
690
+
691
+ describe('Circle', () => {
692
+ testShapeContract(() => new Circle(5));
693
+ });
694
+ ```
695
+
696
+ ### 4. Interface Segregation Principle (ISP)
697
+
698
+ **TDD reveals when interfaces are too large**
699
+
700
+ ```typescript
701
+ // ❌ BAD: Fat interface (forces unnecessary mocking)
702
+ interface Worker {
703
+ work(): void;
704
+ eat(): void;
705
+ sleep(): void;
706
+ }
707
+
708
+ // Mocking is painful
709
+ const mockWorker: Worker = {
710
+ work: vi.fn(),
711
+ eat: vi.fn(), // Not needed for this test!
712
+ sleep: vi.fn(), // Not needed for this test!
713
+ };
714
+
715
+ // ✅ GOOD: Segregated interfaces
716
+ interface Workable {
717
+ work(): void;
718
+ }
719
+
720
+ interface Eatable {
721
+ eat(): void;
722
+ }
723
+
724
+ // Only mock what you need
725
+ const mockWorkable: Workable = {
726
+ work: vi.fn(),
727
+ };
728
+ ```
729
+
730
+ ### 5. Dependency Inversion Principle (DIP)
731
+
732
+ **TDD requires dependency injection (essential for testing)**
733
+
734
+ ```typescript
735
+ // ✅ GOOD: Depends on abstraction
736
+ interface Logger {
737
+ log(message: string): void;
738
+ }
739
+
740
+ class UserService {
741
+ constructor(private logger: Logger) {} // Injected dependency
742
+
743
+ createUser(name: string) {
744
+ this.logger.log(`Creating user: ${name}`);
745
+ // ...
746
+ }
747
+ }
748
+
749
+ // Easy to test with mock
750
+ describe('UserService', () => {
751
+ it('should log user creation', () => {
752
+ const mockLogger: Logger = { log: vi.fn() };
753
+ const service = new UserService(mockLogger);
754
+
755
+ service.createUser('John');
756
+
757
+ expect(mockLogger.log).toHaveBeenCalledWith('Creating user: John');
758
+ });
759
+ });
760
+ ```
761
+
762
+ ## TDD Anti-Patterns to Avoid
763
+
764
+ ### 1. The Liar (Passing test that doesn't test anything)
765
+
766
+ **❌ BAD**:
767
+ ```typescript
768
+ it('should validate user', () => {
769
+ const result = true; // Hardcoded!
770
+ expect(result).toBe(true); // Always passes
771
+ });
772
+ ```
773
+
774
+ ### 2. Excessive Setup (Tests too complex)
775
+
776
+ **❌ BAD**:
777
+ ```typescript
778
+ beforeEach(() => {
779
+ // 50 lines of setup code...
780
+ database.connect();
781
+ seedTestData();
782
+ setupMocks();
783
+ configureEnvironment();
784
+ // ...
785
+ });
786
+ ```
787
+
788
+ **✅ GOOD**: Extract to helper or fixture
789
+ ```typescript
790
+ beforeEach(() => {
791
+ testEnv = createTestEnvironment(); // Encapsulated setup
792
+ });
793
+ ```
794
+
795
+ ### 3. The Giant (One test testing everything)
796
+
797
+ **❌ BAD**:
798
+ ```typescript
799
+ it('should handle entire user lifecycle', () => {
800
+ // 200 lines of test code testing create, update, delete, search...
801
+ });
802
+ ```
803
+
804
+ **✅ GOOD**: One test per behavior
805
+ ```typescript
806
+ it('should create user', () => { /* ... */ });
807
+ it('should update user', () => { /* ... */ });
808
+ it('should delete user', () => { /* ... */ });
809
+ ```
810
+
811
+ ### 4. The Mockery (Over-mocking)
812
+
813
+ **❌ BAD**:
814
+ ```typescript
815
+ vi.mock('./utils');
816
+ vi.mock('./helpers');
817
+ vi.mock('./validators');
818
+ vi.mock('./formatters');
819
+ // Testing nothing but mocks!
820
+ ```
821
+
822
+ **✅ GOOD**: Mock only external dependencies
823
+ ```typescript
824
+ vi.mock('./externalApi'); // Mock external API only
825
+ // Test real code integration
826
+ ```
827
+
828
+ ### 5. The Slow Poke (Slow tests)
829
+
830
+ **❌ BAD**:
831
+ ```typescript
832
+ it('should process data', async () => {
833
+ await sleep(5000); // Hardcoded delays
834
+ // ...
835
+ });
836
+ ```
837
+
838
+ **✅ GOOD**: Use fake timers
839
+ ```typescript
840
+ it('should process data', () => {
841
+ vi.useFakeTimers();
842
+ // ...
843
+ vi.advanceTimersByTime(5000);
844
+ vi.restoreAllTimers();
845
+ });
846
+ ```
847
+
848
+ ## TDD Metrics & Success Indicators
849
+
850
+ **Good TDD indicators**:
851
+ - ✅ 80%+ code coverage
852
+ - ✅ Tests run in < 1 second (unit tests)
853
+ - ✅ Tests are independent and can run in any order
854
+ - ✅ Tests are readable and self-documenting
855
+ - ✅ Red-Green-Refactor cycle followed consistently
856
+ - ✅ Code is modular and testable
857
+
858
+ **Warning signs**:
859
+ - ❌ Tests take minutes to run
860
+ - ❌ Tests fail randomly (flakiness)
861
+ - ❌ Hard to write tests (indicates design issues)
862
+ - ❌ Mocking everything (over-mocking)
863
+ - ❌ Tests break on refactoring (testing implementation)
864
+
865
+ ## TDD in Practice: Real-World Tips
866
+
867
+ ### 1. Start Small
868
+ Begin TDD on new features, not legacy code. Retrofit tests gradually.
869
+
870
+ ### 2. Write Test First (Always!)
871
+ Resist urge to code first. The test is your design tool.
872
+
873
+ ### 3. Keep Tests Fast
874
+ Unit tests should run in milliseconds. Slow tests kill TDD.
875
+
876
+ ### 4. Commit Test + Code Together
877
+ Tests are part of the implementation, not afterthought.
878
+
879
+ ### 5. Refactor Relentlessly
880
+ Green doesn't mean done. Refactor for clarity.
881
+
882
+ ### 6. Test Behavior, Not Implementation
883
+ Tests should survive refactoring.
884
+
885
+ ### 7. Use TDD to Drive Design
886
+ Let tests guide your architecture (dependency injection, SOLID).
887
+
888
+ ## TDD Workflow Commands
889
+
890
+ **Development cycle**:
891
+ ```bash
892
+ # 1. Write failing test (RED)
893
+ npm test -- --watch
894
+
895
+ # 2. Implement (GREEN)
896
+ # Make changes, watch tests turn green
897
+
898
+ # 3. Refactor
899
+ # Improve code, tests stay green
900
+
901
+ # 4. Commit
902
+ git add .
903
+ git commit -m "feat: add user validation"
904
+ ```
905
+
906
+ **Coverage check**:
907
+ ```bash
908
+ npm test -- --coverage
909
+ # Ensure 80%+ coverage
910
+ ```
911
+
912
+ ## Resources
913
+
914
+ - **Kent Beck**: "Test-Driven Development by Example"
915
+ - **Robert C. Martin**: "Clean Code" (TDD chapter)
916
+ - **Martin Fowler**: Refactoring patterns
917
+ - **Growing Object-Oriented Software, Guided by Tests** (Freeman & Pryce)
918
+
919
+ ## Summary
920
+
921
+ **TDD Core Rules**:
922
+ 1. Write test FIRST (red)
923
+ 2. Make it pass MINIMALLY (green)
924
+ 3. Refactor RELENTLESSLY (refactor)
925
+ 4. Repeat
926
+
927
+ **Benefits**:
928
+ - Better design (testable = modular)
929
+ - Living documentation
930
+ - Fearless refactoring
931
+ - Fast feedback loop
932
+ - Higher confidence
933
+
934
+ **Remember**: TDD is about **design**, not just testing. Tests are a tool to drive better architecture.