From 3274a1b804b4d84668d86451447b89b15c1b3e40 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 21 Feb 2026 19:30:25 +0000 Subject: [PATCH] test(gateway): dedupe control-ui fixture setup and cover query asset 404 --- src/gateway/gateway-misc.test.ts | 70 ++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/src/gateway/gateway-misc.test.ts b/src/gateway/gateway-misc.test.ts index 4743a2a3649..a202e4b2915 100644 --- a/src/gateway/gateway-misc.test.ts +++ b/src/gateway/gateway-misc.test.ts @@ -46,6 +46,22 @@ vi.mock("ws", () => ({ })); describe("GatewayClient", () => { + async function withControlUiRoot( + params: { faviconSvg?: string; indexHtml?: string }, + run: (tmp: string) => Promise, + ) { + const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-ui-")); + try { + await fs.writeFile(path.join(tmp, "index.html"), params.indexHtml ?? "\n"); + if (typeof params.faviconSvg === "string") { + await fs.writeFile(path.join(tmp, "favicon.svg"), params.faviconSvg); + } + await run(tmp); + } finally { + await fs.rm(tmp, { recursive: true, force: true }); + } + } + test("uses a large maxPayload for node snapshots", () => { wsMockState.last = null; const client = new GatewayClient({ url: "ws://127.0.0.1:1" }); @@ -57,10 +73,7 @@ describe("GatewayClient", () => { }); it("returns 404 for missing static asset paths instead of SPA fallback", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-ui-")); - try { - await fs.writeFile(path.join(tmp, "index.html"), "\n"); - await fs.writeFile(path.join(tmp, "favicon.svg"), ""); + await withControlUiRoot({ faviconSvg: "" }, async (tmp) => { const { res } = makeControlUiResponse(); const handled = handleControlUiHttpRequest( { url: "/webchat/favicon.svg", method: "GET" } as IncomingMessage, @@ -69,15 +82,24 @@ describe("GatewayClient", () => { ); expect(handled).toBe(true); expect(res.statusCode).toBe(404); - } finally { - await fs.rm(tmp, { recursive: true, force: true }); - } + }); + }); + + it("returns 404 for missing static assets with query strings", async () => { + await withControlUiRoot({}, async (tmp) => { + const { res } = makeControlUiResponse(); + const handled = handleControlUiHttpRequest( + { url: "/webchat/favicon.svg?v=1", method: "GET" } as IncomingMessage, + res, + { root: { kind: "resolved", path: tmp } }, + ); + expect(handled).toBe(true); + expect(res.statusCode).toBe(404); + }); }); it("still serves SPA fallback for extensionless paths", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-ui-")); - try { - await fs.writeFile(path.join(tmp, "index.html"), "\n"); + await withControlUiRoot({}, async (tmp) => { const { res } = makeControlUiResponse(); const handled = handleControlUiHttpRequest( { url: "/webchat/chat", method: "GET" } as IncomingMessage, @@ -86,15 +108,11 @@ describe("GatewayClient", () => { ); expect(handled).toBe(true); expect(res.statusCode).toBe(200); - } finally { - await fs.rm(tmp, { recursive: true, force: true }); - } + }); }); it("HEAD returns 404 for missing static assets consistent with GET", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-ui-")); - try { - await fs.writeFile(path.join(tmp, "index.html"), "\n"); + await withControlUiRoot({}, async (tmp) => { const { res } = makeControlUiResponse(); const handled = handleControlUiHttpRequest( { url: "/webchat/favicon.svg", method: "HEAD" } as IncomingMessage, @@ -103,15 +121,11 @@ describe("GatewayClient", () => { ); expect(handled).toBe(true); expect(res.statusCode).toBe(404); - } finally { - await fs.rm(tmp, { recursive: true, force: true }); - } + }); }); it("serves SPA fallback for dotted path segments that are not static assets", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-ui-")); - try { - await fs.writeFile(path.join(tmp, "index.html"), "\n"); + await withControlUiRoot({}, async (tmp) => { for (const route of ["/webchat/user/jane.doe", "/webchat/v2.0", "/settings/v1.2"]) { const { res } = makeControlUiResponse(); const handled = handleControlUiHttpRequest( @@ -122,15 +136,11 @@ describe("GatewayClient", () => { expect(handled).toBe(true); expect(res.statusCode, `expected 200 for ${route}`).toBe(200); } - } finally { - await fs.rm(tmp, { recursive: true, force: true }); - } + }); }); it("serves SPA fallback for .html paths that do not exist on disk", async () => { - const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-ui-")); - try { - await fs.writeFile(path.join(tmp, "index.html"), "\n"); + await withControlUiRoot({}, async (tmp) => { const { res } = makeControlUiResponse(); const handled = handleControlUiHttpRequest( { url: "/webchat/foo.html", method: "GET" } as IncomingMessage, @@ -139,9 +149,7 @@ describe("GatewayClient", () => { ); expect(handled).toBe(true); expect(res.statusCode).toBe(200); - } finally { - await fs.rm(tmp, { recursive: true, force: true }); - } + }); }); });