76 lines
2.3 KiB
TypeScript
Raw Permalink Normal View History

import { strict as assert } from 'node:assert';
export interface IRunMxCliResult {
readonly logs: string[];
readonly errors: string[];
readonly exitCode: number;
}
async function loadMxCli(): Promise<{ createProgram: () => import('commander').Command }> {
const mxCliUrl = new URL('../../src/index.ts', import.meta.url).href;
return await import(`${mxCliUrl}?test=${Date.now()}-${Math.random().toString(16).slice(2)}`);
}
export async function runMxCli(argv: string[], options: { cwd?: string } = {}): Promise<IRunMxCliResult> {
const logs: string[] = [];
const errors: string[] = [];
let exitCode = 0;
const originalLog = console.log;
const originalError = console.error;
const originalExit = process.exit;
const originalCwd = process.cwd();
const { createProgram } = await loadMxCli();
console.log = (...args: unknown[]) => {
logs.push(args.map((arg) => String(arg)).join(' '));
};
console.error = (...args: unknown[]) => {
errors.push(args.map((arg) => String(arg)).join(' '));
};
(process as unknown as { exit: (code?: number) => never }).exit = ((code?: number) => {
exitCode = code ?? 0;
throw new Error(`process.exit(${exitCode})`);
}) as never;
if (options.cwd) {
process.chdir(options.cwd);
}
try {
const program = createProgram();
await program.parseAsync(argv);
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
if (!message.startsWith('process.exit(')) {
throw err;
}
} finally {
if (options.cwd) {
process.chdir(originalCwd);
}
console.log = originalLog;
console.error = originalError;
(process as unknown as { exit: typeof process.exit }).exit = originalExit;
}
return { logs, errors, exitCode };
}
export function parseLastJson(lines: readonly string[]): unknown {
for (let i = lines.length - 1; i >= 0; i--) {
const value = lines[i]?.trim() ?? '';
if (!value) continue;
try {
return JSON.parse(value);
} catch {
// continue
}
}
throw new Error(`No JSON payload found in output:\n${lines.join('\n')}`);
}
export function assertExitCode(result: IRunMxCliResult, expected: number): void {
assert.equal(result.exitCode, expected, `Expected exit code ${expected}, got ${result.exitCode}`);
}