okr/tests/frontmatter-compat.test.mjs

109 lines
3.5 KiB
JavaScript

// frontmatter-compat.test.mjs
// Karakteriserings-/kompatibilitetstest (SC2): beviser at ruting av
// inject-okr-context.mjs gjennom den delte lib/frontmatter.mjs er
// ATFERDS-BEVARENDE for de 9 leste noeklene, med EN tilsiktet endring:
// comment-leak paa usitert `okr_frikoblet_fra_loenn`-linje forsvinner.
// Spawner hooken som subprosess (full 9-felts frontmatter, rikere enn
// inject-okr-context.test.mjs sin makeProjectConfig som kun skriver navn).
// Zero npm deps. Moenster: tests/inject-okr-context.test.mjs.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { execFileSync } from 'node:child_process';
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const HOOK = join(
dirname(fileURLToPath(import.meta.url)),
'..',
'hooks',
'scripts',
'inject-okr-context.mjs',
);
// Bygger en full 9-felts okr.local.md. okr_frikoblet_fra_loenn skrives USITERT
// MED en trailing "# ..."-kommentar — det er denne lekkasjen den delte
// parseren skal fjerne.
function makeFullConfig(workDir, fields = {}) {
const f = {
navn: 'TestOrg',
kortform: 'TO',
gjeldende: 'T2-2026',
sektor: 'transport',
modenhetsnivaa: 'nivaa-2',
fase: 'utforsker',
okr_frikoblet_fra_loenn: 'true',
psykologisk_trygghet: 'hoy',
linear: true,
...fields,
};
const body =
[
'---',
`navn: "${f.navn}"`,
`kortform: "${f.kortform}"`,
`gjeldende: "${f.gjeldende}"`,
`sektor: "${f.sektor}"`,
`modenhetsnivaa: "${f.modenhetsnivaa}"`,
`fase: "${f.fase}"`,
`okr_frikoblet_fra_loenn: ${f.okr_frikoblet_fra_loenn} # frikoblet fra lonn`,
`psykologisk_trygghet: "${f.psykologisk_trygghet}"`,
'linear:',
` aktivert: ${f.linear}`,
'---',
'',
].join('\n');
const p = join(workDir, '.claude');
mkdirSync(p, { recursive: true });
writeFileSync(join(p, 'okr.local.md'), body);
}
const OKR_PROMPT = JSON.stringify({ prompt: 'hjelp meg skrive OKR' });
function runHook(cwd, home, input = OKR_PROMPT) {
return execFileSync('node', [HOOK], {
cwd,
env: { ...process.env, HOME: home },
input,
encoding: 'utf8',
});
}
function withDirs(fn) {
const home = mkdtempSync(join(tmpdir(), 'okrhome-'));
const work = mkdtempSync(join(tmpdir(), 'okrwork-'));
try {
fn(home, work);
} finally {
rmSync(home, { recursive: true, force: true });
rmSync(work, { recursive: true, force: true });
}
}
test('full config: alle 9 noekler resolver likt som foer', () => {
withDirs((home, work) => {
makeFullConfig(work);
const out = runHook(work, home);
assert.match(out, /Organisasjon: TestOrg \(TO\)/, 'navn + kortform');
assert.match(out, /Syklus: T2-2026 \[utforsker\]/, 'gjeldende + fase');
assert.match(out, /Sektor: transport/, 'sektor');
assert.match(out, /Modenhet: nivaa-2/, 'modenhetsnivaa');
assert.match(out, /OKR frikoblet fra lonn: true/, 'frikoblet-verdi');
assert.match(out, /Psykologisk trygghet: hoy/, 'psykologisk_trygghet');
assert.match(out, /Linear: aktivert/, 'linear aktivert: true');
});
});
test('comment-leak fjernet: ingen "#" i injisert melding', () => {
withDirs((home, work) => {
makeFullConfig(work);
const out = runHook(work, home);
assert.doesNotMatch(
out,
/#/,
'usitert frikoblet-linjes "# ..."-kommentar skal ikke lekke inn i meldingen',
);
});
});