Files
redsen-lean-harness/tests/onboard.test.mjs
T
mozempkandCopilot 5ccf26f859 fix: tests depended on ambient CONTEXT7_API_KEY, broke in CI
\`lh doctor\`'s context7 check is a required, env-only check by design
(ADR: never inferred, never persisted). Tests that shell out to \`lh\`
or \`scripts/onboard.mjs\` inherited whatever CONTEXT7_API_KEY the
developer's shell happened to export, so \`doctor passes once the repo
is initialised\` and the onboard-script e2e test only ever passed on
machines with a real key set — never verified in a clean environment
until this CI run (no secret configured, correctly).

Fixed by injecting an obviously-fake fixture key (TEST_ENV in
helpers.mjs, exported and reused by onboard.test.mjs) into every
subprocess these tests spawn, so behaviour no longer depends on the
ambient shell. Verified locally with \`env -u CONTEXT7_API_KEY\` to
reproduce the CI environment exactly: 58/58 pass either way now.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-09 23:15:53 +02:00

81 lines
3.2 KiB
JavaScript

import { test, describe, after } from 'node:test';
import assert from 'node:assert/strict';
import { existsSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { execFileSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import { tempRepo, cleanup, TEST_ENV } from './helpers.mjs';
after(cleanup);
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
const ONBOARD = join(ROOT, 'scripts', 'onboard.mjs');
/** Run the onboarding script directly. Never throws — returns {code, stdout, stderr}. */
function onboard(args) {
try {
const stdout = execFileSync(process.execPath, [ONBOARD, ...args], {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
env: TEST_ENV,
});
return { code: 0, stdout, stderr: '' };
} catch (e) {
return { code: e.status ?? 1, stdout: e.stdout ?? '', stderr: e.stderr ?? '' };
}
}
describe('onboard script', () => {
test('--dry-run writes nothing', () => {
const dir = tempRepo();
const r = onboard([dir, '--dry-run']);
assert.equal(r.code, 0);
assert.ok(!existsSync(join(dir, '.github', 'agents')), 'dry run must not create files');
assert.ok(!existsSync(join(dir, '.agents')), 'dry run must not run lh init');
assert.match(r.stdout, /would write/);
});
test('--yes --no-npm-link copies the behaviour layer and runs lh init + doctor', () => {
const dir = tempRepo({
'package.json': JSON.stringify({ name: 'fixture', version: '1.0.0', scripts: { test: 'true' } }, null, 2),
});
const r = onboard([dir, '--yes', '--no-npm-link']);
assert.equal(r.code, 0, r.stdout + r.stderr);
for (const rel of ['.github/agents/conductor.agent.md', '.github/skills/design/SKILL.md',
'.github/mcp.json', 'AGENTS.md', '.agents/harness.config.json']) {
assert.ok(existsSync(join(dir, rel)), `expected ${rel} to exist`);
}
assert.match(r.stdout, /doctor: all required checks passed/);
});
test('rerunning with --yes is idempotent (no forced overwrite, no init failure)', () => {
const dir = tempRepo({
'package.json': JSON.stringify({ name: 'fixture', version: '1.0.0', scripts: { test: 'true' } }, null, 2),
});
assert.equal(onboard([dir, '--yes', '--no-npm-link']).code, 0);
const second = onboard([dir, '--yes', '--no-npm-link']);
assert.equal(second.code, 0, second.stdout + second.stderr);
assert.match(second.stdout, /already up to date/);
assert.match(second.stdout, /already initialized/);
});
test('refuses a target directory that does not exist', () => {
const r = onboard(['/nonexistent/path/for/sure', '--yes']);
assert.notEqual(r.code, 0);
});
test('a conflicting existing file is skipped unless --force', () => {
const dir = tempRepo({ 'AGENTS.md': 'custom project notes, do not clobber\n' });
const r = onboard([dir, '--yes', '--no-npm-link']);
assert.equal(r.code, 0);
assert.match(r.stdout, /skipped/);
const kept = existsSync(join(dir, 'AGENTS.md'));
assert.ok(kept, 'AGENTS.md must still exist');
const forced = onboard([dir, '--yes', '--no-npm-link', '--force']);
assert.equal(forced.code, 0);
assert.match(forced.stdout, /written/);
});
});