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
@@ -1,235 +0,0 @@
1
- const {
2
- appendScenarios,
3
- formatScenarioForAppend,
4
- generateTitleFromStandard,
5
- extractScenarioTitles,
6
- extractScenarioTitle,
7
- deduplicateScenarios
8
- } = require('./production-scenario-appender');
9
- const fs = require('fs');
10
- const path = require('path');
11
-
12
- describe('production-scenario-appender', () => {
13
- let testDir;
14
-
15
- beforeEach(() => {
16
- testDir = path.join(__dirname, '../test-tmp', `scenario-appender-${Date.now()}`);
17
- fs.mkdirSync(testDir, { recursive: true });
18
- process.chdir(testDir);
19
- });
20
-
21
- afterEach(() => {
22
- if (testDir && fs.existsSync(testDir)) {
23
- fs.rmSync(testDir, { recursive: true, force: true });
24
- }
25
- });
26
-
27
- describe('generateTitleFromStandard', () => {
28
- test('converts snake_case to Title Case', () => {
29
- const standard = {
30
- id: 'tls_enforced',
31
- domain: 'security'
32
- };
33
-
34
- const title = generateTitleFromStandard(standard);
35
- expect(title).toBe('Security - Tls Enforced (production mode)');
36
- });
37
-
38
- test('handles multi-word IDs', () => {
39
- const standard = {
40
- id: 'performance_budgets_enforced',
41
- domain: 'performance'
42
- };
43
-
44
- const title = generateTitleFromStandard(standard);
45
- expect(title).toBe('Performance - Performance Budgets Enforced (production mode)');
46
- });
47
- });
48
-
49
- describe('formatScenarioForAppend', () => {
50
- test('formats security standard as scenario', () => {
51
- const standard = {
52
- id: 'tls_enforced',
53
- domain: 'security',
54
- acceptance: 'HSTS ≥ 6mo; TLS ≥1.2'
55
- };
56
-
57
- const scenario = formatScenarioForAppend(standard);
58
-
59
- expect(scenario).toContain('Scenario: Security - Tls Enforced');
60
- expect(scenario).toContain('Given the system is deployed to production');
61
- expect(scenario).toContain('Then HSTS ≥ 6mo; TLS ≥1.2');
62
- });
63
-
64
- test('formats performance standard as scenario', () => {
65
- const standard = {
66
- id: 'performance_budgets',
67
- domain: 'performance',
68
- acceptance: 'p95 < 2s'
69
- };
70
-
71
- const scenario = formatScenarioForAppend(standard);
72
-
73
- expect(scenario).toContain('Scenario: Performance - Performance Budgets');
74
- expect(scenario).toContain('Given the system is under production load');
75
- expect(scenario).toContain('Then p95 < 2s');
76
- });
77
- });
78
-
79
- describe('extractScenarioTitles', () => {
80
- test('extracts titles from content', () => {
81
- const content = `Feature: Test
82
-
83
- Scenario: User logs in
84
- Given credentials
85
- When submitting
86
- Then success
87
-
88
- Scenario: Password reset
89
- Given forgot password
90
- When requesting reset
91
- Then email sent`;
92
-
93
- const titles = extractScenarioTitles(content);
94
-
95
- expect(titles).toHaveLength(2);
96
- expect(titles).toContain('user logs in');
97
- expect(titles).toContain('password reset');
98
- });
99
-
100
- test('returns empty array for no scenarios', () => {
101
- const content = 'Feature: Test\n\nNo scenarios here';
102
-
103
- const titles = extractScenarioTitles(content);
104
- expect(titles).toEqual([]);
105
- });
106
- });
107
-
108
- describe('extractScenarioTitle', () => {
109
- test('extracts title from scenario string', () => {
110
- const scenario = `Scenario: User logs in
111
- Given credentials
112
- Then success`;
113
-
114
- const title = extractScenarioTitle(scenario);
115
- expect(title).toBe('User logs in');
116
- });
117
-
118
- test('returns null for invalid scenario', () => {
119
- const scenario = 'Not a scenario';
120
-
121
- const title = extractScenarioTitle(scenario);
122
- expect(title).toBeNull();
123
- });
124
- });
125
-
126
- describe('appendScenarios', () => {
127
- test('throws error when file not found', async () => {
128
- await expect(appendScenarios('nonexistent.feature', []))
129
- .rejects.toThrow('Scenario file not found');
130
- });
131
-
132
- test('adds production mode header if not present', async () => {
133
- const scenarioFile = path.join(testDir, 'test.feature');
134
- fs.writeFileSync(scenarioFile, 'Feature: Test\n\nScenario: Happy path\n Given test\n');
135
-
136
- const newScenarios = ['Scenario: New scenario\n Given production\n Then test'];
137
-
138
- await appendScenarios('test.feature', newScenarios);
139
-
140
- const content = fs.readFileSync(scenarioFile, 'utf8');
141
- expect(content).toContain('# PRODUCTION MODE SCENARIOS');
142
- expect(content).toContain('Scenario: New scenario');
143
- });
144
-
145
- test('does not duplicate production mode header', async () => {
146
- const scenarioFile = path.join(testDir, 'test.feature');
147
- fs.writeFileSync(scenarioFile, `Feature: Test
148
-
149
- # PRODUCTION MODE SCENARIOS
150
-
151
- Scenario: Existing production scenario
152
- Given test
153
- `);
154
-
155
- const newScenarios = ['Scenario: New scenario\n Given production\n Then test'];
156
-
157
- await appendScenarios('test.feature', newScenarios);
158
-
159
- const content = fs.readFileSync(scenarioFile, 'utf8');
160
- const headerCount = (content.match(/# PRODUCTION MODE SCENARIOS/g) || []).length;
161
- expect(headerCount).toBe(1);
162
- });
163
-
164
- test('deduplicates scenarios by title', async () => {
165
- const scenarioFile = path.join(testDir, 'test.feature');
166
- fs.writeFileSync(scenarioFile, `Feature: Test
167
-
168
- Scenario: Existing scenario
169
- Given test
170
- `);
171
-
172
- const newScenarios = [
173
- 'Scenario: Existing scenario\n Given duplicate\n Then skip',
174
- 'Scenario: New scenario\n Given production\n Then test'
175
- ];
176
-
177
- const result = await appendScenarios('test.feature', newScenarios);
178
-
179
- expect(result.added).toBe(1);
180
- expect(result.skipped).toBe(1);
181
-
182
- const content = fs.readFileSync(scenarioFile, 'utf8');
183
- expect(content).toContain('Scenario: New scenario');
184
- expect(content.match(/Scenario: Existing scenario/g)).toHaveLength(1);
185
- });
186
- });
187
-
188
- describe('deduplicateScenarios', () => {
189
- test('removes duplicate scenarios', async () => {
190
- const scenarioFile = path.join(testDir, 'test.feature');
191
- fs.writeFileSync(scenarioFile, `Feature: Test
192
-
193
- Scenario: Test scenario
194
- Given test1
195
- Then success
196
-
197
- Scenario: Another scenario
198
- Given test2
199
- Then success
200
-
201
- Scenario: Test scenario
202
- Given duplicate
203
- Then success
204
- `);
205
-
206
- const result = await deduplicateScenarios('test.feature');
207
-
208
- expect(result.duplicatesRemoved).toBe(1);
209
-
210
- const content = fs.readFileSync(scenarioFile, 'utf8');
211
- expect(content.match(/Scenario: Test scenario/g)).toHaveLength(1);
212
- expect(content.match(/Scenario: Another scenario/g)).toHaveLength(1);
213
- });
214
-
215
- test('preserves first occurrence of duplicate', async () => {
216
- const scenarioFile = path.join(testDir, 'test.feature');
217
- fs.writeFileSync(scenarioFile, `Feature: Test
218
-
219
- Scenario: Test scenario
220
- Given test1
221
- Then success
222
-
223
- Scenario: Test scenario
224
- Given test2
225
- Then success
226
- `);
227
-
228
- await deduplicateScenarios('test.feature');
229
-
230
- const content = fs.readFileSync(scenarioFile, 'utf8');
231
- expect(content).toContain('Given test1');
232
- expect(content).not.toContain('Given test2');
233
- });
234
- });
235
- });
@@ -1,246 +0,0 @@
1
- const {
2
- validateScenarios,
3
- parseScenarios,
4
- matchStandardToScenario,
5
- generateKeywords
6
- } = require('./production-scenario-validator');
7
- const fs = require('fs');
8
- const path = require('path');
9
-
10
- describe('production-scenario-validator', () => {
11
- let testDir;
12
-
13
- beforeEach(() => {
14
- testDir = path.join(__dirname, '../test-tmp', `scenario-validator-${Date.now()}`);
15
- fs.mkdirSync(testDir, { recursive: true });
16
- process.chdir(testDir);
17
- });
18
-
19
- afterEach(() => {
20
- if (testDir && fs.existsSync(testDir)) {
21
- fs.rmSync(testDir, { recursive: true, force: true });
22
- }
23
- });
24
-
25
- describe('parseScenarios', () => {
26
- test('parses single scenario', () => {
27
- const content = `Feature: Test
28
-
29
- Scenario: User logs in
30
- Given I am on the login page
31
- When I enter credentials
32
- Then I am logged in`;
33
-
34
- const scenarios = parseScenarios(content);
35
-
36
- expect(scenarios).toHaveLength(1);
37
- expect(scenarios[0].title).toBe('User logs in');
38
- expect(scenarios[0].content).toContain('Given I am on the login page');
39
- });
40
-
41
- test('parses multiple scenarios', () => {
42
- const content = `Feature: Test
43
-
44
- Scenario: Happy path
45
- Given initial state
46
- When action
47
- Then success
48
-
49
- Scenario: Error case
50
- Given error state
51
- When action
52
- Then error`;
53
-
54
- const scenarios = parseScenarios(content);
55
-
56
- expect(scenarios).toHaveLength(2);
57
- expect(scenarios[0].title).toBe('Happy path');
58
- expect(scenarios[1].title).toBe('Error case');
59
- });
60
-
61
- test('returns empty array for no scenarios', () => {
62
- const content = 'Feature: Test\n\nNo scenarios here';
63
-
64
- const scenarios = parseScenarios(content);
65
-
66
- expect(scenarios).toHaveLength(0);
67
- });
68
- });
69
-
70
- describe('generateKeywords', () => {
71
- test('generates keywords from standard ID', () => {
72
- const standard = {
73
- id: 'tls_enforced',
74
- domain: 'security',
75
- acceptance: 'TLS 1.2 required'
76
- };
77
-
78
- const keywords = generateKeywords(standard);
79
-
80
- expect(keywords).toContain('tls');
81
- expect(keywords).toContain('enforced');
82
- });
83
-
84
- test('includes domain-specific keywords', () => {
85
- const standard = {
86
- id: 'test_security',
87
- domain: 'security',
88
- acceptance: 'test'
89
- };
90
-
91
- const keywords = generateKeywords(standard);
92
-
93
- expect(keywords).toContain('authentication');
94
- expect(keywords).toContain('encryption');
95
- expect(keywords).toContain('rate limiting');
96
- });
97
-
98
- test('includes keywords from acceptance criteria', () => {
99
- const standard = {
100
- id: 'test',
101
- domain: 'performance',
102
- acceptance: 'p95 latency < 2s; load testing required'
103
- };
104
-
105
- const keywords = generateKeywords(standard);
106
-
107
- expect(keywords).toContain('latency');
108
- expect(keywords).toContain('load');
109
- expect(keywords).toContain('testing');
110
- expect(keywords).toContain('required');
111
- });
112
- });
113
-
114
- describe('matchStandardToScenario', () => {
115
- test('returns false when no scenarios match', () => {
116
- const standard = {
117
- id: 'tls_enforced',
118
- domain: 'security',
119
- acceptance: 'TLS 1.2 required'
120
- };
121
-
122
- const scenarios = [
123
- {
124
- title: 'User login',
125
- content: 'Given I am logged in'
126
- }
127
- ];
128
-
129
- const result = matchStandardToScenario(standard, scenarios);
130
- expect(result).toBe(false);
131
- });
132
-
133
- test('returns true when scenario matches standard', () => {
134
- const standard = {
135
- id: 'tls_enforced',
136
- domain: 'security',
137
- acceptance: 'TLS 1.2 required'
138
- };
139
-
140
- const scenarios = [
141
- {
142
- title: 'TLS encryption is enforced',
143
- content: 'Given HTTPS is enabled\nWhen connecting\nThen TLS 1.2 is required'
144
- }
145
- ];
146
-
147
- const result = matchStandardToScenario(standard, scenarios);
148
- expect(result).toBe(true);
149
- });
150
-
151
- test('matches on domain keywords', () => {
152
- const standard = {
153
- id: 'auth_required',
154
- domain: 'security',
155
- acceptance: 'Authentication required for all endpoints'
156
- };
157
-
158
- const scenarios = [
159
- {
160
- title: 'User authentication',
161
- content: 'Given user has valid credentials\nWhen accessing API\nThen authentication succeeds'
162
- }
163
- ];
164
-
165
- const result = matchStandardToScenario(standard, scenarios);
166
- expect(result).toBe(true);
167
- });
168
- });
169
-
170
- describe('validateScenarios', () => {
171
- test('throws error when scenario file not found', async () => {
172
- const standards = {
173
- standards: []
174
- };
175
-
176
- await expect(validateScenarios('nonexistent.feature', standards))
177
- .rejects.toThrow('Scenario file not found');
178
- });
179
-
180
- test('returns all gaps when no scenarios exist', async () => {
181
- const scenarioFile = path.join(testDir, 'test.feature');
182
- fs.writeFileSync(scenarioFile, 'Feature: Test\n\n');
183
-
184
- const standards = {
185
- standards: [
186
- {
187
- id: 'tls_enforced',
188
- domain: 'security',
189
- acceptance: 'TLS 1.2',
190
- reasoning: 'Security requirement'
191
- },
192
- {
193
- id: 'performance_budgets',
194
- domain: 'performance',
195
- acceptance: 'p95 < 2s',
196
- reasoning: 'Performance requirement'
197
- }
198
- ]
199
- };
200
-
201
- const result = await validateScenarios('test.feature', standards);
202
-
203
- expect(result.covered).toBe(0);
204
- expect(result.total).toBe(2);
205
- expect(result.gaps).toHaveLength(2);
206
- expect(result.hasGaps).toBe(true);
207
- });
208
-
209
- test('returns no gaps when all standards are covered', async () => {
210
- const scenarioFile = path.join(testDir, 'test.feature');
211
- fs.writeFileSync(scenarioFile, `Feature: Test
212
-
213
- Scenario: TLS encryption
214
- Given HTTPS enabled
215
- When connecting
216
- Then TLS 1.2 required
217
-
218
- Scenario: Performance testing
219
- Given system under load
220
- When measuring latency
221
- Then p95 < 2s`);
222
-
223
- const standards = {
224
- standards: [
225
- {
226
- id: 'tls_enforced',
227
- domain: 'security',
228
- acceptance: 'TLS 1.2'
229
- },
230
- {
231
- id: 'performance_budgets',
232
- domain: 'performance',
233
- acceptance: 'p95 < 2s'
234
- }
235
- ]
236
- };
237
-
238
- const result = await validateScenarios('test.feature', standards);
239
-
240
- expect(result.covered).toBe(2);
241
- expect(result.total).toBe(2);
242
- expect(result.gaps).toHaveLength(0);
243
- expect(result.hasGaps).toBe(false);
244
- });
245
- });
246
- });