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,351 +0,0 @@
|
|
|
1
|
-
const sqlite3 = require('sqlite3').verbose();
|
|
2
|
-
const migration = require('./002-default-work-item-modes');
|
|
3
|
-
|
|
4
|
-
describe('Migration: 002-default-work-item-modes', () => {
|
|
5
|
-
let db;
|
|
6
|
-
|
|
7
|
-
beforeEach((done) => {
|
|
8
|
-
// Create in-memory database for each test
|
|
9
|
-
db = new sqlite3.Database(':memory:', (err) => {
|
|
10
|
-
if (err) return done(err);
|
|
11
|
-
|
|
12
|
-
// Create work_items table with schema
|
|
13
|
-
db.run(`
|
|
14
|
-
CREATE TABLE work_items (
|
|
15
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
16
|
-
type TEXT NOT NULL,
|
|
17
|
-
title TEXT NOT NULL,
|
|
18
|
-
description TEXT,
|
|
19
|
-
status TEXT DEFAULT 'backlog',
|
|
20
|
-
parent_id INTEGER,
|
|
21
|
-
epic_id INTEGER,
|
|
22
|
-
branch_name TEXT,
|
|
23
|
-
file_paths TEXT,
|
|
24
|
-
commit_sha TEXT,
|
|
25
|
-
mode TEXT,
|
|
26
|
-
current INTEGER DEFAULT 0,
|
|
27
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
28
|
-
)
|
|
29
|
-
`, done);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
afterEach((done) => {
|
|
34
|
-
db.close(done);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
describe('metadata', () => {
|
|
38
|
-
it('has correct migration id', () => {
|
|
39
|
-
expect(migration.id).toBe('002-default-work-item-modes');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('has description', () => {
|
|
43
|
-
expect(migration.description).toBeDefined();
|
|
44
|
-
expect(typeof migration.description).toBe('string');
|
|
45
|
-
expect(migration.description.length).toBeGreaterThan(0);
|
|
46
|
-
expect(migration.description).toContain('epics');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('has up function', () => {
|
|
50
|
-
expect(typeof migration.up).toBe('function');
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
describe('up()', () => {
|
|
55
|
-
it('sets mode to stable for features/bugs/chores with NULL mode', async () => {
|
|
56
|
-
// Insert work items without mode
|
|
57
|
-
await new Promise((resolve, reject) => {
|
|
58
|
-
db.run(
|
|
59
|
-
`INSERT INTO work_items (type, title, mode) VALUES
|
|
60
|
-
('feature', 'Test Feature', NULL),
|
|
61
|
-
('bug', 'Test Bug', NULL),
|
|
62
|
-
('chore', 'Test Chore', NULL)`,
|
|
63
|
-
(err) => err ? reject(err) : resolve()
|
|
64
|
-
);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
// Run migration
|
|
68
|
-
await migration.up(db);
|
|
69
|
-
|
|
70
|
-
// Verify all items have mode set
|
|
71
|
-
const items = await new Promise((resolve, reject) => {
|
|
72
|
-
db.all('SELECT id, type, title, mode FROM work_items ORDER BY id', [], (err, rows) => {
|
|
73
|
-
err ? reject(err) : resolve(rows);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
expect(items).toHaveLength(3);
|
|
78
|
-
expect(items[0].mode).toBe('stable');
|
|
79
|
-
expect(items[1].mode).toBe('stable');
|
|
80
|
-
expect(items[2].mode).toBe('stable');
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('sets epic modes to NULL', async () => {
|
|
84
|
-
// Insert epics with and without modes
|
|
85
|
-
await new Promise((resolve, reject) => {
|
|
86
|
-
db.run(
|
|
87
|
-
`INSERT INTO work_items (type, title, mode) VALUES
|
|
88
|
-
('epic', 'Epic with mode', 'speed'),
|
|
89
|
-
('epic', 'Epic without mode', NULL)`,
|
|
90
|
-
(err) => err ? reject(err) : resolve()
|
|
91
|
-
);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// Run migration
|
|
95
|
-
await migration.up(db);
|
|
96
|
-
|
|
97
|
-
// Verify all epics have NULL mode
|
|
98
|
-
const items = await new Promise((resolve, reject) => {
|
|
99
|
-
db.all('SELECT id, title, mode FROM work_items WHERE type = "epic"', [], (err, rows) => {
|
|
100
|
-
err ? reject(err) : resolve(rows);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
expect(items).toHaveLength(2);
|
|
105
|
-
expect(items[0].mode).toBe(null);
|
|
106
|
-
expect(items[1].mode).toBe(null);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('does not change existing mode values for non-epics', async () => {
|
|
110
|
-
// Insert work items with various modes
|
|
111
|
-
await new Promise((resolve, reject) => {
|
|
112
|
-
db.run(
|
|
113
|
-
`INSERT INTO work_items (type, title, mode) VALUES
|
|
114
|
-
('feature', 'Speed Feature', 'speed'),
|
|
115
|
-
('bug', 'Discovery Bug', 'discovery'),
|
|
116
|
-
('chore', 'Production Chore', 'production'),
|
|
117
|
-
('feature', 'Stable Feature', 'stable')`,
|
|
118
|
-
(err) => err ? reject(err) : resolve()
|
|
119
|
-
);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
// Run migration
|
|
123
|
-
await migration.up(db);
|
|
124
|
-
|
|
125
|
-
// Verify modes unchanged
|
|
126
|
-
const items = await new Promise((resolve, reject) => {
|
|
127
|
-
db.all('SELECT id, type, title, mode FROM work_items ORDER BY id', [], (err, rows) => {
|
|
128
|
-
err ? reject(err) : resolve(rows);
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
expect(items).toHaveLength(4);
|
|
133
|
-
expect(items[0].mode).toBe('speed');
|
|
134
|
-
expect(items[1].mode).toBe('discovery');
|
|
135
|
-
expect(items[2].mode).toBe('production');
|
|
136
|
-
expect(items[3].mode).toBe('stable');
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('handles mixed NULL and non-NULL modes', async () => {
|
|
140
|
-
// Insert mix of items
|
|
141
|
-
await new Promise((resolve, reject) => {
|
|
142
|
-
db.run(
|
|
143
|
-
`INSERT INTO work_items (type, title, mode) VALUES
|
|
144
|
-
('feature', 'Has Speed', 'speed'),
|
|
145
|
-
('feature', 'No Mode', NULL),
|
|
146
|
-
('feature', 'Has Discovery', 'discovery'),
|
|
147
|
-
('feature', 'Also No Mode', NULL)`,
|
|
148
|
-
(err) => err ? reject(err) : resolve()
|
|
149
|
-
);
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// Run migration
|
|
153
|
-
await migration.up(db);
|
|
154
|
-
|
|
155
|
-
// Verify selective update
|
|
156
|
-
const items = await new Promise((resolve, reject) => {
|
|
157
|
-
db.all('SELECT id, title, mode FROM work_items ORDER BY id', [], (err, rows) => {
|
|
158
|
-
err ? reject(err) : resolve(rows);
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
expect(items).toHaveLength(4);
|
|
163
|
-
expect(items[0].mode).toBe('speed'); // Unchanged
|
|
164
|
-
expect(items[1].mode).toBe('stable'); // Changed from NULL
|
|
165
|
-
expect(items[2].mode).toBe('discovery'); // Unchanged
|
|
166
|
-
expect(items[3].mode).toBe('stable'); // Changed from NULL
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('is idempotent - can run multiple times safely', async () => {
|
|
170
|
-
// Insert items without mode
|
|
171
|
-
await new Promise((resolve, reject) => {
|
|
172
|
-
db.run(
|
|
173
|
-
`INSERT INTO work_items (type, title, mode) VALUES
|
|
174
|
-
('feature', 'Test', NULL)`,
|
|
175
|
-
(err) => err ? reject(err) : resolve()
|
|
176
|
-
);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
// Run migration first time
|
|
180
|
-
await migration.up(db);
|
|
181
|
-
|
|
182
|
-
const firstRun = await new Promise((resolve, reject) => {
|
|
183
|
-
db.all('SELECT mode FROM work_items', [], (err, rows) => {
|
|
184
|
-
err ? reject(err) : resolve(rows);
|
|
185
|
-
});
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
expect(firstRun[0].mode).toBe('stable');
|
|
189
|
-
|
|
190
|
-
// Run migration second time
|
|
191
|
-
await migration.up(db);
|
|
192
|
-
|
|
193
|
-
const secondRun = await new Promise((resolve, reject) => {
|
|
194
|
-
db.all('SELECT mode FROM work_items', [], (err, rows) => {
|
|
195
|
-
err ? reject(err) : resolve(rows);
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
expect(secondRun[0].mode).toBe('stable');
|
|
200
|
-
expect(firstRun).toEqual(secondRun);
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it('handles empty work_items table', async () => {
|
|
204
|
-
// Don't insert any items
|
|
205
|
-
|
|
206
|
-
// Run migration - should not fail
|
|
207
|
-
await expect(migration.up(db)).resolves.not.toThrow();
|
|
208
|
-
|
|
209
|
-
// Verify table still empty
|
|
210
|
-
const items = await new Promise((resolve, reject) => {
|
|
211
|
-
db.all('SELECT * FROM work_items', [], (err, rows) => {
|
|
212
|
-
err ? reject(err) : resolve(rows);
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
expect(items).toHaveLength(0);
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
it('handles all item types (epic, feature, bug, chore) correctly', async () => {
|
|
220
|
-
// Insert one of each type without mode
|
|
221
|
-
await new Promise((resolve, reject) => {
|
|
222
|
-
db.run(
|
|
223
|
-
`INSERT INTO work_items (type, title, mode) VALUES
|
|
224
|
-
('epic', 'Test Epic', NULL),
|
|
225
|
-
('feature', 'Test Feature', NULL),
|
|
226
|
-
('bug', 'Test Bug', NULL),
|
|
227
|
-
('chore', 'Test Chore', NULL)`,
|
|
228
|
-
(err) => err ? reject(err) : resolve()
|
|
229
|
-
);
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
// Run migration
|
|
233
|
-
await migration.up(db);
|
|
234
|
-
|
|
235
|
-
// Verify correct modes
|
|
236
|
-
const items = await new Promise((resolve, reject) => {
|
|
237
|
-
db.all('SELECT type, mode FROM work_items ORDER BY id', [], (err, rows) => {
|
|
238
|
-
err ? reject(err) : resolve(rows);
|
|
239
|
-
});
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
expect(items).toHaveLength(4);
|
|
243
|
-
expect(items[0].mode).toBe(null); // epic
|
|
244
|
-
expect(items[1].mode).toBe('stable'); // feature
|
|
245
|
-
expect(items[2].mode).toBe('stable'); // bug
|
|
246
|
-
expect(items[3].mode).toBe('stable'); // chore
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
it('preserves other column values during update', async () => {
|
|
250
|
-
// Insert item with various fields populated
|
|
251
|
-
await new Promise((resolve, reject) => {
|
|
252
|
-
db.run(
|
|
253
|
-
`INSERT INTO work_items
|
|
254
|
-
(type, title, description, status, parent_id, branch_name, current, mode)
|
|
255
|
-
VALUES
|
|
256
|
-
('feature', 'Rich Item', 'A detailed description', 'in_progress', 5, 'feature/test', 1, NULL)`,
|
|
257
|
-
(err) => err ? reject(err) : resolve()
|
|
258
|
-
);
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
// Run migration
|
|
262
|
-
await migration.up(db);
|
|
263
|
-
|
|
264
|
-
// Verify only mode changed
|
|
265
|
-
const item = await new Promise((resolve, reject) => {
|
|
266
|
-
db.get('SELECT * FROM work_items WHERE id = 1', [], (err, row) => {
|
|
267
|
-
err ? reject(err) : resolve(row);
|
|
268
|
-
});
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
expect(item.type).toBe('feature');
|
|
272
|
-
expect(item.title).toBe('Rich Item');
|
|
273
|
-
expect(item.description).toBe('A detailed description');
|
|
274
|
-
expect(item.status).toBe('in_progress');
|
|
275
|
-
expect(item.parent_id).toBe(5);
|
|
276
|
-
expect(item.branch_name).toBe('feature/test');
|
|
277
|
-
expect(item.current).toBe(1);
|
|
278
|
-
expect(item.mode).toBe('stable'); // Only this changed
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
it('returns a Promise', () => {
|
|
282
|
-
const result = migration.up(db);
|
|
283
|
-
expect(result).toBeInstanceOf(Promise);
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
it('resolves Promise on success', async () => {
|
|
287
|
-
await new Promise((resolve, reject) => {
|
|
288
|
-
db.run(
|
|
289
|
-
`INSERT INTO work_items (type, title, mode) VALUES ('feature', 'Test', NULL)`,
|
|
290
|
-
(err) => err ? reject(err) : resolve()
|
|
291
|
-
);
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
await expect(migration.up(db)).resolves.toBeUndefined();
|
|
295
|
-
});
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
describe('edge cases', () => {
|
|
299
|
-
it('handles work items created at exactly the same time', async () => {
|
|
300
|
-
const timestamp = '2024-10-18 12:00:00';
|
|
301
|
-
|
|
302
|
-
await new Promise((resolve, reject) => {
|
|
303
|
-
db.run(
|
|
304
|
-
`INSERT INTO work_items (type, title, mode, created_at) VALUES
|
|
305
|
-
('feature', 'Item 1', NULL, ?),
|
|
306
|
-
('feature', 'Item 2', NULL, ?)`,
|
|
307
|
-
[timestamp, timestamp],
|
|
308
|
-
(err) => err ? reject(err) : resolve()
|
|
309
|
-
);
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
await migration.up(db);
|
|
313
|
-
|
|
314
|
-
const items = await new Promise((resolve, reject) => {
|
|
315
|
-
db.all('SELECT mode FROM work_items', [], (err, rows) => {
|
|
316
|
-
err ? reject(err) : resolve(rows);
|
|
317
|
-
});
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
expect(items).toHaveLength(2);
|
|
321
|
-
expect(items[0].mode).toBe('stable');
|
|
322
|
-
expect(items[1].mode).toBe('stable');
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
it('handles work items with parent_id hierarchy', async () => {
|
|
326
|
-
// Epic with children, none have mode
|
|
327
|
-
await new Promise((resolve, reject) => {
|
|
328
|
-
db.run(
|
|
329
|
-
`INSERT INTO work_items (id, type, title, parent_id, mode) VALUES
|
|
330
|
-
(1, 'epic', 'Epic', NULL, NULL),
|
|
331
|
-
(2, 'feature', 'Child 1', 1, NULL),
|
|
332
|
-
(3, 'bug', 'Child 2', 1, NULL)`,
|
|
333
|
-
(err) => err ? reject(err) : resolve()
|
|
334
|
-
);
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
await migration.up(db);
|
|
338
|
-
|
|
339
|
-
const items = await new Promise((resolve, reject) => {
|
|
340
|
-
db.all('SELECT id, type, title, mode FROM work_items ORDER BY id', [], (err, rows) => {
|
|
341
|
-
err ? reject(err) : resolve(rows);
|
|
342
|
-
});
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
expect(items).toHaveLength(3);
|
|
346
|
-
expect(items[0].mode).toBe(null); // Epic (container, no mode)
|
|
347
|
-
expect(items[1].mode).toBe('stable'); // Child feature
|
|
348
|
-
expect(items[2].mode).toBe('stable'); // Child bug
|
|
349
|
-
});
|
|
350
|
-
});
|
|
351
|
-
});
|