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.
- package/.nvmrc +1 -0
- package/docs/COMPLETE-TESTING-STRATEGY.md +970 -0
- package/docs/DECISIONS.md +10 -12
- package/docs/NODE_VERSION.md +83 -0
- package/docs/TDD-INFRASTRUCTURE-STRATEGY.md +1374 -0
- package/docs/TESTING-FOR-NON-ENGINEERS.md +1588 -0
- package/docs/TESTING-STRATEGY-AUDIT.md +698 -0
- package/hooks/post-checkout +17 -0
- package/hooks/post-merge +17 -0
- package/hooks/pre-commit +30 -0
- package/jettypod.js +259 -120
- package/lib/coverage-tracker.js +218 -0
- package/lib/database.js +2 -0
- package/lib/db-export.js +192 -0
- package/lib/db-import.js +193 -0
- package/lib/external-transition-handler.js +32 -0
- package/lib/git-hook-helpers.js +174 -0
- package/lib/git-root.js +90 -0
- package/lib/infrastructure-chore-generator.js +45 -0
- package/lib/install-hooks.js +52 -0
- package/lib/jettypod-backup.js +238 -0
- package/lib/merge-lock.js +193 -0
- package/lib/migrations/012-add-worktree-path.js +38 -0
- package/lib/migrations/013-worktrees-table.js +86 -0
- package/lib/migrations/014-migrate-worktree-data.js +161 -0
- package/lib/migrations/015-merge-locks-table.js +67 -0
- package/lib/pattern-finder.js +152 -0
- package/lib/process-manager.js +140 -0
- package/lib/production-standards-reader.js +13 -2
- package/lib/production-standards-writer.js +85 -0
- package/lib/skills/feature-planning/dry-run-validator.js +135 -0
- package/lib/skills/feature-planning/validation-formatter.js +160 -0
- package/lib/smart-conflict-detection.js +168 -0
- package/lib/smart-fetch-rebase.js +614 -0
- package/lib/step-definition-parser.js +76 -0
- package/lib/unit-test-generator.js +232 -0
- package/lib/verification-command-generator.js +66 -0
- package/lib/worktree-diagnostics.js +413 -0
- package/lib/worktree-facade.js +174 -0
- package/lib/worktree-manager.js +636 -0
- package/lib/worktree-reconciler.js +429 -0
- package/package.json +30 -3
- package/skills-templates/external-transition/SKILL.md +34 -3
- package/skills-templates/feature-planning/SKILL.md +190 -24
- package/skills-templates/production-mode/SKILL.md +127 -9
- package/skills-templates/speed-mode/SKILL.md +454 -51
- package/skills-templates/stable-mode/SKILL.md +285 -76
- package/.claude/PROTECT_SKILLS.md +0 -28
- package/.claude/settings.json +0 -24
- package/.claude/settings.local.json +0 -16
- package/.claude/skills/epic-planning/SKILL.md +0 -297
- package/.claude/skills/external-transition/SKILL.md +0 -384
- package/.claude/skills/feature-planning/SKILL.md +0 -464
- package/.claude/skills/production-mode/SKILL.md +0 -369
- package/.claude/skills/speed-mode/SKILL.md +0 -481
- package/.claude/skills/stable-mode/SKILL.md +0 -713
- package/.claude/skills.backup-2025-11-10T23-33-09-368Z/epic-planning/SKILL.md +0 -297
- package/.claude/skills.backup-2025-11-10T23-33-09-368Z/feature-planning/SKILL.md +0 -464
- package/.claude/skills.backup-2025-11-10T23-33-09-368Z/speed-mode/SKILL.md +0 -467
- package/.claude/skills.backup-2025-11-10T23-33-09-368Z/stable-mode/SKILL.md +0 -673
- package/.claude/skills.backup-2025-11-11T16-15-10-070Z/epic-discover/SKILL.md +0 -297
- package/.claude/skills.backup-2025-11-11T16-42-43-212Z/epic-planning/SKILL.md +0 -297
- package/.claude/skills.backup-2025-11-11T16-42-43-212Z/feature-planning/SKILL.md +0 -464
- package/.claude/skills.backup-2025-11-11T16-42-43-212Z/speed-mode/SKILL.md +0 -467
- package/.claude/skills.backup-2025-11-11T16-42-43-212Z/stable-mode/SKILL.md +0 -673
- package/.claude/skills.backup-2025-11-11T17-06-09-783Z/epic-planning/SKILL.md +0 -297
- package/.claude/skills.backup-2025-11-11T17-06-09-783Z/feature-planning/SKILL.md +0 -464
- package/.claude/skills.backup-2025-11-11T17-06-09-783Z/speed-mode/SKILL.md +0 -467
- package/.claude/skills.backup-2025-11-11T17-06-09-783Z/stable-mode/SKILL.md +0 -673
- package/.devpod/current-work.json +0 -10
- package/.devpod/work.db +0 -0
- package/.github/workflows/test-safety.yml +0 -85
- package/.jettypod/config.json +0 -5
- package/.jettypod/current-work.json +0 -10
- package/.jettypod/hooks/README.md +0 -77
- package/.jettypod/hooks/protect-claude-md.js +0 -338
- package/.jettypod/test-work.db +0 -0
- package/.jettypod/work.db +0 -0
- package/CLAUDE.md +0 -49
- package/SPEED-STABLE-AUDIT.md +0 -853
- package/SYSTEM-BEHAVIOR.md +0 -2199
- package/TEST_SAFETY_AUDIT.md +0 -314
- package/TEST_SAFETY_IMPLEMENTATION.md +0 -97
- package/cucumber-report.html +0 -45
- package/dist/devpod-linux +0 -0
- package/dist/devpod-macos +0 -0
- package/dist/devpod-win.exe +0 -0
- package/docs/features/jettypod-standards-explained.md +0 -543
- package/docs/features/standards-inventory.md +0 -257
- package/features/auto-generate-production-chores.feature +0 -13
- package/features/backlog-command.feature +0 -26
- package/features/backlog-filtering-production.feature +0 -10
- package/features/claude-md-protection/steps.js +0 -498
- package/features/decisions/index.js +0 -490
- package/features/decisions/index.test.js +0 -208
- package/features/fix-text-wrapping.feature +0 -42
- package/features/git-hooks/git-hooks.feature +0 -30
- package/features/git-hooks/index.js +0 -93
- package/features/git-hooks/index.test.js +0 -137
- package/features/git-hooks/post-commit +0 -56
- package/features/git-hooks/post-merge +0 -47
- package/features/git-hooks/pre-commit +0 -28
- package/features/git-hooks/simple-steps.js +0 -53
- package/features/git-hooks/simple-test.feature +0 -10
- package/features/git-hooks/steps.js +0 -196
- package/features/jettypod-update-command.feature +0 -46
- package/features/mode-prompts/index.js +0 -95
- package/features/mode-prompts/simple-steps.js +0 -44
- package/features/mode-prompts/simple-test.feature +0 -9
- package/features/mode-prompts/validation.test.js +0 -120
- package/features/multiple-claude-instances.feature +0 -121
- package/features/production-mode-skill.feature +0 -121
- package/features/refactor-mode/steps.js +0 -217
- package/features/refactor-mode.feature +0 -49
- package/features/simplify-external-transition.feature +0 -166
- package/features/skills-update/index.test.js +0 -216
- package/features/step_definitions/backlog-command.steps.js +0 -37
- package/features/step_definitions/fix-text-wrapping.steps.js +0 -271
- package/features/step_definitions/multiple-claude-instances.steps.js +0 -621
- package/features/step_definitions/production-mode-skill.steps.js +0 -862
- package/features/step_definitions/simplify-external-transition.steps.js +0 -370
- package/features/step_definitions/terminal-logo.steps.js +0 -145
- package/features/step_definitions/update-command.steps.js +0 -183
- package/features/support/hooks.js +0 -9
- package/features/terminal-logo/index.js +0 -39
- package/features/terminal-logo/terminal-logo.feature +0 -30
- package/features/update-command/index.js +0 -181
- package/features/update-command/index.test.js +0 -225
- package/features/work-commands/bug-workflow-display.feature +0 -22
- package/features/work-commands/index.js +0 -498
- package/features/work-commands/simple-steps.js +0 -69
- package/features/work-commands/stable-tests.feature +0 -57
- package/features/work-commands/steps.js +0 -1174
- package/features/work-commands/validation.test.js +0 -88
- package/features/work-commands/work-commands.feature +0 -13
- package/features/work-tracking/discovery-validation.test.js +0 -228
- package/features/work-tracking/index.js +0 -1921
- package/features/work-tracking/mode-required.feature +0 -112
- package/features/work-tracking/phase-tracking.test.js +0 -482
- package/features/work-tracking/prototype-tracking.test.js +0 -485
- package/features/work-tracking/tree-view.test.js +0 -310
- package/features/work-tracking/work-set-mode.feature +0 -71
- package/features/work-tracking/work-start-mode.feature +0 -88
- package/full-test.txt +0 -0
- package/lib/bug-workflow.test.js +0 -177
- package/lib/claudemd.test.js +0 -195
- package/lib/config.test.js +0 -511
- package/lib/constants.test.js +0 -164
- package/lib/current-work.test.js +0 -146
- package/lib/database-project-config.test.js +0 -111
- package/lib/database.test.js +0 -106
- package/lib/decisions-generator.test.js +0 -457
- package/lib/decisions-helpers.test.js +0 -310
- package/lib/git-coordinator.js +0 -167
- package/lib/git.test.js +0 -145
- package/lib/migrations/002-default-work-item-modes.test.js +0 -351
- package/lib/production-chore-generator.test.js +0 -432
- package/lib/production-context-detector.test.js +0 -277
- package/lib/production-scenario-appender.test.js +0 -235
- package/lib/production-scenario-validator.test.js +0 -246
- package/lib/production-standards-reader.test.js +0 -270
- package/lib/project-state.test.js +0 -92
- package/lib/push-queue.js +0 -417
- package/lib/queue-processor.js +0 -74
- package/lib/test-helpers.js +0 -202
- package/lib/test-helpers.test.js +0 -255
- package/prototypes/2025-01-11-production-mode-autonomous.js +0 -119
- package/prototypes/2025-01-11-production-mode-collaborative.js +0 -166
- package/prototypes/2025-01-11-production-mode-guided.js +0 -217
- package/prototypes/2025-01-11-production-mode-smart-context.js +0 -347
- package/prototypes/2025-01-11-production-standards-example.md +0 -204
- package/prototypes/2025-11-10-backlog-filtering-tree-aware.js +0 -242
- package/prototypes/test/index.html +0 -1
- package/setup-dist-repo.sh +0 -68
- package/test-production-standards-engine.js +0 -130
- package/test-results.json +0 -2195
- package/test-safety-check.sh +0 -80
- package/work-item-tracking-plan.md +0 -199
- /package/{.jettypod/devpod.db → jettypod.db} +0 -0
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
readStandards,
|
|
3
|
-
validateStandardsFormat,
|
|
4
|
-
getStandardsByDomain,
|
|
5
|
-
standardsFileExists,
|
|
6
|
-
getDomains
|
|
7
|
-
} = require('./production-standards-reader');
|
|
8
|
-
const fs = require('fs');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
|
|
11
|
-
describe('production-standards-reader', () => {
|
|
12
|
-
let testDir;
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
// Create test directory
|
|
16
|
-
testDir = path.join(__dirname, '../test-tmp', `standards-reader-${Date.now()}`);
|
|
17
|
-
fs.mkdirSync(testDir, { recursive: true });
|
|
18
|
-
fs.mkdirSync(path.join(testDir, '.jettypod'), { recursive: true });
|
|
19
|
-
process.chdir(testDir);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
if (testDir && fs.existsSync(testDir)) {
|
|
24
|
-
fs.rmSync(testDir, { recursive: true, force: true });
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
describe('standardsFileExists', () => {
|
|
29
|
-
test('returns false when file does not exist', () => {
|
|
30
|
-
expect(standardsFileExists()).toBe(false);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test('returns true when file exists', () => {
|
|
34
|
-
const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
|
|
35
|
-
fs.writeFileSync(standardsPath, '{}');
|
|
36
|
-
|
|
37
|
-
expect(standardsFileExists()).toBe(true);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
describe('readStandards', () => {
|
|
42
|
-
test('throws error when file does not exist', async () => {
|
|
43
|
-
await expect(readStandards()).rejects.toThrow('Production standards file not found');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test('throws error when file has invalid JSON', async () => {
|
|
47
|
-
const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
|
|
48
|
-
fs.writeFileSync(standardsPath, 'invalid json');
|
|
49
|
-
|
|
50
|
-
await expect(readStandards()).rejects.toThrow('Failed to read production standards');
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test('reads and returns valid standards', async () => {
|
|
54
|
-
const standards = {
|
|
55
|
-
preset: 'production-saas',
|
|
56
|
-
refinement: {
|
|
57
|
-
app_description: 'Test app'
|
|
58
|
-
},
|
|
59
|
-
standards: [
|
|
60
|
-
{
|
|
61
|
-
id: 'tls_enforced',
|
|
62
|
-
domain: 'security',
|
|
63
|
-
acceptance: 'HSTS ≥ 6mo; TLS ≥1.2'
|
|
64
|
-
}
|
|
65
|
-
]
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
|
|
69
|
-
fs.writeFileSync(standardsPath, JSON.stringify(standards, null, 2));
|
|
70
|
-
|
|
71
|
-
const result = await readStandards();
|
|
72
|
-
|
|
73
|
-
expect(result).toEqual(standards);
|
|
74
|
-
expect(result.preset).toBe('production-saas');
|
|
75
|
-
expect(result.standards).toHaveLength(1);
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
describe('validateStandardsFormat', () => {
|
|
80
|
-
test('throws error when standards is null', () => {
|
|
81
|
-
expect(() => validateStandardsFormat(null)).toThrow('Standards object is null or undefined');
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test('throws error when missing preset field', () => {
|
|
85
|
-
const standards = {
|
|
86
|
-
standards: []
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
expect(() => validateStandardsFormat(standards)).toThrow('Standards missing required field: preset');
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test('throws error when missing standards array', () => {
|
|
93
|
-
const standards = {
|
|
94
|
-
preset: 'production-saas'
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
expect(() => validateStandardsFormat(standards)).toThrow('Standards missing required field: standards (array)');
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
test('throws error when standards is not an array', () => {
|
|
101
|
-
const standards = {
|
|
102
|
-
preset: 'production-saas',
|
|
103
|
-
standards: 'not an array'
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
expect(() => validateStandardsFormat(standards)).toThrow('Standards missing required field: standards (array)');
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
test('throws error when standard missing id', () => {
|
|
110
|
-
const standards = {
|
|
111
|
-
preset: 'production-saas',
|
|
112
|
-
standards: [
|
|
113
|
-
{
|
|
114
|
-
domain: 'security',
|
|
115
|
-
acceptance: 'test'
|
|
116
|
-
}
|
|
117
|
-
]
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
expect(() => validateStandardsFormat(standards)).toThrow('Standard missing required field: id');
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test('throws error when standard missing domain', () => {
|
|
124
|
-
const standards = {
|
|
125
|
-
preset: 'production-saas',
|
|
126
|
-
standards: [
|
|
127
|
-
{
|
|
128
|
-
id: 'test_standard',
|
|
129
|
-
acceptance: 'test'
|
|
130
|
-
}
|
|
131
|
-
]
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
expect(() => validateStandardsFormat(standards)).toThrow('Standard test_standard missing required field: domain');
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
test('throws error when standard missing acceptance', () => {
|
|
138
|
-
const standards = {
|
|
139
|
-
preset: 'production-saas',
|
|
140
|
-
standards: [
|
|
141
|
-
{
|
|
142
|
-
id: 'test_standard',
|
|
143
|
-
domain: 'security'
|
|
144
|
-
}
|
|
145
|
-
]
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
expect(() => validateStandardsFormat(standards)).toThrow('Standard test_standard missing required field: acceptance');
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
test('validates correct format successfully', () => {
|
|
152
|
-
const standards = {
|
|
153
|
-
preset: 'production-saas',
|
|
154
|
-
standards: [
|
|
155
|
-
{
|
|
156
|
-
id: 'test_standard',
|
|
157
|
-
domain: 'security',
|
|
158
|
-
acceptance: 'test criteria'
|
|
159
|
-
}
|
|
160
|
-
]
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
expect(() => validateStandardsFormat(standards)).not.toThrow();
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
describe('getStandardsByDomain', () => {
|
|
168
|
-
test('returns empty array when no standards match domain', async () => {
|
|
169
|
-
const standards = {
|
|
170
|
-
preset: 'production-saas',
|
|
171
|
-
standards: [
|
|
172
|
-
{
|
|
173
|
-
id: 'test1',
|
|
174
|
-
domain: 'security',
|
|
175
|
-
acceptance: 'test'
|
|
176
|
-
}
|
|
177
|
-
]
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
|
|
181
|
-
fs.writeFileSync(standardsPath, JSON.stringify(standards, null, 2));
|
|
182
|
-
|
|
183
|
-
const result = await getStandardsByDomain('performance');
|
|
184
|
-
expect(result).toEqual([]);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
test('returns standards for specified domain', async () => {
|
|
188
|
-
const standards = {
|
|
189
|
-
preset: 'production-saas',
|
|
190
|
-
standards: [
|
|
191
|
-
{
|
|
192
|
-
id: 'test1',
|
|
193
|
-
domain: 'security',
|
|
194
|
-
acceptance: 'test'
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
id: 'test2',
|
|
198
|
-
domain: 'performance',
|
|
199
|
-
acceptance: 'test'
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
id: 'test3',
|
|
203
|
-
domain: 'security',
|
|
204
|
-
acceptance: 'test2'
|
|
205
|
-
}
|
|
206
|
-
]
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
|
|
210
|
-
fs.writeFileSync(standardsPath, JSON.stringify(standards, null, 2));
|
|
211
|
-
|
|
212
|
-
const result = await getStandardsByDomain('security');
|
|
213
|
-
expect(result).toHaveLength(2);
|
|
214
|
-
expect(result[0].id).toBe('test1');
|
|
215
|
-
expect(result[1].id).toBe('test3');
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
describe('getDomains', () => {
|
|
220
|
-
test('returns empty array when no standards exist', async () => {
|
|
221
|
-
const standards = {
|
|
222
|
-
preset: 'production-saas',
|
|
223
|
-
standards: []
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
|
|
227
|
-
fs.writeFileSync(standardsPath, JSON.stringify(standards, null, 2));
|
|
228
|
-
|
|
229
|
-
const result = await getDomains();
|
|
230
|
-
expect(result).toEqual([]);
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
test('returns unique domain names', async () => {
|
|
234
|
-
const standards = {
|
|
235
|
-
preset: 'production-saas',
|
|
236
|
-
standards: [
|
|
237
|
-
{
|
|
238
|
-
id: 'test1',
|
|
239
|
-
domain: 'security',
|
|
240
|
-
acceptance: 'test'
|
|
241
|
-
},
|
|
242
|
-
{
|
|
243
|
-
id: 'test2',
|
|
244
|
-
domain: 'performance',
|
|
245
|
-
acceptance: 'test'
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
id: 'test3',
|
|
249
|
-
domain: 'security',
|
|
250
|
-
acceptance: 'test2'
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
id: 'test4',
|
|
254
|
-
domain: 'compliance',
|
|
255
|
-
acceptance: 'test'
|
|
256
|
-
}
|
|
257
|
-
]
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
|
|
261
|
-
fs.writeFileSync(standardsPath, JSON.stringify(standards, null, 2));
|
|
262
|
-
|
|
263
|
-
const result = await getDomains();
|
|
264
|
-
expect(result).toHaveLength(3);
|
|
265
|
-
expect(result).toContain('security');
|
|
266
|
-
expect(result).toContain('performance');
|
|
267
|
-
expect(result).toContain('compliance');
|
|
268
|
-
});
|
|
269
|
-
});
|
|
270
|
-
});
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
const config = require('./config');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
describe('Project State', () => {
|
|
6
|
-
const testDir = path.join('/tmp', 'jettypod-project-state-test-' + Date.now());
|
|
7
|
-
const testConfigPath = path.join(testDir, 'config.json');
|
|
8
|
-
const originalPath = config.path;
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
config.path = testConfigPath;
|
|
12
|
-
// SAFETY: Only delete if testDir is in /tmp
|
|
13
|
-
if (fs.existsSync(testDir) && testDir.startsWith('/tmp/')) {
|
|
14
|
-
fs.rmSync(testDir, { recursive: true });
|
|
15
|
-
}
|
|
16
|
-
fs.mkdirSync(testDir, { recursive: true });
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
afterEach(() => {
|
|
20
|
-
config.path = originalPath;
|
|
21
|
-
// SAFETY: Only delete if testDir is in /tmp
|
|
22
|
-
if (fs.existsSync(testDir) && testDir.startsWith('/tmp/')) {
|
|
23
|
-
fs.rmSync(testDir, { recursive: true });
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe('isValidProjectState', () => {
|
|
28
|
-
it('should accept "internal" as valid', () => {
|
|
29
|
-
expect(config.isValidProjectState('internal')).toBe(true);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('should accept "external" as valid', () => {
|
|
33
|
-
expect(config.isValidProjectState('external')).toBe(true);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should reject invalid values', () => {
|
|
37
|
-
expect(config.isValidProjectState('production')).toBe(false);
|
|
38
|
-
expect(config.isValidProjectState('invalid')).toBe(false);
|
|
39
|
-
expect(config.isValidProjectState('')).toBe(false);
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
describe('read', () => {
|
|
44
|
-
it('should default project_state to "external" if not exists', () => {
|
|
45
|
-
const data = config.read();
|
|
46
|
-
expect(data.project_state).toBe('external');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('should default project_state to "external" if invalid value in file', () => {
|
|
50
|
-
fs.mkdirSync(testDir, { recursive: true });
|
|
51
|
-
fs.writeFileSync(testConfigPath, JSON.stringify({ name: 'test', project_state: 'invalid' }));
|
|
52
|
-
|
|
53
|
-
const data = config.read();
|
|
54
|
-
expect(data.project_state).toBe('external');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should preserve valid project_state from file', () => {
|
|
58
|
-
fs.mkdirSync(testDir, { recursive: true });
|
|
59
|
-
fs.writeFileSync(testConfigPath, JSON.stringify({ name: 'test', project_state: 'external' }));
|
|
60
|
-
|
|
61
|
-
const data = config.read();
|
|
62
|
-
expect(data.project_state).toBe('external');
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe('update', () => {
|
|
67
|
-
it('should update project_state to external', () => {
|
|
68
|
-
config.write({ name: 'test', project_state: 'internal' });
|
|
69
|
-
config.update({ project_state: 'external' });
|
|
70
|
-
|
|
71
|
-
const data = config.read();
|
|
72
|
-
expect(data.project_state).toBe('external');
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('should reject invalid project_state', () => {
|
|
76
|
-
config.write({ name: 'test', project_state: 'internal' });
|
|
77
|
-
|
|
78
|
-
expect(() => {
|
|
79
|
-
config.update({ project_state: 'invalid' });
|
|
80
|
-
}).toThrow('Invalid project_state: invalid');
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('should allow updating other fields without affecting project_state', () => {
|
|
84
|
-
config.write({ name: 'test', project_state: 'internal' });
|
|
85
|
-
config.update({ description: 'Test project' });
|
|
86
|
-
|
|
87
|
-
const data = config.read();
|
|
88
|
-
expect(data.project_state).toBe('internal');
|
|
89
|
-
expect(data.description).toBe('Test project');
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
});
|