diff --git a/src/gateway/call.test.ts b/src/gateway/call.test.ts index f716e39d6..ab07d3357 100644 --- a/src/gateway/call.test.ts +++ b/src/gateway/call.test.ts @@ -79,10 +79,10 @@ const { buildGatewayConnectionDetails, callGateway, callGatewayCli, callGatewayS await import("./call.js"); function resetGatewayCallMocks() { - loadConfig.mockReset(); - resolveGatewayPort.mockReset(); - pickPrimaryTailnetIPv4.mockReset(); - pickPrimaryLanIPv4.mockReset(); + loadConfig.mockClear(); + resolveGatewayPort.mockClear(); + pickPrimaryTailnetIPv4.mockClear(); + pickPrimaryLanIPv4.mockClear(); lastClientOptions = null; startMode = "hello"; closeCode = 1006; @@ -133,61 +133,51 @@ describe("callGateway url resolution", () => { expect(lastClientOptions?.url).toBe("ws://127.0.0.1:18800"); }); - it("uses loopback with TLS when local bind is tailnet", async () => { - loadConfig.mockReturnValue({ + it.each([ + { + label: "tailnet with TLS", gateway: { mode: "local", bind: "tailnet", tls: { enabled: true } }, - }); - resolveGatewayPort.mockReturnValue(18800); - pickPrimaryTailnetIPv4.mockReturnValue("100.64.0.1"); - - await callGateway({ method: "health" }); - - expect(lastClientOptions?.url).toBe("wss://127.0.0.1:18800"); - }); - - it("uses loopback without TLS when local bind is tailnet", async () => { - loadConfig.mockReturnValue({ gateway: { mode: "local", bind: "tailnet" } }); - resolveGatewayPort.mockReturnValue(18800); - pickPrimaryTailnetIPv4.mockReturnValue("100.64.0.1"); - - await callGateway({ method: "health" }); - - expect(lastClientOptions?.url).toBe("ws://127.0.0.1:18800"); - }); - - it("uses loopback with TLS when bind is lan", async () => { - loadConfig.mockReturnValue({ + tailnetIp: "100.64.0.1", + lanIp: undefined, + expectedUrl: "wss://127.0.0.1:18800", + }, + { + label: "tailnet without TLS", + gateway: { mode: "local", bind: "tailnet" }, + tailnetIp: "100.64.0.1", + lanIp: undefined, + expectedUrl: "ws://127.0.0.1:18800", + }, + { + label: "lan with TLS", gateway: { mode: "local", bind: "lan", tls: { enabled: true } }, - }); + tailnetIp: undefined, + lanIp: "192.168.1.42", + expectedUrl: "wss://127.0.0.1:18800", + }, + { + label: "lan without TLS", + gateway: { mode: "local", bind: "lan" }, + tailnetIp: undefined, + lanIp: "192.168.1.42", + expectedUrl: "ws://127.0.0.1:18800", + }, + { + label: "lan without discovered LAN IP", + gateway: { mode: "local", bind: "lan" }, + tailnetIp: undefined, + lanIp: undefined, + expectedUrl: "ws://127.0.0.1:18800", + }, + ])("uses loopback for $label", async ({ gateway, tailnetIp, lanIp, expectedUrl }) => { + loadConfig.mockReturnValue({ gateway }); resolveGatewayPort.mockReturnValue(18800); - pickPrimaryTailnetIPv4.mockReturnValue(undefined); - pickPrimaryLanIPv4.mockReturnValue("192.168.1.42"); + pickPrimaryTailnetIPv4.mockReturnValue(tailnetIp); + pickPrimaryLanIPv4.mockReturnValue(lanIp); await callGateway({ method: "health" }); - expect(lastClientOptions?.url).toBe("wss://127.0.0.1:18800"); - }); - - it("uses loopback without TLS when bind is lan", async () => { - loadConfig.mockReturnValue({ gateway: { mode: "local", bind: "lan" } }); - resolveGatewayPort.mockReturnValue(18800); - pickPrimaryTailnetIPv4.mockReturnValue(undefined); - pickPrimaryLanIPv4.mockReturnValue("192.168.1.42"); - - await callGateway({ method: "health" }); - - expect(lastClientOptions?.url).toBe("ws://127.0.0.1:18800"); - }); - - it("falls back to loopback when bind is lan but no LAN IP found", async () => { - loadConfig.mockReturnValue({ gateway: { mode: "local", bind: "lan" } }); - resolveGatewayPort.mockReturnValue(18800); - pickPrimaryTailnetIPv4.mockReturnValue(undefined); - pickPrimaryLanIPv4.mockReturnValue(undefined); - - await callGateway({ method: "health" }); - - expect(lastClientOptions?.url).toBe("ws://127.0.0.1:18800"); + expect(lastClientOptions?.url).toBe(expectedUrl); }); it("uses url override in remote mode even when remote url is missing", async () => { @@ -274,35 +264,30 @@ describe("buildGatewayConnectionDetails", () => { expect(details.message).toContain("Gateway target: ws://127.0.0.1:18789"); }); - it("uses loopback URL and loopback source when bind is lan", () => { - loadConfig.mockReturnValue({ + it.each([ + { + label: "with TLS", gateway: { mode: "local", bind: "lan", tls: { enabled: true } }, - }); + expectedUrl: "wss://127.0.0.1:18800", + }, + { + label: "without TLS", + gateway: { mode: "local", bind: "lan" }, + expectedUrl: "ws://127.0.0.1:18800", + }, + ])("uses loopback URL for bind=lan $label", ({ gateway, expectedUrl }) => { + loadConfig.mockReturnValue({ gateway }); resolveGatewayPort.mockReturnValue(18800); pickPrimaryTailnetIPv4.mockReturnValue(undefined); pickPrimaryLanIPv4.mockReturnValue("10.0.0.5"); const details = buildGatewayConnectionDetails(); - expect(details.url).toBe("wss://127.0.0.1:18800"); + expect(details.url).toBe(expectedUrl); expect(details.urlSource).toBe("local loopback"); expect(details.bindDetail).toBe("Bind: lan"); }); - it("uses loopback URL for bind=lan without TLS", () => { - loadConfig.mockReturnValue({ - gateway: { mode: "local", bind: "lan" }, - }); - resolveGatewayPort.mockReturnValue(18800); - pickPrimaryTailnetIPv4.mockReturnValue(undefined); - pickPrimaryLanIPv4.mockReturnValue("10.0.0.5"); - - const details = buildGatewayConnectionDetails(); - - expect(details.url).toBe("ws://127.0.0.1:18800"); - expect(details.urlSource).toBe("local loopback"); - }); - it("prefers remote url when configured", () => { loadConfig.mockReturnValue({ gateway: { diff --git a/src/infra/bonjour.test.ts b/src/infra/bonjour.test.ts index 53b1049ea..d8f976fdc 100644 --- a/src/infra/bonjour.test.ts +++ b/src/infra/bonjour.test.ts @@ -103,11 +103,11 @@ describe("gateway bonjour advertiser", () => { process.env[key] = value; } - createService.mockReset(); - shutdown.mockReset(); - registerUnhandledRejectionHandler.mockReset(); - logWarn.mockReset(); - logDebug.mockReset(); + createService.mockClear(); + shutdown.mockClear(); + registerUnhandledRejectionHandler.mockClear(); + logWarn.mockClear(); + logDebug.mockClear(); vi.useRealTimers(); vi.restoreAllMocks(); }); diff --git a/src/infra/outbound/target-resolver.test.ts b/src/infra/outbound/target-resolver.test.ts index 6ffed273c..bf5bdd7cb 100644 --- a/src/infra/outbound/target-resolver.test.ts +++ b/src/infra/outbound/target-resolver.test.ts @@ -18,9 +18,9 @@ describe("resolveMessagingTarget (directory fallback)", () => { const cfg = {} as OpenClawConfig; beforeEach(() => { - mocks.listGroups.mockReset(); - mocks.listGroupsLive.mockReset(); - mocks.getChannelPlugin.mockReset(); + mocks.listGroups.mockClear(); + mocks.listGroupsLive.mockClear(); + mocks.getChannelPlugin.mockClear(); resetDirectoryCache(); mocks.getChannelPlugin.mockReturnValue({ directory: {