codex-genesis-harness 0.1.5 → 0.1.6
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/.codebase/ARCHITECTURE_REVIEW_COMPLETE.md +216 -216
- package/.codebase/CURRENT_STATE.md +7 -2
- package/.codebase/FILE_NAMING_CLARIFICATION.md +161 -161
- package/.codebase/HARNESS_COMPLETENESS_AUDIT.md +613 -613
- package/.codebase/IMPLEMENTATION_COMPLETE.md +429 -429
- package/.codebase/IMPLEMENTATION_HANDOFF.md +351 -351
- package/.codebase/IMPROVEMENTS_SUMMARY.md +419 -419
- package/.codebase/PHASE3_SKILLS_NAMING_COMPLETE.md +292 -292
- package/.codebase/PHASE_DEPENDENCY_MAP.md +486 -486
- package/.codebase/QUICK_START_SPEC_IMPACT.md +456 -456
- package/.codebase/README.md +139 -139
- package/.codebase/RECOVERY_POINTS.md +438 -438
- package/.codex/skills/genesis-api-sync/SKILL.md +354 -354
- package/.codex/skills/genesis-api-sync/checklists/api-sync-checklist.md +101 -101
- package/.codex/skills/genesis-api-sync/templates/api-change-template.md +257 -257
- package/.codex/skills/genesis-debug-guide/SKILL.md +479 -479
- package/.codex/skills/genesis-debug-guide/checklists/flaky-test-investigation.md +339 -339
- package/.codex/skills/genesis-debug-guide/checklists/production-bug-debug.md +210 -210
- package/.codex/skills/genesis-debug-guide/checklists/test-failure-debug.md +158 -158
- package/.codex/skills/genesis-debug-guide/observability/debug-commands.md +365 -365
- package/.codex/skills/genesis-debug-guide/playbooks/unit-test-failures.md +289 -289
- package/.codex/skills/genesis-debug-guide/templates/debug-investigation-log.md +288 -288
- package/.codex/skills/genesis-docs-automation/SKILL.md +1003 -1003
- package/.codex/skills/genesis-docs-automation/checklists/docs-validation.md +359 -359
- package/.codex/skills/genesis-docs-automation/checklists/spec-alignment.md +312 -312
- package/.codex/skills/genesis-docs-automation/observability/docs-tracking.md +382 -382
- package/.codex/skills/genesis-docs-automation/playbooks/auto-update-flow.md +851 -851
- package/.codex/skills/genesis-docs-automation/playbooks/changelog-generation.md +491 -491
- package/.codex/skills/genesis-docs-automation/templates/changelog-entry-template.md +187 -187
- package/.codex/skills/genesis-docs-automation/templates/handoff-template.md +297 -297
- package/.codex/skills/genesis-harness/SKILL.md +1427 -1427
- package/.codex/skills/genesis-harness/agents/openai.yaml +7 -7
- package/.codex/skills/genesis-harness/checklists/bug-fix-qa.md +169 -169
- package/.codex/skills/genesis-harness/checklists/new-feature-qa.md +157 -157
- package/.codex/skills/genesis-harness/checklists/refactor-qa.md +216 -216
- package/.codex/skills/genesis-harness/checklists/requirements-validation.md +211 -211
- package/.codex/skills/genesis-harness/references/planning-schema.md +35 -35
- package/.codex/skills/genesis-harness/references/quality-rubric.md +21 -21
- package/.codex/skills/genesis-harness/references/research-rubric.md +41 -41
- package/.codex/skills/genesis-harness/references/workflows.md +33 -33
- package/.codex/skills/genesis-harness/resources/agents-template.md +27 -27
- package/.codex/skills/genesis-harness/resources/api-docs-template.md +32 -32
- package/.codex/skills/genesis-harness/resources/architecture-template.md +30 -30
- package/.codex/skills/genesis-harness/resources/audit-template.md +26 -26
- package/.codex/skills/genesis-harness/resources/bug-template.md +34 -34
- package/.codex/skills/genesis-harness/resources/change-impact-matrix-template.md +204 -204
- package/.codex/skills/genesis-harness/resources/check-template.md +21 -21
- package/.codex/skills/genesis-harness/resources/conventions-template.md +42 -42
- package/.codex/skills/genesis-harness/resources/decision-template.md +33 -33
- package/.codex/skills/genesis-harness/resources/design-template.md +26 -26
- package/.codex/skills/genesis-harness/resources/escalation-template.md +21 -21
- package/.codex/skills/genesis-harness/resources/feature-template.md +49 -49
- package/.codex/skills/genesis-harness/resources/foundation-phase-template.md +131 -131
- package/.codex/skills/genesis-harness/resources/integrations-template.md +32 -32
- package/.codex/skills/genesis-harness/resources/journeys-template.md +13 -13
- package/.codex/skills/genesis-harness/resources/lessons-learned-template.md +12 -12
- package/.codex/skills/genesis-harness/resources/observability-template.md +34 -34
- package/.codex/skills/genesis-harness/resources/phase-00-foundation-template.md +76 -76
- package/.codex/skills/genesis-harness/resources/phase-template.md +34 -34
- package/.codex/skills/genesis-harness/resources/pitfalls-template.md +22 -22
- package/.codex/skills/genesis-harness/resources/planning-tree-template.md +39 -39
- package/.codex/skills/genesis-harness/resources/post-implementation-guide.md +347 -347
- package/.codex/skills/genesis-harness/resources/project-template.md +38 -38
- package/.codex/skills/genesis-harness/resources/quality-score-template.md +11 -11
- package/.codex/skills/genesis-harness/resources/requirements-template.md +26 -26
- package/.codex/skills/genesis-harness/resources/research-template.md +26 -26
- package/.codex/skills/genesis-harness/resources/review-template.md +22 -22
- package/.codex/skills/genesis-harness/resources/spec-changelog-template.md +6 -6
- package/.codex/skills/genesis-harness/resources/stack-template.md +33 -33
- package/.codex/skills/genesis-harness/resources/verification-template.md +26 -26
- package/.codex/skills/genesis-harness/scripts/check-architecture-boundaries.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/check-docs-sync.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/check-no-debug-logs.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/check-required-planning-files.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/check-spec-changelog.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/check-task-tracking.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/compact-context.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/create-adr.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/create-bug.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/create-feature.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/detect-stack.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/init-planning.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/list-changed-files.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/offload-log.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/run-verification.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/run-verify-loop.sh +0 -0
- package/.codex/skills/genesis-harness/scripts/update-state.sh +0 -0
- package/.codex/skills/genesis-mvp-planning/SKILL.md +114 -0
- package/.codex/skills/genesis-mvp-planning/agents/openai.yaml +6 -0
- package/.codex/skills/genesis-mvp-planning/checklists/mvp-readiness.md +18 -0
- package/.codex/skills/genesis-mvp-planning/examples/5-phase-roadmap-example.md +43 -0
- package/.codex/skills/genesis-mvp-planning/templates/phase-1-core.md +17 -0
- package/.codex/skills/genesis-mvp-planning/templates/phase-2-auth.md +17 -0
- package/.codex/skills/genesis-mvp-planning/templates/phase-3-features.md +17 -0
- package/.codex/skills/genesis-mvp-planning/templates/phase-4-integrations.md +17 -0
- package/.codex/skills/genesis-mvp-planning/templates/phase-5-readiness.md +17 -0
- package/.codex/skills/genesis-new-design/agents/openai.yaml +3 -3
- package/.codex/skills/genesis-observability-automation/checklists/.gitkeep +0 -0
- package/.codex/skills/genesis-observability-automation/observability/.gitkeep +0 -0
- package/.codex/skills/genesis-observability-automation/playbooks/.gitkeep +0 -0
- package/.codex/skills/genesis-observability-automation/templates/.gitkeep +0 -0
- package/.codex/skills/genesis-release-orchestration/SKILL.md +653 -653
- package/.codex/skills/genesis-release-orchestration/checklists/post-deployment-verification.md +274 -274
- package/.codex/skills/genesis-release-orchestration/checklists/pre-release-validation.md +220 -220
- package/.codex/skills/genesis-release-orchestration/observability/release-tracking.md +253 -253
- package/.codex/skills/genesis-release-orchestration/playbooks/canary-deployment-orchestration.md +472 -472
- package/.codex/skills/genesis-release-orchestration/playbooks/semantic-versioning-automation.md +494 -494
- package/.codex/skills/genesis-release-orchestration/templates/deployment-strategy-template.md +303 -303
- package/.codex/skills/genesis-release-orchestration/templates/release-runbook-template.md +420 -420
- package/.codex/skills/genesis-research-first/SKILL.md +237 -237
- package/.codex/skills/genesis-research-first/templates/.gitkeep +0 -0
- package/.codex/skills/genesis-spec-propagation/SKILL.md +534 -534
- package/.codex/skills/genesis-spec-propagation/checklists/phase-update-verification.md +384 -384
- package/.codex/skills/genesis-spec-propagation/checklists/spec-change-detection.md +257 -257
- package/.codex/skills/genesis-spec-propagation/observability/propagation-tracking.md +373 -373
- package/.codex/skills/genesis-spec-propagation/playbooks/breaking-change-propagation.md +692 -692
- package/.codex/skills/genesis-spec-propagation/playbooks/feature-change-propagation.md +434 -434
- package/.codex/skills/genesis-spec-propagation/templates/migration-guide-template.md +407 -407
- package/.codex/skills/genesis-upgrade-design/agents/openai.yaml +3 -3
- package/.codex/skills/spec-impact-engine/SKILL.md +504 -504
- package/.codex/skills/spec-impact-engine/detect-spec-changes.sh +0 -0
- package/.codex-plugin/plugin.json +19 -19
- package/CHANGELOG.md +42 -0
- package/LICENSE +22 -22
- package/README.EN.md +784 -730
- package/README.VI.md +776 -723
- package/README.md +102 -247
- package/VERSION +2 -2
- package/bin/genesis-harness.js +90 -87
- package/package.json +9 -3
- package/scripts/README.md +342 -342
- package/scripts/compact-context.sh +0 -0
- package/scripts/contract_integrity_gate.js +83 -0
- package/scripts/detect-changes.sh +0 -0
- package/scripts/healing_telemetry.js +118 -0
- package/scripts/install.sh +4 -1
- package/scripts/offload-log.sh +0 -0
- package/scripts/prompt_sentinel.js +84 -0
- package/scripts/run-evals.sh +1 -0
- package/scripts/run-verify-loop.sh +11 -0
- package/scripts/spec_visual_sync.js +157 -0
- package/scripts/test_generator.js +142 -0
- package/scripts/transition_state.sh +0 -0
- package/scripts/uninstall.sh +1 -0
- package/scripts/validation_gates.sh +40 -1
- package/scripts/verify.sh +5 -0
- package/tests/unit/contract_integrity_gate.test.js +74 -0
- package/tests/unit/healing_telemetry.test.js +58 -0
- package/tests/unit/prompt_sentinel.test.js +50 -0
- package/tests/unit/spec_visual_sync.test.js +77 -0
- package/tests/unit/test_generator.test.js +62 -0
|
@@ -1,289 +1,289 @@
|
|
|
1
|
-
# Unit Test Failures - Debugging Playbook
|
|
2
|
-
|
|
3
|
-
**Purpose**: Systematic approach to debugging unit test failures. Unit tests are isolated and deterministic, so failures are usually in test setup, mocks, or implementation logic.
|
|
4
|
-
|
|
5
|
-
**Trigger**: When a unit test fails consistently
|
|
6
|
-
|
|
7
|
-
**Duration**: 5-15 minutes typically
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## Step 1: Isolate the Failure (2-3 min)
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
# Run ONLY the failing test
|
|
15
|
-
npm test -- path/to/test.test.js
|
|
16
|
-
|
|
17
|
-
# Verify it fails every time
|
|
18
|
-
npm test -- path/to/test.test.js
|
|
19
|
-
npm test -- path/to/test.test.js
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
**Check**:
|
|
23
|
-
- ✅ Fails same way every run? → Deterministic, proceed
|
|
24
|
-
- ❌ Fails sometimes? → See flaky-test-investigation.md
|
|
25
|
-
- ❌ Passes on retry? → Environment issue, check dependencies
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## Step 2: Understand the Failure (2-3 min)
|
|
30
|
-
|
|
31
|
-
Read the error message **completely**:
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
FAIL src/utils/__tests__/parseDate.test.js
|
|
35
|
-
parseDate()
|
|
36
|
-
✓ should parse valid ISO date
|
|
37
|
-
✗ should return null for invalid date
|
|
38
|
-
Expected: null
|
|
39
|
-
Received: "Invalid Date"
|
|
40
|
-
at Object.<anonymous> (src/utils/__tests__/parseDate.test.js:15:5)
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
**Extract**:
|
|
44
|
-
- Test name: "should return null for invalid date"
|
|
45
|
-
- Expected: `null`
|
|
46
|
-
- Received: `"Invalid Date"` (string, not null!)
|
|
47
|
-
- File & line: `parseDate.test.js:15`
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## Step 3: Review Test Code (3-4 min)
|
|
52
|
-
|
|
53
|
-
Open the test file and find the failing test:
|
|
54
|
-
|
|
55
|
-
```javascript
|
|
56
|
-
// parseDate.test.js line 15
|
|
57
|
-
test('should return null for invalid date', () => {
|
|
58
|
-
const result = parseDate('not-a-date');
|
|
59
|
-
expect(result).toBe(null); // ← Expectation at line 15
|
|
60
|
-
});
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
**Questions**:
|
|
64
|
-
- [ ] Is test setup correct? (line 1-5)
|
|
65
|
-
- [ ] Are mocks configured properly? (if any)
|
|
66
|
-
- [ ] Is the assertion testing the right thing?
|
|
67
|
-
- [ ] Could test data be wrong?
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## Step 4: Review Implementation (3-4 min)
|
|
72
|
-
|
|
73
|
-
Find the function being tested:
|
|
74
|
-
|
|
75
|
-
```javascript
|
|
76
|
-
// parseDate.js
|
|
77
|
-
export function parseDate(dateString) {
|
|
78
|
-
const date = new Date(dateString);
|
|
79
|
-
if (isNaN(date.getTime())) {
|
|
80
|
-
return 'Invalid Date'; // ← BUG! Should return null
|
|
81
|
-
}
|
|
82
|
-
return date;
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
**Questions**:
|
|
87
|
-
- [ ] Does function return correct type? (null vs "Invalid Date")
|
|
88
|
-
- [ ] Does logic match test expectations?
|
|
89
|
-
- [ ] Are there other callers expecting different behavior?
|
|
90
|
-
- [ ] Any recent changes to this function? (git blame)
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## Step 5: Fix the Bug (1-2 min)
|
|
95
|
-
|
|
96
|
-
**Option A: Fix is in implementation**
|
|
97
|
-
```javascript
|
|
98
|
-
// WRONG: returns string
|
|
99
|
-
return 'Invalid Date';
|
|
100
|
-
|
|
101
|
-
// CORRECT: returns null
|
|
102
|
-
return null;
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
**Option B: Fix is in test**
|
|
106
|
-
```javascript
|
|
107
|
-
// If implementation is correct, test is wrong
|
|
108
|
-
expect(result).toBe('Invalid Date'); // Update test
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
**Option C: Fix is in mock setup**
|
|
112
|
-
```javascript
|
|
113
|
-
// Mock not configured correctly
|
|
114
|
-
const mockFetch = jest.fn().mockResolvedValue({ ok: true });
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
**Rule**: Fix only ONE thing per fix. Don't refactor while fixing.
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
## Step 6: Verify Fix (1-2 min)
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
# Run failing test - should now PASS
|
|
125
|
-
npm test -- path/to/test.test.js
|
|
126
|
-
|
|
127
|
-
# Run full test suite - all should PASS
|
|
128
|
-
npm test
|
|
129
|
-
|
|
130
|
-
# Check: no new failures
|
|
131
|
-
# Check: no debug code left (console.log, debugger)
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
|
-
## Step 7: Add Prevention (2-3 min)
|
|
137
|
-
|
|
138
|
-
**Similar bugs to prevent**:
|
|
139
|
-
- [ ] Add test for related edge cases
|
|
140
|
-
- [ ] Add test for null/undefined inputs
|
|
141
|
-
- [ ] Add test for wrong type inputs
|
|
142
|
-
- [ ] Add test for boundary values
|
|
143
|
-
|
|
144
|
-
```javascript
|
|
145
|
-
test('should handle null input', () => {
|
|
146
|
-
expect(parseDate(null)).toBe(null);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
test('should handle undefined input', () => {
|
|
150
|
-
expect(parseDate(undefined)).toBe(null);
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
test('should handle empty string', () => {
|
|
154
|
-
expect(parseDate('')).toBe(null);
|
|
155
|
-
});
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
---
|
|
159
|
-
|
|
160
|
-
## Common Unit Test Issues
|
|
161
|
-
|
|
162
|
-
### 1. Mock Not Configured
|
|
163
|
-
```javascript
|
|
164
|
-
// ❌ WRONG: mock returns undefined
|
|
165
|
-
const mock = jest.fn();
|
|
166
|
-
|
|
167
|
-
// ✅ CORRECT: mock returns expected value
|
|
168
|
-
const mock = jest.fn().mockReturnValue({ id: 1, name: 'Test' });
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### 2. Wrong Import
|
|
172
|
-
```javascript
|
|
173
|
-
// ❌ WRONG: importing test mock
|
|
174
|
-
import parseDate from './parseDate.mock.js';
|
|
175
|
-
|
|
176
|
-
// ✅ CORRECT: importing actual implementation
|
|
177
|
-
import { parseDate } from './parseDate.js';
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### 3. Test Data Type Mismatch
|
|
181
|
-
```javascript
|
|
182
|
-
// ❌ WRONG: passing wrong type
|
|
183
|
-
parseDate(123456); // Passing number, expects string
|
|
184
|
-
|
|
185
|
-
// ✅ CORRECT: passing correct type
|
|
186
|
-
parseDate('2024-01-01'); // Passing string
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### 4. Shared State Between Tests
|
|
190
|
-
```javascript
|
|
191
|
-
// ❌ WRONG: variable shared across tests
|
|
192
|
-
let counter = 0;
|
|
193
|
-
test('test 1', () => { counter++; });
|
|
194
|
-
test('test 2', () => { expect(counter).toBe(1); }); // Fails if test 1 ran first!
|
|
195
|
-
|
|
196
|
-
// ✅ CORRECT: each test has isolated state
|
|
197
|
-
test('test 1', () => { const counter = 0; counter++; });
|
|
198
|
-
test('test 2', () => { const counter = 0; expect(counter).toBe(0); });
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### 5. Async/Promise Not Awaited
|
|
202
|
-
```javascript
|
|
203
|
-
// ❌ WRONG: not waiting for promise
|
|
204
|
-
test('should fetch user', () => {
|
|
205
|
-
fetchUser(1); // Returns promise, but not awaited
|
|
206
|
-
expect(result).toBe(...); // Runs before promise resolves!
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
// ✅ CORRECT: await promise or return from test
|
|
210
|
-
test('should fetch user', async () => {
|
|
211
|
-
const result = await fetchUser(1);
|
|
212
|
-
expect(result).toBe(...);
|
|
213
|
-
});
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
---
|
|
217
|
-
|
|
218
|
-
## Debugging Strategy by Test Type
|
|
219
|
-
|
|
220
|
-
### Simple Unit (pure function)
|
|
221
|
-
1. Check inputs match implementation
|
|
222
|
-
2. Check return type
|
|
223
|
-
3. Check logic handles edge cases
|
|
224
|
-
4. Add edge case tests
|
|
225
|
-
|
|
226
|
-
### Function with Dependencies
|
|
227
|
-
1. Check mocks are configured
|
|
228
|
-
2. Check mock is called correctly
|
|
229
|
-
3. Check mock return value used
|
|
230
|
-
4. Verify mock reset between tests
|
|
231
|
-
|
|
232
|
-
### Class/Object Method
|
|
233
|
-
1. Check class instantiation
|
|
234
|
-
2. Check method parameters
|
|
235
|
-
3. Check state after method call
|
|
236
|
-
4. Check side effects (if any)
|
|
237
|
-
|
|
238
|
-
---
|
|
239
|
-
|
|
240
|
-
## Recovery: Still Can't Find Bug?
|
|
241
|
-
|
|
242
|
-
If stuck for >10 minutes:
|
|
243
|
-
|
|
244
|
-
1. **Add debug logging**:
|
|
245
|
-
```javascript
|
|
246
|
-
test('test name', () => {
|
|
247
|
-
console.log('Input:', input);
|
|
248
|
-
const result = parseDate(input);
|
|
249
|
-
console.log('Result:', result);
|
|
250
|
-
console.log('Expected:', expectedValue);
|
|
251
|
-
expect(result).toBe(expectedValue);
|
|
252
|
-
});
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
2. **Simplify test**:
|
|
256
|
-
```javascript
|
|
257
|
-
// Remove test setup, use hardcoded values
|
|
258
|
-
test('test name', () => {
|
|
259
|
-
const result = parseDate('2024-01-01');
|
|
260
|
-
expect(result).toEqual({ year: 2024, month: 1, day: 1 });
|
|
261
|
-
});
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
3. **Check git history**:
|
|
265
|
-
```bash
|
|
266
|
-
git log -p -- path/to/test.js
|
|
267
|
-
git log -p -- path/to/implementation.js
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
4. **Run with debugging**:
|
|
271
|
-
```bash
|
|
272
|
-
node --inspect-brk node_modules/.bin/jest --runInBand path/to/test.js
|
|
273
|
-
# Opens Chrome DevTools for debugging
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
---
|
|
277
|
-
|
|
278
|
-
## Checklist: Ready to Complete
|
|
279
|
-
|
|
280
|
-
- [ ] Test fails in isolation
|
|
281
|
-
- [ ] Error message understood
|
|
282
|
-
- [ ] Test code reviewed
|
|
283
|
-
- [ ] Implementation reviewed
|
|
284
|
-
- [ ] Bug fixed (one thing only)
|
|
285
|
-
- [ ] Test passes
|
|
286
|
-
- [ ] Full suite passes
|
|
287
|
-
- [ ] No debug code left
|
|
288
|
-
- [ ] Edge case tests added
|
|
289
|
-
- [ ] Ready to commit
|
|
1
|
+
# Unit Test Failures - Debugging Playbook
|
|
2
|
+
|
|
3
|
+
**Purpose**: Systematic approach to debugging unit test failures. Unit tests are isolated and deterministic, so failures are usually in test setup, mocks, or implementation logic.
|
|
4
|
+
|
|
5
|
+
**Trigger**: When a unit test fails consistently
|
|
6
|
+
|
|
7
|
+
**Duration**: 5-15 minutes typically
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Step 1: Isolate the Failure (2-3 min)
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Run ONLY the failing test
|
|
15
|
+
npm test -- path/to/test.test.js
|
|
16
|
+
|
|
17
|
+
# Verify it fails every time
|
|
18
|
+
npm test -- path/to/test.test.js
|
|
19
|
+
npm test -- path/to/test.test.js
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Check**:
|
|
23
|
+
- ✅ Fails same way every run? → Deterministic, proceed
|
|
24
|
+
- ❌ Fails sometimes? → See flaky-test-investigation.md
|
|
25
|
+
- ❌ Passes on retry? → Environment issue, check dependencies
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Step 2: Understand the Failure (2-3 min)
|
|
30
|
+
|
|
31
|
+
Read the error message **completely**:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
FAIL src/utils/__tests__/parseDate.test.js
|
|
35
|
+
parseDate()
|
|
36
|
+
✓ should parse valid ISO date
|
|
37
|
+
✗ should return null for invalid date
|
|
38
|
+
Expected: null
|
|
39
|
+
Received: "Invalid Date"
|
|
40
|
+
at Object.<anonymous> (src/utils/__tests__/parseDate.test.js:15:5)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Extract**:
|
|
44
|
+
- Test name: "should return null for invalid date"
|
|
45
|
+
- Expected: `null`
|
|
46
|
+
- Received: `"Invalid Date"` (string, not null!)
|
|
47
|
+
- File & line: `parseDate.test.js:15`
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Step 3: Review Test Code (3-4 min)
|
|
52
|
+
|
|
53
|
+
Open the test file and find the failing test:
|
|
54
|
+
|
|
55
|
+
```javascript
|
|
56
|
+
// parseDate.test.js line 15
|
|
57
|
+
test('should return null for invalid date', () => {
|
|
58
|
+
const result = parseDate('not-a-date');
|
|
59
|
+
expect(result).toBe(null); // ← Expectation at line 15
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Questions**:
|
|
64
|
+
- [ ] Is test setup correct? (line 1-5)
|
|
65
|
+
- [ ] Are mocks configured properly? (if any)
|
|
66
|
+
- [ ] Is the assertion testing the right thing?
|
|
67
|
+
- [ ] Could test data be wrong?
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Step 4: Review Implementation (3-4 min)
|
|
72
|
+
|
|
73
|
+
Find the function being tested:
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
// parseDate.js
|
|
77
|
+
export function parseDate(dateString) {
|
|
78
|
+
const date = new Date(dateString);
|
|
79
|
+
if (isNaN(date.getTime())) {
|
|
80
|
+
return 'Invalid Date'; // ← BUG! Should return null
|
|
81
|
+
}
|
|
82
|
+
return date;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Questions**:
|
|
87
|
+
- [ ] Does function return correct type? (null vs "Invalid Date")
|
|
88
|
+
- [ ] Does logic match test expectations?
|
|
89
|
+
- [ ] Are there other callers expecting different behavior?
|
|
90
|
+
- [ ] Any recent changes to this function? (git blame)
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Step 5: Fix the Bug (1-2 min)
|
|
95
|
+
|
|
96
|
+
**Option A: Fix is in implementation**
|
|
97
|
+
```javascript
|
|
98
|
+
// WRONG: returns string
|
|
99
|
+
return 'Invalid Date';
|
|
100
|
+
|
|
101
|
+
// CORRECT: returns null
|
|
102
|
+
return null;
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Option B: Fix is in test**
|
|
106
|
+
```javascript
|
|
107
|
+
// If implementation is correct, test is wrong
|
|
108
|
+
expect(result).toBe('Invalid Date'); // Update test
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Option C: Fix is in mock setup**
|
|
112
|
+
```javascript
|
|
113
|
+
// Mock not configured correctly
|
|
114
|
+
const mockFetch = jest.fn().mockResolvedValue({ ok: true });
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Rule**: Fix only ONE thing per fix. Don't refactor while fixing.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Step 6: Verify Fix (1-2 min)
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# Run failing test - should now PASS
|
|
125
|
+
npm test -- path/to/test.test.js
|
|
126
|
+
|
|
127
|
+
# Run full test suite - all should PASS
|
|
128
|
+
npm test
|
|
129
|
+
|
|
130
|
+
# Check: no new failures
|
|
131
|
+
# Check: no debug code left (console.log, debugger)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Step 7: Add Prevention (2-3 min)
|
|
137
|
+
|
|
138
|
+
**Similar bugs to prevent**:
|
|
139
|
+
- [ ] Add test for related edge cases
|
|
140
|
+
- [ ] Add test for null/undefined inputs
|
|
141
|
+
- [ ] Add test for wrong type inputs
|
|
142
|
+
- [ ] Add test for boundary values
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
test('should handle null input', () => {
|
|
146
|
+
expect(parseDate(null)).toBe(null);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test('should handle undefined input', () => {
|
|
150
|
+
expect(parseDate(undefined)).toBe(null);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('should handle empty string', () => {
|
|
154
|
+
expect(parseDate('')).toBe(null);
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Common Unit Test Issues
|
|
161
|
+
|
|
162
|
+
### 1. Mock Not Configured
|
|
163
|
+
```javascript
|
|
164
|
+
// ❌ WRONG: mock returns undefined
|
|
165
|
+
const mock = jest.fn();
|
|
166
|
+
|
|
167
|
+
// ✅ CORRECT: mock returns expected value
|
|
168
|
+
const mock = jest.fn().mockReturnValue({ id: 1, name: 'Test' });
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 2. Wrong Import
|
|
172
|
+
```javascript
|
|
173
|
+
// ❌ WRONG: importing test mock
|
|
174
|
+
import parseDate from './parseDate.mock.js';
|
|
175
|
+
|
|
176
|
+
// ✅ CORRECT: importing actual implementation
|
|
177
|
+
import { parseDate } from './parseDate.js';
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 3. Test Data Type Mismatch
|
|
181
|
+
```javascript
|
|
182
|
+
// ❌ WRONG: passing wrong type
|
|
183
|
+
parseDate(123456); // Passing number, expects string
|
|
184
|
+
|
|
185
|
+
// ✅ CORRECT: passing correct type
|
|
186
|
+
parseDate('2024-01-01'); // Passing string
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### 4. Shared State Between Tests
|
|
190
|
+
```javascript
|
|
191
|
+
// ❌ WRONG: variable shared across tests
|
|
192
|
+
let counter = 0;
|
|
193
|
+
test('test 1', () => { counter++; });
|
|
194
|
+
test('test 2', () => { expect(counter).toBe(1); }); // Fails if test 1 ran first!
|
|
195
|
+
|
|
196
|
+
// ✅ CORRECT: each test has isolated state
|
|
197
|
+
test('test 1', () => { const counter = 0; counter++; });
|
|
198
|
+
test('test 2', () => { const counter = 0; expect(counter).toBe(0); });
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 5. Async/Promise Not Awaited
|
|
202
|
+
```javascript
|
|
203
|
+
// ❌ WRONG: not waiting for promise
|
|
204
|
+
test('should fetch user', () => {
|
|
205
|
+
fetchUser(1); // Returns promise, but not awaited
|
|
206
|
+
expect(result).toBe(...); // Runs before promise resolves!
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// ✅ CORRECT: await promise or return from test
|
|
210
|
+
test('should fetch user', async () => {
|
|
211
|
+
const result = await fetchUser(1);
|
|
212
|
+
expect(result).toBe(...);
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Debugging Strategy by Test Type
|
|
219
|
+
|
|
220
|
+
### Simple Unit (pure function)
|
|
221
|
+
1. Check inputs match implementation
|
|
222
|
+
2. Check return type
|
|
223
|
+
3. Check logic handles edge cases
|
|
224
|
+
4. Add edge case tests
|
|
225
|
+
|
|
226
|
+
### Function with Dependencies
|
|
227
|
+
1. Check mocks are configured
|
|
228
|
+
2. Check mock is called correctly
|
|
229
|
+
3. Check mock return value used
|
|
230
|
+
4. Verify mock reset between tests
|
|
231
|
+
|
|
232
|
+
### Class/Object Method
|
|
233
|
+
1. Check class instantiation
|
|
234
|
+
2. Check method parameters
|
|
235
|
+
3. Check state after method call
|
|
236
|
+
4. Check side effects (if any)
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Recovery: Still Can't Find Bug?
|
|
241
|
+
|
|
242
|
+
If stuck for >10 minutes:
|
|
243
|
+
|
|
244
|
+
1. **Add debug logging**:
|
|
245
|
+
```javascript
|
|
246
|
+
test('test name', () => {
|
|
247
|
+
console.log('Input:', input);
|
|
248
|
+
const result = parseDate(input);
|
|
249
|
+
console.log('Result:', result);
|
|
250
|
+
console.log('Expected:', expectedValue);
|
|
251
|
+
expect(result).toBe(expectedValue);
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
2. **Simplify test**:
|
|
256
|
+
```javascript
|
|
257
|
+
// Remove test setup, use hardcoded values
|
|
258
|
+
test('test name', () => {
|
|
259
|
+
const result = parseDate('2024-01-01');
|
|
260
|
+
expect(result).toEqual({ year: 2024, month: 1, day: 1 });
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
3. **Check git history**:
|
|
265
|
+
```bash
|
|
266
|
+
git log -p -- path/to/test.js
|
|
267
|
+
git log -p -- path/to/implementation.js
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
4. **Run with debugging**:
|
|
271
|
+
```bash
|
|
272
|
+
node --inspect-brk node_modules/.bin/jest --runInBand path/to/test.js
|
|
273
|
+
# Opens Chrome DevTools for debugging
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Checklist: Ready to Complete
|
|
279
|
+
|
|
280
|
+
- [ ] Test fails in isolation
|
|
281
|
+
- [ ] Error message understood
|
|
282
|
+
- [ ] Test code reviewed
|
|
283
|
+
- [ ] Implementation reviewed
|
|
284
|
+
- [ ] Bug fixed (one thing only)
|
|
285
|
+
- [ ] Test passes
|
|
286
|
+
- [ ] Full suite passes
|
|
287
|
+
- [ ] No debug code left
|
|
288
|
+
- [ ] Edge case tests added
|
|
289
|
+
- [ ] Ready to commit
|