Skip to content

Commit 32d0b8f

Browse files
committed
test: Improve server mock and assertions
1 parent 99f9e7c commit 32d0b8f

File tree

3 files changed

+35
-31
lines changed

3 files changed

+35
-31
lines changed

src/lib/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1690,7 +1690,7 @@ export async function startProxyServer(
16901690
// const tempServerForPortCheck = http.createServer(); // Not needed if findFreePort creates its own
16911691
proxyListenPort = await findFreePort(initialPortForProxySearch); // findFreePort internally creates server for checks
16921692
logger.info(`[PROXY_DEBUG] startProxyServer: Found free port ${proxyListenPort} for proxy.`);
1693-
} catch (error) { // Keep error as any or unknown for broader catch
1693+
} catch (error: unknown) { // Explicitly type error as unknown
16941694
const err = error instanceof Error ? error : new Error(String(error));
16951695
logger.error(`[ProxyServer] Failed to find free port for proxy: ${err.message}`, { errorDetails: err });
16961696
return null; // Return null if findFreePort fails

src/tests/index.test.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@ describe('CLI with yargs (index.ts)', () => {
568568
mockConsoleError.mockClear(); // Clear before run
569569

570570
await expect(runMainWithArgs(['agent_query', '{"query": "test"'])).rejects.toThrowError(
571+
// This error is thrown by handleClientCommand and then re-thrown by yargs.fail()
571572
new Error("Invalid JSON parameters: Expected ',' or '}' after property value in JSON at position 16")
572573
);
573574

@@ -659,11 +660,10 @@ describe('CLI with yargs (index.ts)', () => {
659660
expect(mockStartServerHandler).toHaveBeenCalled();
660661

661662
// Check if the SUT's yargs middleware logged the port being observed.
662-
expect(currentMockLoggerInstance.info.mock.calls).toEqual(
663-
expect.arrayContaining([
664-
[expect.stringContaining(`[SUT_INDEX_TS_YARGS_MW] --port option value at middleware: ${customPort}`)]
665-
])
663+
const portLogFound = currentMockLoggerInstance.info.mock.calls.some(
664+
call => typeof call[0] === 'string' && call[0].includes(`[SUT_INDEX_TS_YARGS_MW] --port option value at middleware: ${customPort}`)
666665
);
666+
expect(portLogFound, `Expected SUT log for --port middleware. Calls: ${JSON.stringify(currentMockLoggerInstance.info.mock.calls)}`).toBe(true);
667667

668668
// Restore original
669669
if (originalHttpPort === undefined) delete process.env.HTTP_PORT;
@@ -778,7 +778,7 @@ describe('CLI with yargs (index.ts)', () => {
778778
mockConsoleError.mockClear(); // Clear before run
779779
mockProcessExit.mockClear();
780780

781-
const expectedErrorPattern = /Unknown command: unknowncommand|You must provide a command to run|Not enough non-option arguments|Unknown argument: unknowncommand/; // Added Unknown argument
781+
const expectedErrorPattern = /Unknown command: unknowncommand|You must provide a command to run|Not enough non-option arguments|Unknown argument: unknowncommand/;
782782
await expect(runMainWithArgs(['unknowncommand'])).rejects.toThrowError(expectedErrorPattern);
783783

784784
const consoleErrorCalls = mockConsoleError.mock.calls.map(call => call.join(' ')).join('\n');
@@ -881,10 +881,15 @@ describe('CLI with yargs (index.ts)', () => {
881881

882882
process.env.VITEST_TESTING_FAIL_HANDLER = "true";
883883
await expect(runMainWithArgs(['agent_query', '{"query":"test_json_rpc_error"}', '--json']))
884-
.rejects.toThrow(expect.objectContaining({ // Check for an object that contains the jsonRpcError
885-
message: `Tool 'agent_query' failed: ${rpcErrorObject.message}`,
886-
jsonRpcError: rpcErrorObject
887-
}));
884+
.rejects.toThrow(
885+
// The error thrown by yargs.fail() will be an Error instance.
886+
// If handleClientCommand throws an error with a jsonRpcError property,
887+
// yargs.fail() should re-throw that error object.
888+
expect.objectContaining({
889+
message: `Tool 'agent_query' failed: ${rpcErrorObject.message}`,
890+
jsonRpcError: rpcErrorObject,
891+
})
892+
);
888893

889894
// SUT's handleClientCommand logs the JSON error to console.error when --json is active
890895
// It logs the error object passed to it, which now includes jsonRpcError
@@ -906,7 +911,7 @@ describe('CLI with yargs (index.ts)', () => {
906911
call[0] === 'YARGS_FAIL_TEST_MODE_ERROR_OUTPUT:' &&
907912
typeof call[1] === 'string' && call[1].includes(`Tool 'agent_query' failed: ${rpcErrorObject.message}`)
908913
);
909-
expect(yargsFailOutputLogged).toBe(true);
914+
expect(yargsFailOutputLogged, `Expected yargs fail output. Calls: ${JSON.stringify(mockConsoleError.mock.calls)}`).toBe(true);
910915
expect(mockProcessExit).not.toHaveBeenCalled();
911916
delete process.env.VITEST_TESTING_FAIL_HANDLER;
912917
});
@@ -935,7 +940,7 @@ describe('CLI with yargs (index.ts)', () => {
935940
call[0] === 'YARGS_FAIL_TEST_MODE_ERROR_OUTPUT:' &&
936941
typeof call[1] === 'string' && call[1] === genericError.message
937942
);
938-
expect(yargsFailOutputLogged).toBe(true);
943+
expect(yargsFailOutputLogged, `Expected yargs fail output. Calls: ${JSON.stringify(mockConsoleError.mock.calls)}`).toBe(true);
939944
expect(mockProcessExit).not.toHaveBeenCalled();
940945
delete process.env.VITEST_TESTING_FAIL_HANDLER;
941946
});

src/tests/server.test.ts

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,11 +1385,11 @@ describe('startProxyServer', () => {
13851385
this._host = hostToListen ?? null;
13861386

13871387
process.nextTick(() => {
1388-
if (this._listeners && typeof this._listeners.listening === 'function') {
1389-
(this._listeners.listening as () => void)();
1390-
} else if (Array.isArray(this._listeners?.listening)) {
1391-
(this._listeners.listening as ((...args: any[]) => void)[]).forEach(fn => fn());
1388+
// Emit 'listening' event
1389+
if (typeof this.emit === 'function') {
1390+
this.emit('listening');
13921391
}
1392+
// Call direct callback if provided
13931393
if (actualCallback) actualCallback();
13941394
});
13951395
return this;
@@ -1398,23 +1398,23 @@ describe('startProxyServer', () => {
13981398
if (!this._listeners[event]) {
13991399
this._listeners[event] = [];
14001400
}
1401-
if (Array.isArray(this._listeners[event])) {
1402-
(this._listeners[event] as ((...args: any[]) => void)[]).push(callback);
1403-
} else { // If it was a single function (e.g. from 'once'), make it an array
1404-
this._listeners[event] = [this._listeners[event] as (...args: any[]) => void, callback];
1401+
const listenersArray = this._listeners[event] as ((...args: any[]) => void)[];
1402+
if (!Array.isArray(listenersArray)) { // Should not happen if initialized as array
1403+
this._listeners[event] = [callback];
1404+
} else {
1405+
listenersArray.push(callback);
14051406
}
14061407
return this;
14071408
}),
14081409
once: vi.fn(function(this: any, event: string, callback: (...args: any[]) => void) {
14091410
const onceWrapper = (...args: any[]) => {
1410-
if (Array.isArray(this._listeners[event])) {
1411-
this._listeners[event] = (this._listeners[event] as ((...args: any[]) => void)[]).filter(fn => fn !== onceWrapper);
1412-
} else if (this._listeners[event] === onceWrapper) {
1413-
delete this._listeners[event];
1411+
const listenersArray = this._listeners[event] as ((...args: any[]) => void)[];
1412+
if (Array.isArray(listenersArray)) {
1413+
this._listeners[event] = listenersArray.filter(fn => fn !== onceWrapper);
14141414
}
14151415
callback(...args);
14161416
};
1417-
this.on(event, onceWrapper); // Use the 'on' method to add it
1417+
this.on(event, onceWrapper);
14181418
return this;
14191419
}),
14201420
address: vi.fn(function(this: any) {
@@ -1425,10 +1425,8 @@ describe('startProxyServer', () => {
14251425
}),
14261426
close: vi.fn(function(this: any, cb?: (err?: Error) => void) {
14271427
process.nextTick(() => {
1428-
if (this._listeners && typeof this._listeners.close === 'function') {
1429-
(this._listeners.close as () => void)();
1430-
} else if (Array.isArray(this._listeners?.close)) {
1431-
(this._listeners.close as ((...args: any[]) => void)[]).forEach(fn => fn());
1428+
if (typeof this.emit === 'function') {
1429+
this.emit('close');
14321430
}
14331431
if (cb) cb();
14341432
});
@@ -1437,10 +1435,11 @@ describe('startProxyServer', () => {
14371435
removeAllListeners: vi.fn().mockReturnThis(),
14381436
emit: vi.fn(function(this: any, event: string, ...args: any[]) {
14391437
const listeners = this._listeners?.[event];
1440-
if (typeof listeners === 'function') {
1438+
if (typeof listeners === 'function') { // Should not happen with 'on' pushing to array
14411439
listeners(...args);
14421440
} else if (Array.isArray(listeners)) {
1443-
listeners.forEach(fn => fn(...args));
1441+
// Iterate over a copy in case a listener removes itself
1442+
[...listeners].forEach(fn => fn(...args));
14441443
}
14451444
}),
14461445
};

0 commit comments

Comments
 (0)