diff --git a/src/cli/gateway-cli/run.option-collisions.test.ts b/src/cli/gateway-cli/run.option-collisions.test.ts index 0bbab7a8448..b9deb42f667 100644 --- a/src/cli/gateway-cli/run.option-collisions.test.ts +++ b/src/cli/gateway-cli/run.option-collisions.test.ts @@ -196,15 +196,24 @@ describe("gateway run option collisions", () => { await sharedProgram.parseAsync(argv, { from: "user" }); } + function callArg(mock: { mock: { calls: unknown[][] } }, index = 0, argIndex = 0): T { + const call = mock.mock.calls[index]; + expect(call).toBeDefined(); + return call?.[argIndex] as T; + } + + function gatewayStartOptions(index = 0) { + expect(startGatewayServer.mock.calls[index]?.[0]).toBe(18789); + return callArg<{ + auth?: { mode?: string; token?: string; password?: string }; + bind?: string; + startupConfigSnapshotRead?: { snapshot?: Record }; + startupStartedAt?: number; + }>(startGatewayServer, index, 1); + } + function expectAuthOverrideMode(mode: string) { - expect(startGatewayServer).toHaveBeenCalledWith( - 18789, - expect.objectContaining({ - auth: expect.objectContaining({ - mode, - }), - }), - ); + expect(gatewayStartOptions().auth?.mode).toBe(mode); } it("forwards parent-captured options to `gateway run` subcommand", async () => { @@ -219,20 +228,13 @@ describe("gateway run option collisions", () => { "--force", ]); - expect(forceFreePortAndWait).toHaveBeenCalledWith(18789, expect.anything()); - expect(waitForPortBindable).toHaveBeenCalledWith( - 18789, - expect.objectContaining({ intervalMs: 150, timeoutMs: 3000 }), + expect(forceFreePortAndWait.mock.calls[0]?.[0]).toBe(18789); + expect(waitForPortBindable.mock.calls[0]?.[0]).toBe(18789); + expect(callArg<{ intervalMs?: number; timeoutMs?: number }>(waitForPortBindable, 0, 1)).toEqual( + { intervalMs: 150, timeoutMs: 3000 }, ); expect(setGatewayWsLogStyle).toHaveBeenCalledWith("full"); - expect(startGatewayServer).toHaveBeenCalledWith( - 18789, - expect.objectContaining({ - auth: expect.objectContaining({ - token: "tok_run", - }), - }), - ); + expect(gatewayStartOptions().auth?.token).toBe("tok_run"); }); it("blocks --force port cleanup from an older binary with newer config", async () => { @@ -295,15 +297,9 @@ describe("gateway run option collisions", () => { expect(readConfigFileSnapshotWithPluginMetadata).toHaveBeenCalledTimes(1); expect(readBestEffortConfig).not.toHaveBeenCalled(); - expect(startGatewayServer).toHaveBeenCalledWith( - 18789, - expect.objectContaining({ - bind: "loopback", - startupConfigSnapshotRead: { - snapshot: configState.snapshot, - }, - }), - ); + const options = gatewayStartOptions(); + expect(options.bind).toBe("loopback"); + expect(options.startupConfigSnapshotRead).toEqual({ snapshot: configState.snapshot }); }); it("uses the startup snapshot only for the first in-process gateway start", async () => { @@ -315,30 +311,12 @@ describe("gateway run option collisions", () => { await runGatewayCli(["gateway", "run", "--allow-unconfigured"]); expect(startGatewayServer).toHaveBeenCalledTimes(2); - expect(startGatewayServer).toHaveBeenNthCalledWith( - 1, - 18789, - expect.objectContaining({ - startupStartedAt: 1000, - startupConfigSnapshotRead: { - snapshot: configState.snapshot, - }, - }), - ); - expect(startGatewayServer).toHaveBeenNthCalledWith( - 2, - 18789, - expect.not.objectContaining({ - startupConfigSnapshotRead: expect.anything(), - }), - ); - expect(startGatewayServer).toHaveBeenNthCalledWith( - 2, - 18789, - expect.objectContaining({ - startupStartedAt: 2000, - }), - ); + const firstOptions = gatewayStartOptions(0); + expect(firstOptions.startupStartedAt).toBe(1000); + expect(firstOptions.startupConfigSnapshotRead).toEqual({ snapshot: configState.snapshot }); + const secondOptions = gatewayStartOptions(1); + expect(secondOptions.startupConfigSnapshotRead).toBeUndefined(); + expect(secondOptions.startupStartedAt).toBe(2000); }); it("logs when first startup will build missing Control UI assets", async () => { @@ -433,15 +411,9 @@ describe("gateway run option collisions", () => { await runGatewayCli(["gateway", "run", "--allow-unconfigured"]); - expect(startGatewayServer).toHaveBeenCalledWith( - 18789, - expect.objectContaining({ - bind: "loopback", - startupConfigSnapshotRead: expect.objectContaining({ - snapshot: expect.objectContaining({ valid: false }), - }), - }), - ); + const options = gatewayStartOptions(); + expect(options.bind).toBe("loopback"); + expect(options.startupConfigSnapshotRead?.snapshot?.valid).toBe(false); }); it.each(["none", "trusted-proxy"] as const)("accepts --auth %s override", async (mode) => { @@ -483,12 +455,7 @@ describe("gateway run option collisions", () => { await runGatewayCli(["gateway", "run", "--allow-unconfigured"]); - expect(startGatewayServer).toHaveBeenCalledWith( - 18789, - expect.objectContaining({ - bind: "loopback", - }), - ); + expect(gatewayStartOptions().bind).toBe("loopback"); }); it("reads gateway password from --password-file", async () => { @@ -508,15 +475,9 @@ describe("gateway run option collisions", () => { }, ); - expect(startGatewayServer).toHaveBeenCalledWith( - 18789, - expect.objectContaining({ - auth: expect.objectContaining({ - mode: "password", - password: "pw_from_file", // pragma: allowlist secret - }), - }), - ); + const options = gatewayStartOptions(); + expect(options.auth?.mode).toBe("password"); + expect(options.auth?.password).toBe("pw_from_file"); // pragma: allowlist secret expect(runtimeErrors).not.toContain( "Warning: --password can be exposed via process listings. Prefer --password-file or OPENCLAW_GATEWAY_PASSWORD.", );