jettypod 4.1.2 → 4.1.4

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 (179) hide show
  1. package/.nvmrc +1 -0
  2. package/docs/COMPLETE-TESTING-STRATEGY.md +970 -0
  3. package/docs/DECISIONS.md +10 -12
  4. package/docs/NODE_VERSION.md +83 -0
  5. package/docs/TDD-INFRASTRUCTURE-STRATEGY.md +1374 -0
  6. package/docs/TESTING-FOR-NON-ENGINEERS.md +1588 -0
  7. package/docs/TESTING-STRATEGY-AUDIT.md +698 -0
  8. package/hooks/post-checkout +17 -0
  9. package/hooks/post-merge +17 -0
  10. package/hooks/pre-commit +30 -0
  11. package/jettypod.js +259 -120
  12. package/lib/coverage-tracker.js +218 -0
  13. package/lib/database.js +2 -0
  14. package/lib/db-export.js +192 -0
  15. package/lib/db-import.js +193 -0
  16. package/lib/external-transition-handler.js +32 -0
  17. package/lib/git-hook-helpers.js +174 -0
  18. package/lib/git-root.js +90 -0
  19. package/lib/infrastructure-chore-generator.js +45 -0
  20. package/lib/install-hooks.js +52 -0
  21. package/lib/jettypod-backup.js +238 -0
  22. package/lib/merge-lock.js +193 -0
  23. package/lib/migrations/012-add-worktree-path.js +38 -0
  24. package/lib/migrations/013-worktrees-table.js +86 -0
  25. package/lib/migrations/014-migrate-worktree-data.js +161 -0
  26. package/lib/migrations/015-merge-locks-table.js +67 -0
  27. package/lib/pattern-finder.js +152 -0
  28. package/lib/process-manager.js +140 -0
  29. package/lib/production-standards-reader.js +13 -2
  30. package/lib/production-standards-writer.js +85 -0
  31. package/lib/skills/feature-planning/dry-run-validator.js +135 -0
  32. package/lib/skills/feature-planning/validation-formatter.js +160 -0
  33. package/lib/smart-conflict-detection.js +168 -0
  34. package/lib/smart-fetch-rebase.js +614 -0
  35. package/lib/step-definition-parser.js +76 -0
  36. package/lib/unit-test-generator.js +232 -0
  37. package/lib/verification-command-generator.js +66 -0
  38. package/lib/worktree-diagnostics.js +413 -0
  39. package/lib/worktree-facade.js +174 -0
  40. package/lib/worktree-manager.js +636 -0
  41. package/lib/worktree-reconciler.js +429 -0
  42. package/package.json +30 -3
  43. package/skills-templates/external-transition/SKILL.md +34 -3
  44. package/skills-templates/feature-planning/SKILL.md +190 -24
  45. package/skills-templates/production-mode/SKILL.md +127 -9
  46. package/skills-templates/speed-mode/SKILL.md +454 -51
  47. package/skills-templates/stable-mode/SKILL.md +285 -76
  48. package/.claude/PROTECT_SKILLS.md +0 -28
  49. package/.claude/settings.json +0 -24
  50. package/.claude/settings.local.json +0 -16
  51. package/.claude/skills/epic-planning/SKILL.md +0 -297
  52. package/.claude/skills/external-transition/SKILL.md +0 -384
  53. package/.claude/skills/feature-planning/SKILL.md +0 -464
  54. package/.claude/skills/production-mode/SKILL.md +0 -369
  55. package/.claude/skills/speed-mode/SKILL.md +0 -481
  56. package/.claude/skills/stable-mode/SKILL.md +0 -713
  57. package/.claude/skills.backup-2025-11-10T23-33-09-368Z/epic-planning/SKILL.md +0 -297
  58. package/.claude/skills.backup-2025-11-10T23-33-09-368Z/feature-planning/SKILL.md +0 -464
  59. package/.claude/skills.backup-2025-11-10T23-33-09-368Z/speed-mode/SKILL.md +0 -467
  60. package/.claude/skills.backup-2025-11-10T23-33-09-368Z/stable-mode/SKILL.md +0 -673
  61. package/.claude/skills.backup-2025-11-11T16-15-10-070Z/epic-discover/SKILL.md +0 -297
  62. package/.claude/skills.backup-2025-11-11T16-42-43-212Z/epic-planning/SKILL.md +0 -297
  63. package/.claude/skills.backup-2025-11-11T16-42-43-212Z/feature-planning/SKILL.md +0 -464
  64. package/.claude/skills.backup-2025-11-11T16-42-43-212Z/speed-mode/SKILL.md +0 -467
  65. package/.claude/skills.backup-2025-11-11T16-42-43-212Z/stable-mode/SKILL.md +0 -673
  66. package/.claude/skills.backup-2025-11-11T17-06-09-783Z/epic-planning/SKILL.md +0 -297
  67. package/.claude/skills.backup-2025-11-11T17-06-09-783Z/feature-planning/SKILL.md +0 -464
  68. package/.claude/skills.backup-2025-11-11T17-06-09-783Z/speed-mode/SKILL.md +0 -467
  69. package/.claude/skills.backup-2025-11-11T17-06-09-783Z/stable-mode/SKILL.md +0 -673
  70. package/.devpod/current-work.json +0 -10
  71. package/.devpod/work.db +0 -0
  72. package/.github/workflows/test-safety.yml +0 -85
  73. package/.jettypod/config.json +0 -5
  74. package/.jettypod/current-work.json +0 -10
  75. package/.jettypod/hooks/README.md +0 -77
  76. package/.jettypod/hooks/protect-claude-md.js +0 -338
  77. package/.jettypod/test-work.db +0 -0
  78. package/.jettypod/work.db +0 -0
  79. package/CLAUDE.md +0 -49
  80. package/SPEED-STABLE-AUDIT.md +0 -853
  81. package/SYSTEM-BEHAVIOR.md +0 -2199
  82. package/TEST_SAFETY_AUDIT.md +0 -314
  83. package/TEST_SAFETY_IMPLEMENTATION.md +0 -97
  84. package/cucumber-report.html +0 -45
  85. package/dist/devpod-linux +0 -0
  86. package/dist/devpod-macos +0 -0
  87. package/dist/devpod-win.exe +0 -0
  88. package/docs/features/jettypod-standards-explained.md +0 -543
  89. package/docs/features/standards-inventory.md +0 -257
  90. package/features/auto-generate-production-chores.feature +0 -13
  91. package/features/backlog-command.feature +0 -26
  92. package/features/backlog-filtering-production.feature +0 -10
  93. package/features/claude-md-protection/steps.js +0 -498
  94. package/features/decisions/index.js +0 -490
  95. package/features/decisions/index.test.js +0 -208
  96. package/features/fix-text-wrapping.feature +0 -42
  97. package/features/git-hooks/git-hooks.feature +0 -30
  98. package/features/git-hooks/index.js +0 -93
  99. package/features/git-hooks/index.test.js +0 -137
  100. package/features/git-hooks/post-commit +0 -56
  101. package/features/git-hooks/post-merge +0 -47
  102. package/features/git-hooks/pre-commit +0 -28
  103. package/features/git-hooks/simple-steps.js +0 -53
  104. package/features/git-hooks/simple-test.feature +0 -10
  105. package/features/git-hooks/steps.js +0 -196
  106. package/features/jettypod-update-command.feature +0 -46
  107. package/features/mode-prompts/index.js +0 -95
  108. package/features/mode-prompts/simple-steps.js +0 -44
  109. package/features/mode-prompts/simple-test.feature +0 -9
  110. package/features/mode-prompts/validation.test.js +0 -120
  111. package/features/multiple-claude-instances.feature +0 -121
  112. package/features/production-mode-skill.feature +0 -121
  113. package/features/refactor-mode/steps.js +0 -217
  114. package/features/refactor-mode.feature +0 -49
  115. package/features/simplify-external-transition.feature +0 -166
  116. package/features/skills-update/index.test.js +0 -216
  117. package/features/step_definitions/backlog-command.steps.js +0 -37
  118. package/features/step_definitions/fix-text-wrapping.steps.js +0 -271
  119. package/features/step_definitions/multiple-claude-instances.steps.js +0 -621
  120. package/features/step_definitions/production-mode-skill.steps.js +0 -862
  121. package/features/step_definitions/simplify-external-transition.steps.js +0 -370
  122. package/features/step_definitions/terminal-logo.steps.js +0 -145
  123. package/features/step_definitions/update-command.steps.js +0 -183
  124. package/features/support/hooks.js +0 -9
  125. package/features/terminal-logo/index.js +0 -39
  126. package/features/terminal-logo/terminal-logo.feature +0 -30
  127. package/features/update-command/index.js +0 -181
  128. package/features/update-command/index.test.js +0 -225
  129. package/features/work-commands/bug-workflow-display.feature +0 -22
  130. package/features/work-commands/index.js +0 -498
  131. package/features/work-commands/simple-steps.js +0 -69
  132. package/features/work-commands/stable-tests.feature +0 -57
  133. package/features/work-commands/steps.js +0 -1174
  134. package/features/work-commands/validation.test.js +0 -88
  135. package/features/work-commands/work-commands.feature +0 -13
  136. package/features/work-tracking/discovery-validation.test.js +0 -228
  137. package/features/work-tracking/index.js +0 -1921
  138. package/features/work-tracking/mode-required.feature +0 -112
  139. package/features/work-tracking/phase-tracking.test.js +0 -482
  140. package/features/work-tracking/prototype-tracking.test.js +0 -485
  141. package/features/work-tracking/tree-view.test.js +0 -310
  142. package/features/work-tracking/work-set-mode.feature +0 -71
  143. package/features/work-tracking/work-start-mode.feature +0 -88
  144. package/full-test.txt +0 -0
  145. package/lib/bug-workflow.test.js +0 -177
  146. package/lib/claudemd.test.js +0 -195
  147. package/lib/config.test.js +0 -511
  148. package/lib/constants.test.js +0 -164
  149. package/lib/current-work.test.js +0 -146
  150. package/lib/database-project-config.test.js +0 -111
  151. package/lib/database.test.js +0 -106
  152. package/lib/decisions-generator.test.js +0 -457
  153. package/lib/decisions-helpers.test.js +0 -310
  154. package/lib/git-coordinator.js +0 -167
  155. package/lib/git.test.js +0 -145
  156. package/lib/migrations/002-default-work-item-modes.test.js +0 -351
  157. package/lib/production-chore-generator.test.js +0 -432
  158. package/lib/production-context-detector.test.js +0 -277
  159. package/lib/production-scenario-appender.test.js +0 -235
  160. package/lib/production-scenario-validator.test.js +0 -246
  161. package/lib/production-standards-reader.test.js +0 -270
  162. package/lib/project-state.test.js +0 -92
  163. package/lib/push-queue.js +0 -417
  164. package/lib/queue-processor.js +0 -74
  165. package/lib/test-helpers.js +0 -202
  166. package/lib/test-helpers.test.js +0 -255
  167. package/prototypes/2025-01-11-production-mode-autonomous.js +0 -119
  168. package/prototypes/2025-01-11-production-mode-collaborative.js +0 -166
  169. package/prototypes/2025-01-11-production-mode-guided.js +0 -217
  170. package/prototypes/2025-01-11-production-mode-smart-context.js +0 -347
  171. package/prototypes/2025-01-11-production-standards-example.md +0 -204
  172. package/prototypes/2025-11-10-backlog-filtering-tree-aware.js +0 -242
  173. package/prototypes/test/index.html +0 -1
  174. package/setup-dist-repo.sh +0 -68
  175. package/test-production-standards-engine.js +0 -130
  176. package/test-results.json +0 -2195
  177. package/test-safety-check.sh +0 -80
  178. package/work-item-tracking-plan.md +0 -199
  179. /package/{.jettypod/devpod.db → jettypod.db} +0 -0
