// tests/lib/manifest-schema-extensions.test.mjs // Cover the OPTIONAL_KEYS extension to lib/parsers/manifest-yaml.mjs: // - skip_commit_check (boolean, default false) // - memory_write (boolean, default false) // // Defaults must NOT break the REQUIRED_KEYS contract. // Non-boolean values must produce MANIFEST_OPTIONAL_TYPE error. import { test } from 'node:test'; import { strict as assert } from 'node:assert'; import { parseManifest, OPTIONAL_KEYS } from '../../lib/parsers/manifest-yaml.mjs'; const BASE = `### Step 1: Cover - Manifest: \`\`\`yaml manifest: expected_paths: - lib/foo.mjs min_file_count: 1 commit_message_pattern: "^feat:" bash_syntax_check: [] forbidden_paths: [] must_contain: []`; function bodyWithExtras(extras) { return `${BASE}\n${extras}\n \`\`\`\n`; } function bodyOnlyRequired() { return `${BASE}\n \`\`\`\n`; } test('OPTIONAL_KEYS exports skip_commit_check + memory_write', () => { assert.deepEqual( [...OPTIONAL_KEYS].sort(), ['memory_write', 'skip_commit_check'].sort(), 'OPTIONAL_KEYS export drift — pin contract', ); }); test('absence of optional keys → defaults to false (both fields)', () => { const r = parseManifest(bodyOnlyRequired()); assert.equal(r.valid, true, JSON.stringify(r.errors)); assert.equal(r.parsed.skip_commit_check, false); assert.equal(r.parsed.memory_write, false); }); test('skip_commit_check: true honored', () => { const r = parseManifest(bodyWithExtras(' skip_commit_check: true')); assert.equal(r.valid, true, JSON.stringify(r.errors)); assert.equal(r.parsed.skip_commit_check, true); assert.equal(r.parsed.memory_write, false); }); test('memory_write: true honored', () => { const r = parseManifest(bodyWithExtras(' memory_write: true')); assert.equal(r.valid, true, JSON.stringify(r.errors)); assert.equal(r.parsed.memory_write, true); assert.equal(r.parsed.skip_commit_check, false); }); test('both optional fields together — both honored', () => { const r = parseManifest(bodyWithExtras(' skip_commit_check: true\n memory_write: true')); assert.equal(r.valid, true, JSON.stringify(r.errors)); assert.equal(r.parsed.skip_commit_check, true); assert.equal(r.parsed.memory_write, true); }); test('skip_commit_check: non-boolean rejected with MANIFEST_OPTIONAL_TYPE', () => { const r = parseManifest(bodyWithExtras(' skip_commit_check: "yes"')); assert.equal(r.valid, false); const found = r.errors.find(e => e.code === 'MANIFEST_OPTIONAL_TYPE'); assert.ok(found, `expected MANIFEST_OPTIONAL_TYPE, got: ${JSON.stringify(r.errors)}`); assert.match(found.message, /skip_commit_check/); }); test('memory_write: numeric rejected with MANIFEST_OPTIONAL_TYPE', () => { const r = parseManifest(bodyWithExtras(' memory_write: 1')); assert.equal(r.valid, false); const found = r.errors.find(e => e.code === 'MANIFEST_OPTIONAL_TYPE'); assert.ok(found, `expected MANIFEST_OPTIONAL_TYPE, got: ${JSON.stringify(r.errors)}`); assert.match(found.message, /memory_write/); }); test('extension does NOT break REQUIRED_KEYS contract', () => { const r = parseManifest(bodyOnlyRequired()); assert.equal(r.valid, true); for (const k of ['expected_paths', 'min_file_count', 'commit_message_pattern', 'bash_syntax_check', 'forbidden_paths', 'must_contain']) { assert.ok(k in r.parsed, `required key ${k} missing after extension`); } });