\`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>
81 lines
3.2 KiB
JavaScript
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/);
|
|
});
|
|
});
|