Files
stack/packages/webui/tests/library-cli.test.mjs

35 lines
2.8 KiB
JavaScript

// C2-04 only wires callbacks. HTTP routes and pages are later rows.
import test from 'node:test';
import assert from 'node:assert/strict';
import { spawnSync } from 'node:child_process';
import { readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { tmp, fixture } from '../../cli/tests/helpers.mjs';
import { HUMAN_CLI, TESTER_CLI } from '../../cli/src/transport.mjs';
test('C2-04 CLI: both listener callback pairs dispatch library verbs with their own transport', t => {
const root = tmp(t, 'library-cli-'), f = fixture(root), log = join(root, 'calls.jsonl');
writeFileSync(log, '');
const hook = join(root, 'hooks.mjs');
// The loader supplies a fixture bus and captures callbacks instead of
// opening an HTTP listener. Production imports and routes are unchanged.
const serveSource = "export const DEFAULT_BOARD='http://127.0.0.1:9';export const previewOptions=()=>null;export const proofOptions=()=>null;export async function startServer(o){if(typeof o.libraryFile!=='function'||typeof o.libraryStatus!=='function')throw Error('missing library callbacks');await o.libraryFile({project:'books',path:'Book One/A.md'});await o.libraryStatus({project:'books'});return {address:()=>({port:0}),close:()=>{}};}";
const busSource = `import {appendFileSync} from 'node:fs';export class BusReadError extends Error{};export const busCaller=o=>async(verb,args)=>{appendFileSync(${JSON.stringify(log)},JSON.stringify({verb,args,cli:o.cli??${JSON.stringify(HUMAN_CLI)}})+'\\n');return {};};export const organizationConsole=()=>{throw Error('organizationConsole outside dev-owner')};export const busBusiness=()=>{throw Error('busBusiness outside --sso')};export const userCaller=()=>{throw Error('userCaller outside --sso')};export const consoleCall=()=>{throw Error('consoleCall outside --sso')};`;
writeFileSync(hook, `import {registerHooks} from 'node:module';
registerHooks({load(url,context,next){
if(url.endsWith('/webui/src/serve.mjs'))return {format:'module',shortCircuit:true,source:${JSON.stringify(serveSource)}};
if(url.endsWith('/webui/src/bus.mjs'))return {format:'module',shortCircuit:true,source:${JSON.stringify(busSource)}};
return next(url,context);
}});`);
const result = spawnSync(process.execPath, [new URL('../src/cli.mjs', import.meta.url).pathname,
'serve', '--business', 'acme', '--port', '0', '--tester-socket'],
{ env: { ...f.env, NODE_OPTIONS: `--import=${hook}` }, encoding: 'utf8', timeout: 10000 });
assert.equal(result.status, 0, result.stdout + result.stderr);
const calls = readFileSync(log, 'utf8').trim().split('\n').filter(Boolean).map(JSON.parse);
assert.deepEqual(calls.map(c => [c.verb, c.cli]), [
['library.file', HUMAN_CLI], ['library.status', HUMAN_CLI],
['library.file', TESTER_CLI], ['library.status', TESTER_CLI],
]);
assert.equal(calls[0].args.path, 'Book One/A.md');
});