Files
ccs/tests/unit/targets/codex-adapter-exec.test.ts

107 lines
3.1 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, spyOn } from 'bun:test';
import * as childProcess from 'child_process';
import { EventEmitter } from 'events';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { CodexAdapter } from '../../../src/targets/codex-adapter';
import { buildCodexBrowserMcpOverrides } from '../../../src/utils/browser-codex-overrides';
import * as signalForwarder from '../../../src/utils/signal-forwarder';
function createMockChild(): EventEmitter & {
stdout: EventEmitter;
stderr: EventEmitter;
exitCode: number | null;
killed: boolean;
pid: number;
unref: () => EventEmitter;
kill: () => boolean;
} {
const child = new EventEmitter() as EventEmitter & {
stdout: EventEmitter;
stderr: EventEmitter;
exitCode: number | null;
killed: boolean;
pid: number;
unref: () => EventEmitter;
kill: () => boolean;
};
child.stdout = new EventEmitter();
child.stderr = new EventEmitter();
child.exitCode = null;
child.killed = false;
child.pid = process.pid;
child.unref = () => child;
child.kill = () => {
child.killed = true;
child.exitCode = 1;
return true;
};
return child;
}
describe('codex-adapter exec', () => {
const originalPlatform = process.platform;
let tmpDir: string;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-codex-adapter-exec-'));
});
afterEach(() => {
Object.defineProperty(process, 'platform', { value: originalPlatform });
fs.rmSync(tmpDir, { recursive: true, force: true });
});
it('launches Windows cmd wrappers via cmd.exe when runtime overrides include browser MCP args', () => {
Object.defineProperty(process, 'platform', { value: 'win32' });
const fakeCodex = path.join(tmpDir, 'codex.cmd');
fs.writeFileSync(fakeCodex, '');
const spawnSpy = spyOn(childProcess, 'spawn').mockImplementation(
() => createMockChild() as unknown as ReturnType<typeof childProcess.spawn>
);
const signalSpy = spyOn(signalForwarder, 'wireChildProcessSignals').mockImplementation(
() => undefined
);
try {
const adapter = new CodexAdapter();
const binaryInfo = {
path: fakeCodex,
needsShell: true,
features: ['config-overrides'],
};
const args = adapter.buildArgs('default', ['--version'], {
profileType: 'default',
creds: {
profile: 'default',
baseUrl: '',
apiKey: '',
runtimeConfigOverrides: buildCodexBrowserMcpOverrides(),
},
binaryInfo,
});
adapter.exec(args, {}, { binaryInfo });
expect(spawnSpy).toHaveBeenCalledTimes(1);
const [command, options] = spawnSpy.mock.calls[0] as [
string,
Record<string, unknown> | undefined,
];
expect(options?.shell).toBe('C:\\Windows\\System32\\cmd.exe');
expect(command).toContain(fakeCodex);
expect(command).toContain('mcp_servers.ccs_browser.args=');
expect(command).toContain('@playwright/mcp@0.0.70');
} finally {
spawnSpy.mockRestore();
signalSpy.mockRestore();
}
});
});