test: harden mvp-mode behavioral coverage

This commit is contained in:
Tom Boucher
2026-05-15 20:17:57 -04:00
parent 5a8610e0c2
commit ceb7a948d8
2 changed files with 45 additions and 3 deletions

View File

@@ -226,7 +226,7 @@ function getRoadmapModeForPhase(cwd, phaseNum) {
const sectionStart = headerMatch.index;
const rest = content.slice(sectionStart);
const nextHeader = rest.slice(headerMatch[0].length).match(/\n#{2,4}\s+Phase\s+\d/i);
const nextHeader = rest.slice(headerMatch[0].length).match(/\n#{2,4}\s+Phase\s+\S/i);
const sectionEnd = nextHeader ? sectionStart + headerMatch[0].length + nextHeader.index : content.length;
const section = content.slice(sectionStart, sectionEnd);
const modeMatch = section.match(/\*\*Mode(?::\*\*|\*\*:)\s*([^\n]+)/i);

View File

@@ -10,6 +10,7 @@
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const crypto = require('node:crypto');
const fs = require('node:fs');
const os = require('node:os');
const path = require('path');
@@ -141,6 +142,8 @@ function runGsdTools(args, projectDir) {
return spawnSync(process.execPath, [GSD_TOOLS, ...args], {
cwd: projectDir,
encoding: 'utf8',
timeout: 30000,
killSignal: 'SIGKILL',
});
}
@@ -152,11 +155,16 @@ function listProjectFiles(projectDir) {
const full = path.join(dir, entry.name);
const rel = path.relative(projectDir, full);
if (entry.isDirectory()) walk(full);
else files.push(rel);
else {
files.push({
path: rel,
sha256: crypto.createHash('sha256').update(fs.readFileSync(full)).digest('hex'),
});
}
}
}
walk(projectDir);
return files.sort();
return files.sort((a, b) => a.path.localeCompare(b.path));
}
describe('feat-3251: generated aliases dispatch through real gsd-tools behavior', () => {
@@ -212,6 +220,40 @@ describe('feat-3251: generated aliases dispatch through real gsd-tools behavior'
}
});
test('phase.mvp-mode ROADMAP lookup stops before custom-id next phase', () => {
const projectDir = createProject();
try {
fs.writeFileSync(
path.join(projectDir, '.planning', 'ROADMAP.md'),
[
'# Roadmap',
'',
'## v1.0.0',
'',
'### Phase 1: Numeric Phase',
'**Goal:** Users can sign in.',
'',
'### Phase custom-alpha: Custom Phase',
'**Goal:** Custom work.',
'**Mode:** mvp',
'',
].join('\n'),
);
const beforeFiles = listProjectFiles(projectDir);
const result = runGsdTools(['phase', 'mvp-mode', '1'], projectDir);
assert.equal(result.status, 0, result.stderr);
const output = JSON.parse(result.stdout);
assert.equal(output.active, false);
assert.equal(output.source, 'none');
assert.equal(output.roadmap_mode, null);
assert.deepEqual(listProjectFiles(projectDir), beforeFiles);
} finally {
fs.rmSync(projectDir, { recursive: true, force: true });
}
});
test('phase.mvp-mode JSON error is typed and leaves project files untouched', () => {
const projectDir = createProject();
try {