Files
get-shit-done/tests/init.test.cjs
Lex Christopherson acb76fee16 test: add TBD guard coverage for phase_req_ids extraction
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 09:35:43 -06:00

206 lines
9.2 KiB
JavaScript

/**
* GSD Tools Tests - Init
*/
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('init commands', () => {
let tmpDir;
beforeEach(() => {
tmpDir = createTempProject();
});
afterEach(() => {
cleanup(tmpDir);
});
test('init execute-phase returns file paths', () => {
const phaseDir = path.join(tmpDir, '.planning', 'phases', '03-api');
fs.mkdirSync(phaseDir, { recursive: true });
fs.writeFileSync(path.join(phaseDir, '03-01-PLAN.md'), '# Plan');
const result = runGsdTools('init execute-phase 03', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.strictEqual(output.state_path, '.planning/STATE.md');
assert.strictEqual(output.roadmap_path, '.planning/ROADMAP.md');
assert.strictEqual(output.config_path, '.planning/config.json');
});
test('init plan-phase returns file paths', () => {
const phaseDir = path.join(tmpDir, '.planning', 'phases', '03-api');
fs.mkdirSync(phaseDir, { recursive: true });
fs.writeFileSync(path.join(phaseDir, '03-CONTEXT.md'), '# Phase Context');
fs.writeFileSync(path.join(phaseDir, '03-RESEARCH.md'), '# Research Findings');
fs.writeFileSync(path.join(phaseDir, '03-VERIFICATION.md'), '# Verification');
fs.writeFileSync(path.join(phaseDir, '03-UAT.md'), '# UAT');
const result = runGsdTools('init plan-phase 03', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.strictEqual(output.state_path, '.planning/STATE.md');
assert.strictEqual(output.roadmap_path, '.planning/ROADMAP.md');
assert.strictEqual(output.requirements_path, '.planning/REQUIREMENTS.md');
assert.strictEqual(output.context_path, '.planning/phases/03-api/03-CONTEXT.md');
assert.strictEqual(output.research_path, '.planning/phases/03-api/03-RESEARCH.md');
assert.strictEqual(output.verification_path, '.planning/phases/03-api/03-VERIFICATION.md');
assert.strictEqual(output.uat_path, '.planning/phases/03-api/03-UAT.md');
});
test('init progress returns file paths', () => {
const result = runGsdTools('init progress', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.strictEqual(output.state_path, '.planning/STATE.md');
assert.strictEqual(output.roadmap_path, '.planning/ROADMAP.md');
assert.strictEqual(output.project_path, '.planning/PROJECT.md');
assert.strictEqual(output.config_path, '.planning/config.json');
});
test('init phase-op returns core and optional phase file paths', () => {
const phaseDir = path.join(tmpDir, '.planning', 'phases', '03-api');
fs.mkdirSync(phaseDir, { recursive: true });
fs.writeFileSync(path.join(phaseDir, '03-CONTEXT.md'), '# Phase Context');
fs.writeFileSync(path.join(phaseDir, '03-RESEARCH.md'), '# Research');
fs.writeFileSync(path.join(phaseDir, '03-VERIFICATION.md'), '# Verification');
fs.writeFileSync(path.join(phaseDir, '03-UAT.md'), '# UAT');
const result = runGsdTools('init phase-op 03', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.strictEqual(output.state_path, '.planning/STATE.md');
assert.strictEqual(output.roadmap_path, '.planning/ROADMAP.md');
assert.strictEqual(output.requirements_path, '.planning/REQUIREMENTS.md');
assert.strictEqual(output.context_path, '.planning/phases/03-api/03-CONTEXT.md');
assert.strictEqual(output.research_path, '.planning/phases/03-api/03-RESEARCH.md');
assert.strictEqual(output.verification_path, '.planning/phases/03-api/03-VERIFICATION.md');
assert.strictEqual(output.uat_path, '.planning/phases/03-api/03-UAT.md');
});
test('init plan-phase omits optional paths if files missing', () => {
const phaseDir = path.join(tmpDir, '.planning', 'phases', '03-api');
fs.mkdirSync(phaseDir, { recursive: true });
const result = runGsdTools('init plan-phase 03', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.strictEqual(output.context_path, undefined);
assert.strictEqual(output.research_path, undefined);
});
// ── phase_req_ids extraction (fix for #684) ──────────────────────────────
test('init plan-phase extracts phase_req_ids from ROADMAP', () => {
fs.mkdirSync(path.join(tmpDir, '.planning', 'phases', '03-api'), { recursive: true });
fs.writeFileSync(
path.join(tmpDir, '.planning', 'ROADMAP.md'),
`# Roadmap\n\n### Phase 3: API\n**Goal:** Build API\n**Requirements**: CP-01, CP-02, CP-03\n**Plans:** 0 plans\n`
);
const result = runGsdTools('init plan-phase 3', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.strictEqual(output.phase_req_ids, 'CP-01, CP-02, CP-03');
});
test('init plan-phase strips brackets from phase_req_ids', () => {
fs.mkdirSync(path.join(tmpDir, '.planning', 'phases', '03-api'), { recursive: true });
fs.writeFileSync(
path.join(tmpDir, '.planning', 'ROADMAP.md'),
`# Roadmap\n\n### Phase 3: API\n**Goal:** Build API\n**Requirements**: [CP-01, CP-02]\n**Plans:** 0 plans\n`
);
const result = runGsdTools('init plan-phase 3', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.strictEqual(output.phase_req_ids, 'CP-01, CP-02');
});
test('init plan-phase returns null phase_req_ids when Requirements line is absent', () => {
fs.mkdirSync(path.join(tmpDir, '.planning', 'phases', '03-api'), { recursive: true });
fs.writeFileSync(
path.join(tmpDir, '.planning', 'ROADMAP.md'),
`# Roadmap\n\n### Phase 3: API\n**Goal:** Build API\n**Plans:** 0 plans\n`
);
const result = runGsdTools('init plan-phase 3', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.strictEqual(output.phase_req_ids, null);
});
test('init plan-phase returns null phase_req_ids when ROADMAP is absent', () => {
fs.mkdirSync(path.join(tmpDir, '.planning', 'phases', '03-api'), { recursive: true });
const result = runGsdTools('init plan-phase 3', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.strictEqual(output.phase_req_ids, null);
});
test('init execute-phase extracts phase_req_ids from ROADMAP', () => {
const phaseDir = path.join(tmpDir, '.planning', 'phases', '03-api');
fs.mkdirSync(phaseDir, { recursive: true });
fs.writeFileSync(path.join(phaseDir, '03-01-PLAN.md'), '# Plan');
fs.writeFileSync(
path.join(tmpDir, '.planning', 'ROADMAP.md'),
`# Roadmap\n\n### Phase 3: API\n**Goal:** Build API\n**Requirements**: EX-01, EX-02\n**Plans:** 1 plans\n`
);
const result = runGsdTools('init execute-phase 3', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.strictEqual(output.phase_req_ids, 'EX-01, EX-02');
});
test('init plan-phase returns null phase_req_ids when value is TBD', () => {
fs.mkdirSync(path.join(tmpDir, '.planning', 'phases', '03-api'), { recursive: true });
fs.writeFileSync(
path.join(tmpDir, '.planning', 'ROADMAP.md'),
`# Roadmap\n\n### Phase 3: API\n**Goal:** Build API\n**Requirements**: TBD\n**Plans:** 0 plans\n`
);
const result = runGsdTools('init plan-phase 3', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.strictEqual(output.phase_req_ids, null, 'TBD placeholder should return null');
});
test('init execute-phase returns null phase_req_ids when Requirements line is absent', () => {
const phaseDir = path.join(tmpDir, '.planning', 'phases', '03-api');
fs.mkdirSync(phaseDir, { recursive: true });
fs.writeFileSync(path.join(phaseDir, '03-01-PLAN.md'), '# Plan');
fs.writeFileSync(
path.join(tmpDir, '.planning', 'ROADMAP.md'),
`# Roadmap\n\n### Phase 3: API\n**Goal:** Build API\n**Plans:** 1 plans\n`
);
const result = runGsdTools('init execute-phase 3', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.strictEqual(output.phase_req_ids, null);
});
});
// ─────────────────────────────────────────────────────────────────────────────
// roadmap analyze command
// ─────────────────────────────────────────────────────────────────────────────