Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD across contents and paths, upstream package/repo coordinates -> @golem15/msd-core and golem15com/msd-core. Deep links into upstream history, sibling upstream packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is. Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line, package/plugin identity, regenerated lockfile, install-tree fixtures, derived registries and benchmark baseline; migration checksum baseline re-locked (MSD keeps its own install state, so no install had applied the old sums); sort-order and regex-escaped expectations in tests adjusted.
78 lines
2.9 KiB
JavaScript
78 lines
2.9 KiB
JavaScript
/**
|
|
* Roadmap parser — `**Mode:**` field extraction
|
|
* Covers PRD: vertical-mvp-slice Phase 1 (Q1: all-or-nothing per phase).
|
|
*/
|
|
const { test, describe, beforeEach, afterEach } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { runMsdTools, createTempProject, cleanup } = require('./helpers.cjs');
|
|
|
|
const ROADMAP_WITH_MODE = `# Roadmap
|
|
|
|
## v1.0.0
|
|
|
|
### Phase 1: User Auth MVP
|
|
**Goal:** A user can register and log in
|
|
**Mode:** mvp
|
|
**Success Criteria**:
|
|
1. Registration works
|
|
2. Login works
|
|
|
|
### Phase 2: Bulk Import
|
|
**Goal:** Admin can upload CSV
|
|
**Success Criteria**:
|
|
1. CSV parses
|
|
`;
|
|
|
|
describe('roadmap parser — mode field', () => {
|
|
let tmpDir;
|
|
beforeEach(() => { tmpDir = createTempProject(); });
|
|
afterEach(() => { cleanup(tmpDir); });
|
|
|
|
test('roadmap.get-phase returns mode="mvp" when **Mode:** mvp present', () => {
|
|
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), ROADMAP_WITH_MODE);
|
|
const result = runMsdTools('roadmap get-phase 1', tmpDir);
|
|
assert.ok(result.success, `Command failed: ${result.error}`);
|
|
const out = JSON.parse(result.output);
|
|
assert.strictEqual(out.found, true);
|
|
assert.strictEqual(out.mode, 'mvp');
|
|
});
|
|
|
|
test('roadmap.get-phase returns mode=null when **Mode:** absent', () => {
|
|
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), ROADMAP_WITH_MODE);
|
|
const result = runMsdTools('roadmap get-phase 2', tmpDir);
|
|
assert.ok(result.success, `Command failed: ${result.error}`);
|
|
const out = JSON.parse(result.output);
|
|
assert.strictEqual(out.found, true);
|
|
assert.strictEqual(out.mode, null);
|
|
});
|
|
|
|
test('roadmap.analyze surfaces mode per phase', () => {
|
|
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), ROADMAP_WITH_MODE);
|
|
const result = runMsdTools('roadmap analyze', tmpDir);
|
|
assert.ok(result.success, `Command failed: ${result.error}`);
|
|
const out = JSON.parse(result.output);
|
|
const p1 = out.phases.find(p => p.number === '1');
|
|
const p2 = out.phases.find(p => p.number === '2');
|
|
assert.strictEqual(p1.mode, 'mvp');
|
|
assert.strictEqual(p2.mode, null);
|
|
});
|
|
|
|
test('mode field is case-insensitive and trimmed', () => {
|
|
const variant = ROADMAP_WITH_MODE.replace('**Mode:** mvp', '**mode**: MVP ');
|
|
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), variant);
|
|
const result = runMsdTools('roadmap get-phase 1', tmpDir);
|
|
const out = JSON.parse(result.output);
|
|
assert.strictEqual(out.mode, 'mvp');
|
|
});
|
|
|
|
test('unrecognized mode value is preserved verbatim (forward-compat)', () => {
|
|
const variant = ROADMAP_WITH_MODE.replace('**Mode:** mvp', '**Mode:** experimental');
|
|
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), variant);
|
|
const result = runMsdTools('roadmap get-phase 1', tmpDir);
|
|
const out = JSON.parse(result.output);
|
|
assert.strictEqual(out.mode, 'experimental');
|
|
});
|
|
});
|