mirror of
https://github.com/glittercowboy/get-shit-done
synced 2026-04-26 01:35:29 +02:00
Move 81 tests (18 describe blocks) from single monolithic test file into 7 domain-specific test files under tests/ with shared helpers. Test parity verified: 81/81 pass before and after split. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
266 lines
8.7 KiB
JavaScript
266 lines
8.7 KiB
JavaScript
/**
|
|
* GSD Tools Tests - Roadmap
|
|
*/
|
|
|
|
const { test, describe, beforeEach, afterEach } = require('node:test');
|
|
const assert = require('node:assert');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
|
|
|
|
describe('roadmap get-phase command', () => {
|
|
let tmpDir;
|
|
|
|
beforeEach(() => {
|
|
tmpDir = createTempProject();
|
|
});
|
|
|
|
afterEach(() => {
|
|
cleanup(tmpDir);
|
|
});
|
|
|
|
test('extracts phase section from ROADMAP.md', () => {
|
|
fs.writeFileSync(
|
|
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
|
`# Roadmap v1.0
|
|
|
|
## Phases
|
|
|
|
### Phase 1: Foundation
|
|
**Goal:** Set up project infrastructure
|
|
**Plans:** 2 plans
|
|
|
|
Some description here.
|
|
|
|
### Phase 2: API
|
|
**Goal:** Build REST API
|
|
**Plans:** 3 plans
|
|
`
|
|
);
|
|
|
|
const result = runGsdTools('roadmap get-phase 1', tmpDir);
|
|
assert.ok(result.success, `Command failed: ${result.error}`);
|
|
|
|
const output = JSON.parse(result.output);
|
|
assert.strictEqual(output.found, true, 'phase should be found');
|
|
assert.strictEqual(output.phase_number, '1', 'phase number correct');
|
|
assert.strictEqual(output.phase_name, 'Foundation', 'phase name extracted');
|
|
assert.strictEqual(output.goal, 'Set up project infrastructure', 'goal extracted');
|
|
});
|
|
|
|
test('returns not found for missing phase', () => {
|
|
fs.writeFileSync(
|
|
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
|
`# Roadmap v1.0
|
|
|
|
### Phase 1: Foundation
|
|
**Goal:** Set up project
|
|
`
|
|
);
|
|
|
|
const result = runGsdTools('roadmap get-phase 5', tmpDir);
|
|
assert.ok(result.success, `Command failed: ${result.error}`);
|
|
|
|
const output = JSON.parse(result.output);
|
|
assert.strictEqual(output.found, false, 'phase should not be found');
|
|
});
|
|
|
|
test('handles decimal phase numbers', () => {
|
|
fs.writeFileSync(
|
|
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
|
`# Roadmap
|
|
|
|
### Phase 2: Main
|
|
**Goal:** Main work
|
|
|
|
### Phase 2.1: Hotfix
|
|
**Goal:** Emergency fix
|
|
`
|
|
);
|
|
|
|
const result = runGsdTools('roadmap get-phase 2.1', tmpDir);
|
|
assert.ok(result.success, `Command failed: ${result.error}`);
|
|
|
|
const output = JSON.parse(result.output);
|
|
assert.strictEqual(output.found, true, 'decimal phase should be found');
|
|
assert.strictEqual(output.phase_name, 'Hotfix', 'phase name correct');
|
|
assert.strictEqual(output.goal, 'Emergency fix', 'goal extracted');
|
|
});
|
|
|
|
test('extracts full section content', () => {
|
|
fs.writeFileSync(
|
|
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
|
`# Roadmap
|
|
|
|
### Phase 1: Setup
|
|
**Goal:** Initialize everything
|
|
|
|
This phase covers:
|
|
- Database setup
|
|
- Auth configuration
|
|
- CI/CD pipeline
|
|
|
|
### Phase 2: Build
|
|
**Goal:** Build features
|
|
`
|
|
);
|
|
|
|
const result = runGsdTools('roadmap get-phase 1', tmpDir);
|
|
assert.ok(result.success, `Command failed: ${result.error}`);
|
|
|
|
const output = JSON.parse(result.output);
|
|
assert.ok(output.section.includes('Database setup'), 'section includes description');
|
|
assert.ok(output.section.includes('CI/CD pipeline'), 'section includes all bullets');
|
|
assert.ok(!output.section.includes('Phase 2'), 'section does not include next phase');
|
|
});
|
|
|
|
test('handles missing ROADMAP.md gracefully', () => {
|
|
const result = runGsdTools('roadmap get-phase 1', tmpDir);
|
|
assert.ok(result.success, `Command failed: ${result.error}`);
|
|
|
|
const output = JSON.parse(result.output);
|
|
assert.strictEqual(output.found, false, 'should return not found');
|
|
assert.strictEqual(output.error, 'ROADMAP.md not found', 'should explain why');
|
|
});
|
|
|
|
test('accepts ## phase headers (two hashes)', () => {
|
|
fs.writeFileSync(
|
|
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
|
`# Roadmap v1.0
|
|
|
|
## Phase 1: Foundation
|
|
**Goal:** Set up project infrastructure
|
|
**Plans:** 2 plans
|
|
|
|
## Phase 2: API
|
|
**Goal:** Build REST API
|
|
`
|
|
);
|
|
|
|
const result = runGsdTools('roadmap get-phase 1', tmpDir);
|
|
assert.ok(result.success, `Command failed: ${result.error}`);
|
|
|
|
const output = JSON.parse(result.output);
|
|
assert.strictEqual(output.found, true, 'phase with ## header should be found');
|
|
assert.strictEqual(output.phase_name, 'Foundation', 'phase name extracted');
|
|
assert.strictEqual(output.goal, 'Set up project infrastructure', 'goal extracted');
|
|
});
|
|
|
|
test('detects malformed ROADMAP with summary list but no detail sections', () => {
|
|
fs.writeFileSync(
|
|
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
|
`# Roadmap v1.0
|
|
|
|
## Phases
|
|
|
|
- [ ] **Phase 1: Foundation** - Set up project
|
|
- [ ] **Phase 2: API** - Build REST API
|
|
`
|
|
);
|
|
|
|
const result = runGsdTools('roadmap get-phase 1', tmpDir);
|
|
assert.ok(result.success, `Command failed: ${result.error}`);
|
|
|
|
const output = JSON.parse(result.output);
|
|
assert.strictEqual(output.found, false, 'phase should not be found');
|
|
assert.strictEqual(output.error, 'malformed_roadmap', 'should identify malformed roadmap');
|
|
assert.ok(output.message.includes('missing'), 'should explain the issue');
|
|
});
|
|
});
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// phase next-decimal command
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
describe('roadmap analyze command', () => {
|
|
let tmpDir;
|
|
|
|
beforeEach(() => {
|
|
tmpDir = createTempProject();
|
|
});
|
|
|
|
afterEach(() => {
|
|
cleanup(tmpDir);
|
|
});
|
|
|
|
test('missing ROADMAP.md returns error', () => {
|
|
const result = runGsdTools('roadmap analyze', tmpDir);
|
|
assert.ok(result.success, `Command should succeed: ${result.error}`);
|
|
|
|
const output = JSON.parse(result.output);
|
|
assert.strictEqual(output.error, 'ROADMAP.md not found');
|
|
});
|
|
|
|
test('parses phases with goals and disk status', () => {
|
|
fs.writeFileSync(
|
|
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
|
`# Roadmap v1.0
|
|
|
|
### Phase 1: Foundation
|
|
**Goal:** Set up infrastructure
|
|
|
|
### Phase 2: Authentication
|
|
**Goal:** Add user auth
|
|
|
|
### Phase 3: Features
|
|
**Goal:** Build core features
|
|
`
|
|
);
|
|
|
|
// Create phase dirs with varying completion
|
|
const p1 = path.join(tmpDir, '.planning', 'phases', '01-foundation');
|
|
fs.mkdirSync(p1, { recursive: true });
|
|
fs.writeFileSync(path.join(p1, '01-01-PLAN.md'), '# Plan');
|
|
fs.writeFileSync(path.join(p1, '01-01-SUMMARY.md'), '# Summary');
|
|
|
|
const p2 = path.join(tmpDir, '.planning', 'phases', '02-authentication');
|
|
fs.mkdirSync(p2, { recursive: true });
|
|
fs.writeFileSync(path.join(p2, '02-01-PLAN.md'), '# Plan');
|
|
|
|
const result = runGsdTools('roadmap analyze', tmpDir);
|
|
assert.ok(result.success, `Command failed: ${result.error}`);
|
|
|
|
const output = JSON.parse(result.output);
|
|
assert.strictEqual(output.phase_count, 3, 'should find 3 phases');
|
|
assert.strictEqual(output.phases[0].disk_status, 'complete', 'phase 1 complete');
|
|
assert.strictEqual(output.phases[1].disk_status, 'planned', 'phase 2 planned');
|
|
assert.strictEqual(output.phases[2].disk_status, 'no_directory', 'phase 3 no directory');
|
|
assert.strictEqual(output.completed_phases, 1, '1 phase complete');
|
|
assert.strictEqual(output.total_plans, 2, '2 total plans');
|
|
assert.strictEqual(output.total_summaries, 1, '1 total summary');
|
|
assert.strictEqual(output.progress_percent, 50, '50% complete');
|
|
assert.strictEqual(output.current_phase, '2', 'current phase is 2');
|
|
});
|
|
|
|
test('extracts goals and dependencies', () => {
|
|
fs.writeFileSync(
|
|
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
|
`# Roadmap
|
|
|
|
### Phase 1: Setup
|
|
**Goal:** Initialize project
|
|
**Depends on:** Nothing
|
|
|
|
### Phase 2: Build
|
|
**Goal:** Build features
|
|
**Depends on:** Phase 1
|
|
`
|
|
);
|
|
|
|
const result = runGsdTools('roadmap analyze', tmpDir);
|
|
assert.ok(result.success, `Command failed: ${result.error}`);
|
|
|
|
const output = JSON.parse(result.output);
|
|
assert.strictEqual(output.phases[0].goal, 'Initialize project');
|
|
assert.strictEqual(output.phases[0].depends_on, 'Nothing');
|
|
assert.strictEqual(output.phases[1].goal, 'Build features');
|
|
assert.strictEqual(output.phases[1].depends_on, 'Phase 1');
|
|
});
|
|
});
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// phase add command
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|