@@ -0,0 +1,970 @@
1
+ # Complete Testing Strategy for JettyPod
2
+
3
+ **Date**: 2025-11-14
4
+ **Purpose**: Honest, comprehensive testing strategy incorporating ALL test types
5
+ **Scope**: Unit, Integration, E2E, Performance, Security, Contract, Visual, Mutation
6
+
7
+ ---
8
+
9
+ ## Honesty First: What We Actually Need
10
+
11
+ ### The Truth About Testing
12
+
13
+ **You don't need every test type.** You need the right tests for your project.
14
+
15
+ **JettyPod is a CLI tool with:**
16
+ - Local database (SQLite)
17
+ - Git integration
18
+ - File system operations
19
+ - No UI (no visual regression tests needed)
20
+ - No external APIs (no contract tests needed yet)
21
+ - Single-user (no load tests needed yet)
22
+
23
+ **Therefore, prioritize:**
24
+ 1. ✅ **Unit tests** - Most important (fast, reliable)
25
+ 2. ✅ **Integration tests** - Important (BDD scenarios)
26
+ 3. ✅ **E2E tests** - Some (full CLI workflows)
27
+ 4. ⚠️ **Performance tests** - Basic (timing checks)
28
+ 5. ⚠️ **Security tests** - Basic (input validation)
29
+ 6. ❌ **Visual tests** - Not needed (no UI)
30
+ 7. ❌ **Contract tests** - Not needed yet (no external APIs)
31
+ 8. ❌ **Mutation tests** - Nice to have (not MVP)
32
+
33
+ ---
34
+
35
+ ## The Test Pyramid (Applied to JettyPod)
36
+
37
+ ```
38
+ /\
39
+ / \
40
+ / E2E \ 10% - Full CLI workflows
41
+ /-------\ (~10 tests)
42
+ / BDD \ 30% - Feature scenarios
43
+ /-----------\ (~30 scenarios)
44
+ / Unit \ 60% - Function/module tests
45
+ /_______________\ (~100+ tests)
46
+ ```
47
+
48
+ ### Why This Ratio?
49
+
50
+ **Unit tests (60%):**
51
+ - Test pure functions in lib/
52
+ - Fast (milliseconds)
53
+ - Reliable (no dependencies)
54
+ - Easy to debug
55
+ - Cheap to maintain
56
+
57
+ **Integration/BDD tests (30%):**
58
+ - Test modules working together
59
+ - Medium speed (seconds)
60
+ - Some setup required
61
+ - Test user workflows
62
+ - Living documentation
63
+
64
+ **E2E tests (10%):**
65
+ - Test complete system
66
+ - Slow (minutes)
67
+ - Brittle (environment-dependent)
68
+ - High maintenance
69
+ - Catch integration gaps
70
+
71
+ ---
72
+
73
+ ## Test Type 1: Unit Tests (Jest)
74
+
75
+ ### What to Unit Test
76
+
77
+ **Everything in lib/ directory:**
78
+ ```
79
+ lib/
80
+ ├── merge-lock.js → merge-lock.test.js
81
+ ├── validators.js → validators.test.js
82
+ ├── database.js → database.test.js
83
+ ├── git-helpers.js → git-helpers.test.js
84
+ ├── decisions-helpers.js → decisions-helpers.test.js
85
+ └── current-work.js → current-work.test.js
86
+ ```
87
+
88
+ **What makes a good unit test:**
89
+ - Tests ONE function/method
90
+ - No external dependencies (or mocked)
91
+ - Fast (< 100ms per test)
92
+ - Deterministic (same input = same output)
93
+ - Independent (can run in any order)
94
+
95
+ ### Example: Comprehensive Unit Test
96
+
97
+ ```javascript
98
+ // lib/validators.test.js
99
+ const { validateWorkItemTitle, validateMode, validateStatus } = require('./validators');
100
+
101
+ describe('validateWorkItemTitle', () => {
102
+ describe('valid titles', () => {
103
+ it('accepts standard title', () => {
104
+ expect(validateWorkItemTitle('Add login feature')).toBe(true);
105
+ });
106
+
107
+ it('accepts title with numbers', () => {
108
+ expect(validateWorkItemTitle('Fix bug #123')).toBe(true);
109
+ });
110
+
111
+ it('accepts title with special characters', () => {
112
+ expect(validateWorkItemTitle('Add @mentions support')).toBe(true);
113
+ });
114
+
115
+ it('accepts minimum length title', () => {
116
+ expect(validateWorkItemTitle('Fix')).toBe(true);
117
+ });
118
+ });
119
+
120
+ describe('invalid titles', () => {
121
+ it('rejects null', () => {
122
+ expect(validateWorkItemTitle(null)).toBe(false);
123
+ });
124
+
125
+ it('rejects undefined', () => {
126
+ expect(validateWorkItemTitle(undefined)).toBe(false);
127
+ });
128
+
129
+ it('rejects empty string', () => {
130
+ expect(validateWorkItemTitle('')).toBe(false);
131
+ });
132
+
133
+ it('rejects whitespace only', () => {
134
+ expect(validateWorkItemTitle(' ')).toBe(false);
135
+ });
136
+
137
+ it('rejects too long title', () => {
138
+ const longTitle = 'a'.repeat(501);
139
+ expect(validateWorkItemTitle(longTitle)).toBe(false);
140
+ });
141
+ });
142
+
143
+ describe('edge cases', () => {
144
+ it('handles title at max length', () => {
145
+ const maxTitle = 'a'.repeat(500);
146
+ expect(validateWorkItemTitle(maxTitle)).toBe(true);
147
+ });
148
+
149
+ it('trims whitespace before validation', () => {
150
+ expect(validateWorkItemTitle(' Valid title ')).toBe(true);
151
+ });
152
+
153
+ it('handles unicode characters', () => {
154
+ expect(validateWorkItemTitle('Add 日本語 support')).toBe(true);
155
+ });
156
+ });
157
+ });
158
+
159
+ describe('validateMode', () => {
160
+ it('accepts speed mode', () => {
161
+ expect(validateMode('speed')).toBe(true);
162
+ });
163
+
164
+ it('accepts stable mode', () => {
165
+ expect(validateMode('stable')).toBe(true);
166
+ });
167
+
168
+ it('accepts production mode', () => {
169
+ expect(validateMode('production')).toBe(true);
170
+ });
171
+
172
+ it('rejects invalid mode', () => {
173
+ expect(validateMode('fast')).toBe(false);
174
+ });
175
+
176
+ it('rejects null', () => {
177
+ expect(validateMode(null)).toBe(false);
178
+ });
179
+
180
+ it('is case sensitive', () => {
181
+ expect(validateMode('Speed')).toBe(false);
182
+ });
183
+ });
184
+ ```
185
+
186
+ ### Unit Test Best Practices
187
+
188
+ **1. Use descriptive test names:**
189
+ ```javascript
190
+ // ❌ Bad
191
+ it('works', () => { ... });
192
+
193
+ // ✅ Good
194
+ it('returns false when title exceeds 500 characters', () => { ... });
195
+ ```
196
+
197
+ **2. Arrange-Act-Assert pattern:**
198
+ ```javascript
199
+ it('calculates queue position correctly', () => {
200
+ // Arrange
201
+ const queue = [
202
+ { id: 1, timestamp: 100 },
203
+ { id: 2, timestamp: 200 },
204
+ { id: 3, timestamp: 300 }
205
+ ];
206
+
207
+ // Act
208
+ const position = getQueuePosition(queue, 2);
209
+
210
+ // Assert
211
+ expect(position).toBe(1); // 0-indexed
212
+ });
213
+ ```
214
+
215
+ **3. One assertion per test (when possible):**
216
+ ```javascript
217
+ // ❌ Too many concerns
218
+ it('validates and sanitizes input', () => {
219
+ expect(validate(input)).toBe(true);
220
+ expect(sanitize(input)).toBe(cleaned);
221
+ expect(process(cleaned)).toBe(result);
222
+ });
223
+
224
+ // ✅ Separate concerns
225
+ it('validates input', () => {
226
+ expect(validate(input)).toBe(true);
227
+ });
228
+
229
+ it('sanitizes input', () => {
230
+ expect(sanitize(input)).toBe(cleaned);
231
+ });
232
+
233
+ it('processes sanitized input', () => {
234
+ expect(process(cleaned)).toBe(result);
235
+ });
236
+ ```
237
+
238
+ **4. Test error conditions:**
239
+ ```javascript
240
+ describe('error handling', () => {
241
+ it('throws when database is locked', () => {
242
+ mockDb.isLocked = true;
243
+ expect(() => acquireLock()).toThrow('Database is locked');
244
+ });
245
+
246
+ it('throws with helpful message when file not found', () => {
247
+ expect(() => readConfig('/nonexistent')).toThrow(/Config file not found/);
248
+ });
249
+ });
250
+ ```
251
+
252
+ **5. Mock external dependencies:**
253
+ ```javascript
254
+ // ❌ Bad - depends on real file system
255
+ it('reads config file', () => {
256
+ const config = readConfig('.jettypod/config.json');
257
+ expect(config).toBeDefined();
258
+ });
259
+
260
+ // ✅ Good - mocked file system
261
+ jest.mock('fs');
262
+ it('reads config file', () => {
263
+ fs.readFileSync.mockReturnValue('{"key": "value"}');
264
+ const config = readConfig('.jettypod/config.json');
265
+ expect(config.key).toBe('value');
266
+ });
267
+ ```
268
+
269
+ ### When to Write Unit Tests
270
+
271
+ **In workflow:**
272
+ - **Stable mode**: When adding error handling logic
273
+ - **Standalone chores**: When implementing utility functions
274
+ - **Refactoring**: Before changing implementation
275
+
276
+ **What to unit test:**
277
+ - ✅ Pure functions (no side effects)
278
+ - ✅ Business logic
279
+ - ✅ Validation functions
280
+ - ✅ Utility functions
281
+ - ✅ Error handling paths
282
+ - ✅ Edge cases and boundary conditions
283
+
284
+ **What NOT to unit test:**
285
+ - ❌ External libraries (trust they're tested)
286
+ - ❌ Configuration files (use schema validation)
287
+ - ❌ Generated code
288
+ - ❌ Trivial getters/setters
289
+
290
+ ---
291
+
292
+ ## Test Type 2: Integration Tests (BDD/Cucumber)
293
+
294
+ ### What to Integration Test
295
+
296
+ **User workflows that span multiple modules:**
297
+ - Work item lifecycle (create → start → complete)
298
+ - Git integration (hooks, branches, worktrees)
299
+ - Feature workflow (planning → speed → stable → production)
300
+ - Database operations with business logic
301
+
302
+ ### Integration vs Unit Tests
303
+
304
+ | Unit Test | Integration Test |
305
+ |-----------|------------------|
306
+ | Single function | Multiple modules |
307
+ | Mocked dependencies | Real dependencies |
308
+ | Milliseconds | Seconds |
309
+ | Testing implementation | Testing behavior |
310
+ | Easy to debug | Harder to debug |
311
+
312
+ ### Example: Integration Test (BDD)
313
+
314
+ ```gherkin
315
+ # features/work-lifecycle.feature
316
+
317
+ Feature: Work Item Lifecycle
318
+ Test complete workflow from creation to completion
319
+
320
+ Background:
321
+ Given I have initialized jettypod with git
322
+ And I am on the main branch
323
+
324
+ Scenario: Create and complete a chore
325
+ When I create a chore "Fix merge lock bug"
326
+ Then a work item should exist with title "Fix merge lock bug"
327
+ And the work item status should be "todo"
328
+
329
+ When I start work on the chore
330
+ Then a git worktree should be created
331
+ And the work item status should be "in_progress"
332
+ And current work should be set to the chore
333
+
334
+ When I make a commit with message "Fix bug"
335
+ Then the work item status should be "in_progress"
336
+
337
+ When I merge the branch to main
338
+ Then the work item status should be "done"
339
+ And the worktree should be cleaned up
340
+ And current work should be cleared
341
+
342
+ Scenario: Multiple chores in sequence
343
+ Given I have a feature "User Authentication"
344
+ When I create a chore "Implement login" under the feature
345
+ And I create a chore "Add password reset" under the feature
346
+ Then both chores should have mode "speed"
347
+
348
+ When I start work on "Implement login"
349
+ And I complete the chore
350
+ Then I can start work on "Add password reset"
351
+ And the first chore should remain done
352
+ ```
353
+
354
+ ### Integration Test Step Definitions
355
+
356
+ ```javascript
357
+ // features/step_definitions/work-lifecycle.steps.js
358
+
359
+ const { Given, When, Then } = require('@cucumber/cucumber');
360
+ const { execSync } = require('child_process');
361
+ const fs = require('fs');
362
+ const path = require('path');
363
+ const { getDb } = require('../../lib/database');
364
+
365
+ // Setup and cleanup using test safety patterns
366
+ const { Before, After } = require('@cucumber/cucumber');
367
+
368
+ Before(function() {
369
+ // Track created items for cleanup
370
+ this.createdFiles = [];
371
+ this.createdDirs = [];
372
+ this.testWorkItems = [];
373
+
374
+ // Create isolated test environment
375
+ this.testDir = path.join(process.cwd(), '.test-temp', `test-${Date.now()}`);
376
+ fs.mkdirSync(this.testDir, { recursive: true });
377
+ this.createdDirs.push(this.testDir);
378
+
379
+ // Initialize test database
380
+ this.testDb = path.join(this.testDir, 'work.db');
381
+ process.env.JETTYPOD_DB = this.testDb;
382
+ });
383
+
384
+ After(function() {
385
+ // Cleanup test environment
386
+ if (this.testDir && fs.existsSync(this.testDir)) {
387
+ try {
388
+ fs.rmSync(this.testDir, { recursive: true, force: true });
389
+ } catch (e) {
390
+ console.error('Cleanup failed:', e);
391
+ }
392
+ }
393
+
394
+ // Close database connections
395
+ const db = getDb();
396
+ if (db) {
397
+ db.close();
398
+ }
399
+ });
400
+
401
+ // Step implementations
402
+ When('I create a chore {string}', function(title) {
403
+ const { create } = require('../../features/work-tracking');
404
+ const result = create('chore', title);
405
+
406
+ this.lastWorkItemId = result.id;
407
+ this.testWorkItems.push(result.id);
408
+ });
409
+
410
+ Then('a work item should exist with title {string}', function(expectedTitle) {
411
+ const db = getDb();
412
+ const item = db.prepare('SELECT * FROM work_items WHERE id = ?').get(this.lastWorkItemId);
413
+
414
+ expect(item).toBeDefined();
415
+ expect(item.title).toBe(expectedTitle);
416
+ });
417
+
418
+ When('I start work on the chore', function() {
419
+ const { startWork } = require('../../features/work-tracking');
420
+ startWork(this.lastWorkItemId);
421
+ });
422
+
423
+ Then('a git worktree should be created', function() {
424
+ const worktrees = execSync('git worktree list', { encoding: 'utf-8' });
425
+ const workItemBranch = `feature/work-${this.lastWorkItemId}`;
426
+
427
+ expect(worktrees).toContain(workItemBranch);
428
+ });
429
+ ```
430
+
431
+ ### Integration Test Best Practices
432
+
433
+ **1. Test realistic workflows:**
434
+ ```gherkin
435
+ # ✅ Good - realistic user workflow
436
+ Scenario: Developer completes a feature
437
+ Given I have a feature "Login" with 3 chores
438
+ When I complete all chores in speed mode
439
+ Then the feature should auto-elevate to stable mode
440
+ And stable mode chores should be auto-generated
441
+
442
+ # ❌ Bad - testing internals
443
+ Scenario: Database query returns correct result
444
+ When I execute SQL "SELECT * FROM work_items"
445
+ Then the result should have correct columns
446
+ ```
447
+
448
+ **2. Use Background for common setup:**
449
+ ```gherkin
450
+ Background:
451
+ Given I have initialized jettypod with git
452
+ And I am on the main branch
453
+ And no work is currently in progress
454
+ ```
455
+
456
+ **3. Tag scenarios for selective running:**
457
+ ```gherkin
458
+ @wip
459
+ Scenario: Feature under development
460
+ ...
461
+
462
+ @slow
463
+ Scenario: Complex workflow with many steps
464
+ ...
465
+
466
+ @production
467
+ Scenario: Security hardening validation
468
+ ...
469
+ ```
470
+
471
+ **4. Keep scenarios independent:**
472
+ ```gherkin
473
+ # ❌ Bad - depends on previous scenario
474
+ Scenario: Create feature
475
+ When I create feature "Login"
476
+
477
+ Scenario: Add chore to feature
478
+ When I add chore to "Login" # Assumes Login exists
479
+
480
+ # ✅ Good - independent
481
+ Scenario: Add chore to feature
482
+ Given I have a feature "Login"
483
+ When I add chore to the feature
484
+ ```
485
+
486
+ ---
487
+
488
+ ## Test Type 3: End-to-End Tests
489
+
490
+ ### What Makes E2E Different
491
+
492
+ **Integration tests:**
493
+ - Test modules working together
494
+ - May use test doubles/mocks
495
+ - Run in test environment
496
+ - Focus on specific workflows
497
+
498
+ **E2E tests:**
499
+ - Test ENTIRE system as user sees it
500
+ - NO mocks (real everything)
501
+ - Production-like environment
502
+ - Test critical paths only
503
+
504
+ ### E2E Test Strategy for JettyPod
505
+
506
+ **Critical paths to E2E test:**
507
+ 1. First-time user initialization
508
+ 2. Feature planning → implementation → completion
509
+ 3. Git hook integration (real git commits)
510
+ 4. Worktree creation and cleanup
511
+ 5. Database migration/initialization
512
+
513
+ ### Example: E2E Test
514
+
515
+ ```javascript
516
+ // test/e2e/complete-workflow.e2e.test.js
517
+
518
+ const { execSync } = require('child_process');
519
+ const fs = require('fs');
520
+ const path = require('path');
521
+ const os = require('os');
522
+
523
+ describe('E2E: Complete Feature Workflow', () => {
524
+ let testDir;
525
+ let originalCwd;
526
+
527
+ beforeEach(() => {
528
+ // Create completely isolated environment
529
+ testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'jettypod-e2e-'));
530
+ originalCwd = process.cwd();
531
+ process.chdir(testDir);
532
+
533
+ // Initialize real git repo
534
+ execSync('git init');
535
+ execSync('git config user.email "test@example.com"');
536
+ execSync('git config user.name "Test User"');
537
+
538
+ // Create initial commit (git requires one)
539
+ fs.writeFileSync('README.md', '# Test Project');
540
+ execSync('git add .');
541
+ execSync('git commit -m "Initial commit"');
542
+ });
543
+
544
+ afterEach(() => {
545
+ process.chdir(originalCwd);
546
+ fs.rmSync(testDir, { recursive: true, force: true });
547
+ });
548
+
549
+ test('Complete feature workflow from init to done', () => {
550
+ // 1. Initialize jettypod
551
+ const initOutput = execSync('node /path/to/jettypod.js init', {
552
+ encoding: 'utf-8'
553
+ });
554
+ expect(initOutput).toContain('JettyPod initialized');
555
+ expect(fs.existsSync('.jettypod/work.db')).toBe(true);
556
+
557
+ // 2. Create feature
558
+ const createOutput = execSync(
559
+ 'node /path/to/jettypod.js work create feature "User Login"',
560
+ { encoding: 'utf-8' }
561
+ );
562
+ expect(createOutput).toContain('Created feature');
563
+ const featureId = parseInt(createOutput.match(/ID: (\d+)/)[1]);
564
+
565
+ // 3. Start feature planning (manual for E2E)
566
+ execSync(`node /path/to/jettypod.js work start ${featureId}`);
567
+
568
+ // Create BDD scenario manually (simulating skill output)
569
+ fs.mkdirSync('features', { recursive: true });
570
+ fs.writeFileSync('features/user-login.feature', `
571
+ Feature: User Login
572
+ Scenario: User logs in successfully
573
+ Given I am on the login page
574
+ When I enter valid credentials
575
+ Then I am redirected to dashboard
576
+ `);
577
+
578
+ // 4. Transition to implementation
579
+ execSync(
580
+ `node /path/to/jettypod.js work implement ${featureId} --winner="Simple form"`,
581
+ { encoding: 'utf-8' }
582
+ );
583
+
584
+ // 5. Create and complete speed mode chore
585
+ const choreOutput = execSync(
586
+ `node /path/to/jettypod.js work create chore "Implement login form" --parent=${featureId}`,
587
+ { encoding: 'utf-8' }
588
+ );
589
+ const choreId = parseInt(choreOutput.match(/ID: (\d+)/)[1]);
590
+
591
+ execSync(`node /path/to/jettypod.js work start ${choreId}`);
592
+
593
+ // Check worktree was created
594
+ const worktrees = execSync('git worktree list', { encoding: 'utf-8' });
595
+ expect(worktrees).toContain(`work-${choreId}`);
596
+
597
+ // Make commit (should trigger post-commit hook)
598
+ fs.writeFileSync('login.js', 'module.exports = function login() {}');
599
+ execSync('git add .');
600
+ execSync('git commit -m "Implement login"');
601
+
602
+ // 6. Merge to main (should trigger post-merge hook)
603
+ execSync('git checkout main');
604
+ execSync(`git merge feature/work-${choreId}-implement-login-form`);
605
+
606
+ // Check work item marked as done
607
+ const statusOutput = execSync(
608
+ `node /path/to/jettypod.js work show ${choreId}`,
609
+ { encoding: 'utf-8' }
610
+ );
611
+ expect(statusOutput).toContain('Status: done');
612
+
613
+ // Check worktree cleaned up
614
+ const finalWorktrees = execSync('git worktree list', { encoding: 'utf-8' });
615
+ expect(finalWorktrees).not.toContain(`work-${choreId}`);
616
+
617
+ }, 30000); // 30 second timeout for E2E
618
+
619
+ test('Git hooks work correctly', () => {
620
+ execSync('node /path/to/jettypod.js init');
621
+
622
+ const choreId = parseInt(
623
+ execSync('node /path/to/jettypod.js work create chore "Test hooks"', {
624
+ encoding: 'utf-8'
625
+ }).match(/ID: (\d+)/)[1]
626
+ );
627
+
628
+ execSync(`node /path/to/jettypod.js work start ${choreId}`);
629
+
630
+ // Check initial status
631
+ let status = execSync(`node /path/to/jettypod.js work show ${choreId}`, {
632
+ encoding: 'utf-8'
633
+ });
634
+ expect(status).toContain('Status: todo');
635
+
636
+ // Make first commit - should trigger post-commit hook
637
+ fs.writeFileSync('test.js', 'console.log("test")');
638
+ execSync('git add .');
639
+ execSync('git commit -m "Test commit"');
640
+
641
+ // Check status updated to in_progress
642
+ status = execSync(`node /path/to/jettypod.js work show ${choreId}`, {
643
+ encoding: 'utf-8'
644
+ });
645
+ expect(status).toContain('Status: in_progress');
646
+
647
+ // Merge to main - should trigger post-merge hook
648
+ execSync('git checkout main');
649
+ execSync(`git merge feature/work-${choreId}-test-hooks`);
650
+
651
+ // Check status updated to done
652
+ status = execSync(`node /path/to/jettypod.js work show ${choreId}`, {
653
+ encoding: 'utf-8'
654
+ });
655
+ expect(status).toContain('Status: done');
656
+ }, 30000);
657
+ });
658
+ ```
659
+
660
+ ### E2E Test Best Practices
661
+
662
+ **1. Only test critical paths:**
663
+ - Don't duplicate integration test coverage
664
+ - Focus on "user can accomplish their goal"
665
+ - Test with real data, real environment
666
+
667
+ **2. Make tests resilient:**
668
+ ```javascript
669
+ // ❌ Brittle - depends on exact output format
670
+ expect(output).toBe('Created feature #1: User Login');
671
+
672
+ // ✅ Resilient - checks essential information
673
+ expect(output).toContain('Created feature');
674
+ expect(output).toMatch(/ID: \d+/);
675
+ expect(output).toContain('User Login');
676
+ ```
677
+
678
+ **3. Clean up properly:**
679
+ ```javascript
680
+ afterEach(() => {
681
+ // Always clean up, even if test failed
682
+ try {
683
+ process.chdir(originalCwd);
684
+ fs.rmSync(testDir, { recursive: true, force: true });
685
+ } catch (e) {
686
+ console.error('E2E cleanup failed:', e);
687
+ }
688
+ });
689
+ ```
690
+
691
+ **4. Use longer timeouts:**
692
+ ```javascript
693
+ test('complete workflow', () => {
694
+ // E2E tests are slower
695
+ }, 30000); // 30 seconds
696
+ ```
697
+
698
+ ---
699
+
700
+ ## Test Type 4: Performance Tests
701
+
702
+ ### What to Performance Test
703
+
704
+ **For JettyPod (CLI tool):**
705
+ - Command execution time
706
+ - Database query performance
707
+ - File operations (especially with many worktrees)
708
+ - Git operations
709
+
710
+ ### Performance Testing Strategy
711
+
712
+ ```javascript
713
+ // test/performance/commands.perf.test.js
714
+
715
+ describe('Performance: Command Execution', () => {
716
+ test('work create should complete in under 100ms', () => {
717
+ const start = Date.now();
718
+
719
+ execSync('node jettypod.js work create chore "Test"');
720
+
721
+ const duration = Date.now() - start;
722
+ expect(duration).toBeLessThan(100);
723
+ });
724
+
725
+ test('backlog command scales with many work items', () => {
726
+ // Create 1000 work items
727
+ for (let i = 0; i < 1000; i++) {
728
+ execSync(`node jettypod.js work create chore "Item ${i}"`);
729
+ }
730
+
731
+ const start = Date.now();
732
+ execSync('node jettypod.js backlog');
733
+ const duration = Date.now() - start;
734
+
735
+ // Should still be under 500ms with 1000 items
736
+ expect(duration).toBeLessThan(500);
737
+ });
738
+ });
739
+ ```
740
+
741
+ ### Performance Test with BDD
742
+
743
+ ```gherkin
744
+ # features/performance.feature
745
+
746
+ @performance
747
+ Feature: Performance Requirements
748
+ Ensure commands execute within acceptable time limits
749
+
750
+ Scenario: Work item creation is fast
751
+ Given I have 100 existing work items
752
+ When I create a new work item
753
+ Then it should complete in under 100ms
754
+
755
+ Scenario: Backlog scales with large datasets
756
+ Given I have 1000 work items
757
+ When I run the backlog command
758
+ Then it should complete in under 500ms
759
+ And it should return all items
760
+
761
+ Scenario: Git operations don't block
762
+ Given I have 50 worktrees
763
+ When I create a new worktree
764
+ Then it should complete in under 2 seconds
765
+ ```
766
+
767
+ ```javascript
768
+ // features/step_definitions/performance.steps.js
769
+
770
+ When('I create a new work item', function() {
771
+ this.startTime = Date.now();
772
+ execSync('node jettypod.js work create chore "Test"');
773
+ this.duration = Date.now() - this.startTime;
774
+ });
775
+
776
+ Then('it should complete in under {int}ms', function(maxMs) {
777
+ expect(this.duration).toBeLessThan(maxMs);
778
+ });
779
+ ```
780
+
781
+ ---
782
+
783
+ ## Test Type 5: Security Tests
784
+
785
+ ### What to Security Test
786
+
787
+ **For JettyPod:**
788
+ - SQL injection in database queries
789
+ - Command injection in git operations
790
+ - Path traversal in file operations
791
+ - Input validation
792
+
793
+ ### Security Testing Examples
794
+
795
+ ```javascript
796
+ // test/security/injection.test.js
797
+
798
+ describe('Security: SQL Injection Prevention', () => {
799
+ test('prevents SQL injection in work item title', () => {
800
+ const maliciousTitle = "'; DROP TABLE work_items; --";
801
+
802
+ const { create } = require('../../features/work-tracking');
803
+ const result = create('chore', maliciousTitle);
804
+
805
+ // Should escape SQL properly
806
+ expect(result.id).toBeDefined();
807
+
808
+ // Table should still exist
809
+ const db = getDb();
810
+ const items = db.prepare('SELECT * FROM work_items').all();
811
+ expect(items).toBeDefined();
812
+ });
813
+
814
+ test('prevents SQL injection in search', () => {
815
+ const maliciousSearch = "' OR '1'='1";
816
+
817
+ const { search } = require('../../features/work-tracking');
818
+ const results = search(maliciousSearch);
819
+
820
+ // Should not return all items
821
+ expect(results.length).toBe(0);
822
+ });
823
+ });
824
+
825
+ describe('Security: Command Injection Prevention', () => {
826
+ test('prevents command injection in git operations', () => {
827
+ const maliciousMessage = 'commit"; rm -rf /; echo "';
828
+
829
+ expect(() => {
830
+ execSync(`git commit -m "${maliciousMessage}"`);
831
+ }).not.toThrow();
832
+
833
+ // System should still be intact
834
+ expect(fs.existsSync('.')).toBe(true);
835
+ });
836
+ });
837
+
838
+ describe('Security: Path Traversal Prevention', () => {
839
+ test('prevents path traversal in file operations', () => {
840
+ const maliciousPath = '../../../../etc/passwd';
841
+
842
+ const { readConfig } = require('../../lib/config');
843
+
844
+ expect(() => {
845
+ readConfig(maliciousPath);
846
+ }).toThrow(/Invalid path/);
847
+ });
848
+ });
849
+ ```
850
+
851
+ ---
852
+
853
+ ## Test Coverage Strategy
854
+
855
+ ### Coverage Goals
856
+
857
+ ```javascript
858
+ // jest.config.js
859
+ module.exports = {
860
+ collectCoverageFrom: [
861
+ 'lib/**/*.js',
862
+ 'features/**/*.js',
863
+ '!**/*.test.js',
864
+ '!**/node_modules/**',
865
+ '!**/__tests__/**'
866
+ ],
867
+ coverageThresholds: {
868
+ global: {
869
+ branches: 80,
870
+ functions: 80,
871
+ lines: 80,
872
+ statements: 80
873
+ },
874
+ // Stricter for core library code
875
+ 'lib/**/*.js': {
876
+ branches: 90,
877
+ functions: 90,
878
+ lines: 90,
879
+ statements: 90
880
+ }
881
+ },
882
+ coverageReporters: ['text', 'text-summary', 'html', 'lcov']
883
+ };
884
+ ```
885
+
886
+ ### What Coverage Numbers Mean
887
+
888
+ **Lines covered: 80%** = 80% of code lines executed during tests
889
+ **Branches covered: 80%** = 80% of if/else paths tested
890
+ **Functions covered: 80%** = 80% of functions called
891
+ **Statements covered: 80%** = 80% of statements executed
892
+
893
+ **100% coverage ≠ bug-free code**
894
+ - Coverage measures execution, not correctness
895
+ - Can have 100% coverage with bad assertions
896
+ - Focus on meaningful tests, not coverage %
897
+
898
+ ---
899
+
900
+ ## Complete Testing Checklist
901
+
902
+ ### Feature Workflow Testing
903
+
904
+ **Feature-Planning:**
905
+ - [ ] Dry-run BDD scenarios (syntax validation)
906
+ - [ ] Step definitions match scenario steps
907
+ - [ ] Test safety hooks in place
908
+
909
+ **Speed-Mode:**
910
+ - [ ] Happy path BDD scenario passes
911
+ - [ ] Basic unit tests for new functions
912
+ - [ ] No regressions in existing tests
913
+
914
+ **Stable-Mode:**
915
+ - [ ] All BDD scenarios pass (happy + error + edge)
916
+ - [ ] Unit tests for error handling logic
917
+ - [ ] Integration tests for module interactions
918
+ - [ ] Test coverage >= 80% for new code
919
+
920
+ **Production-Mode:**
921
+ - [ ] Production BDD scenarios pass
922
+ - [ ] Security tests for vulnerabilities
923
+ - [ ] Performance tests meet targets
924
+ - [ ] No regressions in full test suite
925
+
926
+ ### Standalone Chore Testing
927
+
928
+ - [ ] Unit tests for new functionality
929
+ - [ ] Integration tests if touching multiple modules
930
+ - [ ] No regressions in existing tests
931
+ - [ ] Test coverage >= 80% for changes
932
+
933
+ ---
934
+
935
+ ## Summary: Realistic Testing Strategy
936
+
937
+ ### What You Actually Need
938
+
939
+ **Priority 1 (Must Have):**
940
+ 1. ✅ Unit tests for lib/ code (60% of tests)
941
+ 2. ✅ BDD integration tests for workflows (30% of tests)
942
+ 3. ✅ Test safety infrastructure (cleanup hooks)
943
+ 4. ✅ Pre-commit/pre-push git hooks
944
+
945
+ **Priority 2 (Should Have):**
946
+ 5. ✅ E2E tests for critical paths (10% of tests)
947
+ 6. ✅ Basic performance tests (timing checks)
948
+ 7. ✅ Test coverage tracking (80% threshold)
949
+
950
+ **Priority 3 (Nice to Have):**
951
+ 8. ⚠️ Security tests (injection prevention)
952
+ 9. ⚠️ Mutation testing (test quality)
953
+
954
+ **Not Needed (For Your Project):**
955
+ - ❌ Visual regression tests (no UI)
956
+ - ❌ Contract tests (no external APIs yet)
957
+ - ❌ Load tests (single-user CLI)
958
+ - ❌ Accessibility tests (no UI)
959
+
960
+ ### The Honest Truth
961
+
962
+ You don't need ALL testing best practices. You need:
963
+ - **Fast unit tests** that give immediate feedback
964
+ - **Reliable integration tests** that catch workflow bugs
965
+ - **Selective E2E tests** for critical paths
966
+ - **Smart git hooks** that don't kill velocity
967
+
968
+ The previous document (TDD-INFRASTRUCTURE-STRATEGY.md) had the git hooks and timing strategy right. This document fills in the gaps on WHAT to test and HOW to test it properly.
969
+
970
+ **Together they form a complete strategy.**