155 lines
6.2 KiB
JavaScript
155 lines
6.2 KiB
JavaScript
/**
|
|
* install_to_bmad Flag — Design Contract Tests
|
|
*
|
|
* Unit tests against the functions that implement the install_to_bmad flag.
|
|
* These nail down the 4 core design decisions:
|
|
*
|
|
* 1. true/omitted → skill stays in _bmad/ (default behavior)
|
|
* 2. false → skill removed from _bmad/ after IDE install
|
|
* 3. No platform → no cleanup runs (cleanup lives in installVerbatimSkills)
|
|
* 4. Mixed flags → each skill evaluated independently
|
|
*
|
|
* Usage: node test/test-install-to-bmad.js
|
|
*/
|
|
|
|
const path = require('node:path');
|
|
const os = require('node:os');
|
|
const fs = require('fs-extra');
|
|
const { loadSkillManifest, getInstallToBmad } = require('../tools/cli/installers/lib/ide/shared/skill-manifest');
|
|
|
|
// ANSI colors
|
|
const colors = {
|
|
reset: '\u001B[0m',
|
|
green: '\u001B[32m',
|
|
red: '\u001B[31m',
|
|
yellow: '\u001B[33m',
|
|
cyan: '\u001B[36m',
|
|
dim: '\u001B[2m',
|
|
};
|
|
|
|
let passed = 0;
|
|
let failed = 0;
|
|
|
|
function assert(condition, testName, errorMessage = '') {
|
|
if (condition) {
|
|
console.log(`${colors.green}✓${colors.reset} ${testName}`);
|
|
passed++;
|
|
} else {
|
|
console.log(`${colors.red}✗${colors.reset} ${testName}`);
|
|
if (errorMessage) {
|
|
console.log(` ${colors.dim}${errorMessage}${colors.reset}`);
|
|
}
|
|
failed++;
|
|
}
|
|
}
|
|
|
|
async function runTests() {
|
|
console.log(`${colors.cyan}========================================`);
|
|
console.log('install_to_bmad — Design Contract Tests');
|
|
console.log(`========================================${colors.reset}\n`);
|
|
|
|
// ============================================================
|
|
// 1. true/omitted → getInstallToBmad returns true (keep in _bmad/)
|
|
// ============================================================
|
|
console.log(`${colors.yellow}Design decision 1: true or omitted → skill stays in _bmad/${colors.reset}\n`);
|
|
|
|
// Null manifest (no bmad-skill-manifest.yaml) → true
|
|
assert(getInstallToBmad(null, 'workflow.md') === true, 'null manifest defaults to true');
|
|
|
|
// Single-entry, flag omitted → true
|
|
assert(
|
|
getInstallToBmad({ __single: { type: 'skill' } }, 'workflow.md') === true,
|
|
'single-entry manifest with flag omitted defaults to true',
|
|
);
|
|
|
|
// Single-entry, explicit true → true
|
|
assert(
|
|
getInstallToBmad({ __single: { type: 'skill', install_to_bmad: true } }, 'workflow.md') === true,
|
|
'single-entry manifest with explicit true returns true',
|
|
);
|
|
|
|
console.log('');
|
|
|
|
// ============================================================
|
|
// 2. false → getInstallToBmad returns false (remove from _bmad/)
|
|
// ============================================================
|
|
console.log(`${colors.yellow}Design decision 2: false → skill removed from _bmad/${colors.reset}\n`);
|
|
|
|
// Single-entry, explicit false → false
|
|
assert(
|
|
getInstallToBmad({ __single: { type: 'skill', install_to_bmad: false } }, 'workflow.md') === false,
|
|
'single-entry manifest with explicit false returns false',
|
|
);
|
|
|
|
// loadSkillManifest round-trip: YAML with false is preserved through load
|
|
{
|
|
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-itb-'));
|
|
await fs.writeFile(path.join(tmpDir, 'bmad-skill-manifest.yaml'), 'type: skill\ninstall_to_bmad: false\n');
|
|
const loaded = await loadSkillManifest(tmpDir);
|
|
assert(getInstallToBmad(loaded, 'workflow.md') === false, 'loadSkillManifest preserves install_to_bmad: false through round-trip');
|
|
await fs.remove(tmpDir);
|
|
}
|
|
|
|
console.log('');
|
|
|
|
// ============================================================
|
|
// 3. No platform → cleanup only runs inside installVerbatimSkills
|
|
// (This is a design invariant: getInstallToBmad is only consulted
|
|
// during IDE install. Without a platform, the flag has no effect.)
|
|
// ============================================================
|
|
console.log(`${colors.yellow}Design decision 3: flag is a per-skill property, not a pipeline gate${colors.reset}\n`);
|
|
|
|
// The flag value is stored but doesn't trigger any side effects by itself.
|
|
// Cleanup is driven by reading the CSV column inside installVerbatimSkills.
|
|
// We verify the flag is just data — getInstallToBmad doesn't touch the filesystem.
|
|
{
|
|
const manifest = { __single: { type: 'skill', install_to_bmad: false } };
|
|
const result = getInstallToBmad(manifest, 'workflow.md');
|
|
assert(typeof result === 'boolean', 'getInstallToBmad returns a boolean (pure data, no side effects)');
|
|
assert(result === false, 'false value is faithfully returned for consumer to act on');
|
|
}
|
|
|
|
console.log('');
|
|
|
|
// ============================================================
|
|
// 4. Mixed flags → each skill evaluated independently
|
|
// ============================================================
|
|
console.log(`${colors.yellow}Design decision 4: mixed flags — each skill independent${colors.reset}\n`);
|
|
|
|
// Multi-entry manifest: different files can have different flags
|
|
{
|
|
const manifest = {
|
|
'workflow.md': { type: 'skill', install_to_bmad: false },
|
|
'other.md': { type: 'skill', install_to_bmad: true },
|
|
};
|
|
assert(getInstallToBmad(manifest, 'workflow.md') === false, 'multi-entry: workflow.md with false returns false');
|
|
assert(getInstallToBmad(manifest, 'other.md') === true, 'multi-entry: other.md with true returns true');
|
|
assert(getInstallToBmad(manifest, 'unknown.md') === true, 'multi-entry: unknown file defaults to true');
|
|
}
|
|
|
|
console.log('');
|
|
|
|
// ============================================================
|
|
// Summary
|
|
// ============================================================
|
|
console.log(`${colors.cyan}========================================`);
|
|
console.log('Results:');
|
|
console.log(` Passed: ${colors.green}${passed}${colors.reset}`);
|
|
console.log(` Failed: ${colors.red}${failed}${colors.reset}`);
|
|
console.log(`========================================${colors.reset}\n`);
|
|
|
|
if (failed === 0) {
|
|
console.log(`${colors.green}All install_to_bmad contract tests passed!${colors.reset}\n`);
|
|
process.exit(0);
|
|
} else {
|
|
console.log(`${colors.red}Some install_to_bmad contract tests failed${colors.reset}\n`);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
runTests().catch((error) => {
|
|
console.error(`${colors.red}Test runner failed:${colors.reset}`, error.message);
|
|
console.error(error.stack);
|
|
process.exit(1);
|
|
});
|