agentic-team-templates 0.4.2 → 0.6.0
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.
- package/README.md +69 -5
- package/bin/cli.js +4 -1
- package/package.json +8 -3
- package/src/index.js +776 -134
- package/src/index.test.js +947 -0
- package/templates/testing/.cursorrules/advanced-techniques.md +596 -0
- package/templates/testing/.cursorrules/ci-cd-integration.md +603 -0
- package/templates/testing/.cursorrules/overview.md +163 -0
- package/templates/testing/.cursorrules/performance-testing.md +536 -0
- package/templates/testing/.cursorrules/quality-metrics.md +456 -0
- package/templates/testing/.cursorrules/reliability.md +557 -0
- package/templates/testing/.cursorrules/tdd-methodology.md +294 -0
- package/templates/testing/.cursorrules/test-data.md +565 -0
- package/templates/testing/.cursorrules/test-design.md +511 -0
- package/templates/testing/.cursorrules/test-types.md +398 -0
- package/templates/testing/CLAUDE.md +1134 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# TDD Methodology
|
|
2
|
+
|
|
3
|
+
Guidelines for practicing Test-Driven Development effectively.
|
|
4
|
+
|
|
5
|
+
## The Red-Green-Refactor Cycle
|
|
6
|
+
|
|
7
|
+
TDD follows a disciplined three-step cycle:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ │
|
|
12
|
+
│ ┌─────────┐ ┌─────────┐ ┌─────────────┐ │
|
|
13
|
+
│ │ RED │ ───► │ GREEN │ ───► │ REFACTOR │ ───┐ │
|
|
14
|
+
│ │ │ │ │ │ │ │ │
|
|
15
|
+
│ │ Write │ │ Make │ │ Improve │ │ │
|
|
16
|
+
│ │ failing │ │ it │ │ code │ │ │
|
|
17
|
+
│ │ test │ │ pass │ │ quality │ │ │
|
|
18
|
+
│ └─────────┘ └─────────┘ └─────────────┘ │ │
|
|
19
|
+
│ ▲ │ │
|
|
20
|
+
│ └────────────────────────────────────────────────┘ │
|
|
21
|
+
│ │
|
|
22
|
+
└─────────────────────────────────────────────────────────────┘
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Step 1: RED (Write Failing Test)
|
|
26
|
+
|
|
27
|
+
Write a test that describes the behavior you want. It should fail because the code doesn't exist yet.
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
describe('calculateTax', () => {
|
|
31
|
+
it('applies 10% tax rate to standard items', () => {
|
|
32
|
+
const result = calculateTax(100, 'standard');
|
|
33
|
+
expect(result).toBe(110);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Run the test. Watch it fail. **This confirms your test is actually testing something.**
|
|
39
|
+
|
|
40
|
+
### Step 2: GREEN (Make It Pass)
|
|
41
|
+
|
|
42
|
+
Write the **minimum** code necessary to make the test pass. Don't over-engineer.
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
function calculateTax(amount: number, type: string): number {
|
|
46
|
+
if (type === 'standard') {
|
|
47
|
+
return amount * 1.10;
|
|
48
|
+
}
|
|
49
|
+
return amount;
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Step 3: REFACTOR (Improve Quality)
|
|
54
|
+
|
|
55
|
+
Now that tests pass, improve the code without changing behavior. Tests give you confidence to refactor.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
const TAX_RATES: Record<string, number> = {
|
|
59
|
+
standard: 0.10,
|
|
60
|
+
reduced: 0.05,
|
|
61
|
+
exempt: 0,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
function calculateTax(amount: number, type: TaxType): number {
|
|
65
|
+
const rate = TAX_RATES[type] ?? 0;
|
|
66
|
+
return amount * (1 + rate);
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## TDD Best Practices
|
|
71
|
+
|
|
72
|
+
### Keep Cycles Short
|
|
73
|
+
|
|
74
|
+
Each red-green-refactor cycle should take **2-10 minutes**. If you're stuck in red for more than 10 minutes, your slice is too big.
|
|
75
|
+
|
|
76
|
+
### One Test at a Time
|
|
77
|
+
|
|
78
|
+
Write one failing test, make it pass, refactor. Don't write multiple failing tests.
|
|
79
|
+
|
|
80
|
+
### Start with the Simplest Case
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
// Start here
|
|
84
|
+
it('returns 0 for empty cart', () => {
|
|
85
|
+
expect(calculateTotal([])).toBe(0);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Then add complexity
|
|
89
|
+
it('sums single item price', () => {
|
|
90
|
+
expect(calculateTotal([{ price: 100 }])).toBe(100);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Then more
|
|
94
|
+
it('sums multiple items', () => {
|
|
95
|
+
expect(calculateTotal([{ price: 100 }, { price: 50 }])).toBe(150);
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Test the API, Not the Implementation
|
|
100
|
+
|
|
101
|
+
Write tests against the public interface. Don't test private methods.
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
// Bad: Testing internals
|
|
105
|
+
it('calls _parseInput internally', () => {
|
|
106
|
+
const spy = vi.spyOn(parser, '_parseInput');
|
|
107
|
+
parser.parse('data');
|
|
108
|
+
expect(spy).toHaveBeenCalled();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Good: Testing behavior
|
|
112
|
+
it('parses valid JSON', () => {
|
|
113
|
+
const result = parser.parse('{"key": "value"}');
|
|
114
|
+
expect(result).toEqual({ key: 'value' });
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Write the Test You Wish You Had
|
|
119
|
+
|
|
120
|
+
Ask yourself: "What test would give me confidence this works?" Then write that test.
|
|
121
|
+
|
|
122
|
+
## TDD Patterns
|
|
123
|
+
|
|
124
|
+
### Triangulation
|
|
125
|
+
|
|
126
|
+
Use multiple examples to drive toward a general solution:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
it('calculates shipping for weight 1kg', () => {
|
|
130
|
+
expect(calculateShipping(1)).toBe(5);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('calculates shipping for weight 2kg', () => {
|
|
134
|
+
expect(calculateShipping(2)).toBe(10);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Now the pattern is clear: $5/kg
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Transformation Priority Premise
|
|
141
|
+
|
|
142
|
+
When making tests pass, prefer simpler transformations:
|
|
143
|
+
|
|
144
|
+
1. `{} → nil` (empty to null/nil)
|
|
145
|
+
2. `nil → constant` (null to specific value)
|
|
146
|
+
3. `constant → constant+` (simple to more complex)
|
|
147
|
+
4. `constant → scalar` (to variable)
|
|
148
|
+
5. `statement → statements` (add more statements)
|
|
149
|
+
6. `unconditional → if` (add conditional)
|
|
150
|
+
7. `scalar → collection` (to array/list)
|
|
151
|
+
8. `collection → collection+` (add to collection)
|
|
152
|
+
9. `statement → recursion` (add recursion)
|
|
153
|
+
10. `if → while` (conditional to loop)
|
|
154
|
+
11. `expression → function` (extract expression)
|
|
155
|
+
12. `variable → assignment` (complex assignment)
|
|
156
|
+
|
|
157
|
+
### Test List
|
|
158
|
+
|
|
159
|
+
Before coding, write a list of tests you think you'll need:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
calculateDiscount:
|
|
163
|
+
- [ ] returns 0 for no discount
|
|
164
|
+
- [ ] applies percentage discount
|
|
165
|
+
- [ ] applies fixed discount
|
|
166
|
+
- [ ] caps discount at item price (no negative)
|
|
167
|
+
- [ ] handles zero price
|
|
168
|
+
- [ ] throws for negative discount value
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Work through the list, adding tests you discover along the way.
|
|
172
|
+
|
|
173
|
+
## When TDD Adds Maximum Value
|
|
174
|
+
|
|
175
|
+
- **Complex business logic** - Rules that are easy to get wrong
|
|
176
|
+
- **Algorithms** - Sort, search, validation
|
|
177
|
+
- **State machines** - Transitions, edge cases
|
|
178
|
+
- **Financial calculations** - Money, taxes, discounts
|
|
179
|
+
- **Security logic** - Auth, permissions, validation
|
|
180
|
+
- **Integration points** - APIs, databases, queues
|
|
181
|
+
|
|
182
|
+
## When to Adapt TDD
|
|
183
|
+
|
|
184
|
+
### Spike and Stabilize
|
|
185
|
+
|
|
186
|
+
For exploratory work, spike first, then write tests:
|
|
187
|
+
|
|
188
|
+
1. Write throwaway code to understand the problem
|
|
189
|
+
2. Delete the spike
|
|
190
|
+
3. TDD the real implementation
|
|
191
|
+
|
|
192
|
+
### Outside-In vs Inside-Out
|
|
193
|
+
|
|
194
|
+
**Outside-In (London School):**
|
|
195
|
+
- Start with E2E test
|
|
196
|
+
- Mock dependencies
|
|
197
|
+
- Work inward
|
|
198
|
+
|
|
199
|
+
**Inside-Out (Chicago School):**
|
|
200
|
+
- Start with domain logic
|
|
201
|
+
- Build up from units
|
|
202
|
+
- Integrate at the end
|
|
203
|
+
|
|
204
|
+
Choose based on what you're building.
|
|
205
|
+
|
|
206
|
+
## Common TDD Mistakes
|
|
207
|
+
|
|
208
|
+
### 1. Skipping the Red Phase
|
|
209
|
+
|
|
210
|
+
If you write code before the test, you don't know if the test works.
|
|
211
|
+
|
|
212
|
+
### 2. Writing Too Many Tests at Once
|
|
213
|
+
|
|
214
|
+
This defeats the purpose. Write one test, make it pass, repeat.
|
|
215
|
+
|
|
216
|
+
### 3. Not Refactoring
|
|
217
|
+
|
|
218
|
+
The refactor step is not optional. Skipping it leaves messy code.
|
|
219
|
+
|
|
220
|
+
### 4. Testing Implementation Details
|
|
221
|
+
|
|
222
|
+
This makes refactoring painful. Test behavior, not internals.
|
|
223
|
+
|
|
224
|
+
### 5. Giant Leaps
|
|
225
|
+
|
|
226
|
+
If your test requires lots of code to pass, break it into smaller tests.
|
|
227
|
+
|
|
228
|
+
## Example: TDD Session
|
|
229
|
+
|
|
230
|
+
Let's TDD a password validator:
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
// Test 1: Red
|
|
234
|
+
it('rejects empty password', () => {
|
|
235
|
+
expect(validatePassword('')).toEqual({ valid: false, errors: ['Password is required'] });
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Green
|
|
239
|
+
function validatePassword(password: string) {
|
|
240
|
+
if (!password) {
|
|
241
|
+
return { valid: false, errors: ['Password is required'] };
|
|
242
|
+
}
|
|
243
|
+
return { valid: true, errors: [] };
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Test 2: Red
|
|
247
|
+
it('rejects password under 8 characters', () => {
|
|
248
|
+
expect(validatePassword('abc')).toEqual({
|
|
249
|
+
valid: false,
|
|
250
|
+
errors: ['Password must be at least 8 characters']
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Green
|
|
255
|
+
function validatePassword(password: string) {
|
|
256
|
+
const errors: string[] = [];
|
|
257
|
+
|
|
258
|
+
if (!password) {
|
|
259
|
+
errors.push('Password is required');
|
|
260
|
+
} else if (password.length < 8) {
|
|
261
|
+
errors.push('Password must be at least 8 characters');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return { valid: errors.length === 0, errors };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Test 3: Red
|
|
268
|
+
it('requires at least one uppercase letter', () => {
|
|
269
|
+
expect(validatePassword('abcdefgh')).toEqual({
|
|
270
|
+
valid: false,
|
|
271
|
+
errors: ['Password must contain at least one uppercase letter'],
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// Green + Refactor
|
|
276
|
+
const RULES = [
|
|
277
|
+
{ test: (p: string) => p.length >= 8, error: 'Password must be at least 8 characters' },
|
|
278
|
+
{ test: (p: string) => /[A-Z]/.test(p), error: 'Password must contain at least one uppercase letter' },
|
|
279
|
+
];
|
|
280
|
+
|
|
281
|
+
function validatePassword(password: string) {
|
|
282
|
+
if (!password) {
|
|
283
|
+
return { valid: false, errors: ['Password is required'] };
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const errors = RULES
|
|
287
|
+
.filter(rule => !rule.test(password))
|
|
288
|
+
.map(rule => rule.error);
|
|
289
|
+
|
|
290
|
+
return { valid: errors.length === 0, errors };
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Each cycle is small, focused, and builds confidence.
|