diff --git a/src/gateway/server.chat.gateway-server-chat.test.ts b/src/gateway/server.chat.gateway-server-chat.test.ts index b809c57d36a..dcf2078e9ec 100644 --- a/src/gateway/server.chat.gateway-server-chat.test.ts +++ b/src/gateway/server.chat.gateway-server-chat.test.ts @@ -130,6 +130,23 @@ describe("gateway server chat", () => { }) .filter((value): value is string => typeof value === "string"); + const expectRecordFields = (value: unknown, expected: Record) => { + expect(value).toBeDefined(); + expect(typeof value).toBe("object"); + expect(value).not.toBeNull(); + const actual = value as Record; + for (const [key, expectedValue] of Object.entries(expected)) { + expect(actual[key]).toEqual(expectedValue); + } + return actual; + }; + + const expectStringRunId = (payload: unknown) => { + const actual = expectRecordFields(payload, {}); + expect(typeof actual.runId).toBe("string"); + return actual.runId as string; + }; + const expectAgentWaitTimeout = (res: Awaited>) => { expect(res.ok).toBe(true); expect(res.payload?.status).toBe("timeout"); @@ -308,7 +325,7 @@ describe("gateway server chat", () => { if (abortRes.payload?.status === "aborted") { expect(abortRes.payload?.abortedRunId).toBe("idem-sessions-abort-1"); const cancelledEvent = await cancelledEventP; - expect(cancelledEvent.payload?.data).toMatchObject({ + expectRecordFields(cancelledEvent.payload?.data, { phase: "end", status: "cancelled", aborted: true, @@ -319,7 +336,7 @@ describe("gateway server chat", () => { timeoutMs: 0, }); expect(waitRes.ok).toBe(true); - expect(waitRes.payload).toMatchObject({ + expectRecordFields(waitRes.payload, { runId: "idem-sessions-abort-1", status: "timeout", stopReason: "rpc", @@ -539,7 +556,7 @@ describe("gateway server chat", () => { CHAT_RESPONSE_TIMEOUT_MS, ); expect(imgRes.ok).toBe(true); - expect(imgRes.payload).toEqual(expect.objectContaining({ runId: expect.any(String) })); + expectStringRunId(imgRes.payload); const reqIdOnly = "chat-img-only"; ws.send( JSON.stringify({ @@ -568,7 +585,7 @@ describe("gateway server chat", () => { CHAT_RESPONSE_TIMEOUT_MS, ); expect(imgOnlyRes.ok).toBe(true); - expect(imgOnlyRes.payload).toEqual(expect.objectContaining({ runId: expect.any(String) })); + expectStringRunId(imgOnlyRes.payload); const historyDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gw-")); tempDirs.push(historyDir); @@ -804,14 +821,14 @@ describe("gateway server chat", () => { }); const sideResult = await sideResultPromise; const finalEvent = await finalPromise; - expect(sideResult.payload).toMatchObject({ + expectRecordFields(sideResult.payload, { kind: "btw", runId: "idem-btw-1", sessionKey: "agent:main:main", question: "what is 17 * 19?", text: "323", }); - expect(finalEvent.payload).toMatchObject({ + expectRecordFields(finalEvent.payload, { runId: "idem-btw-1", sessionKey: "agent:main:main", state: "final", @@ -886,7 +903,7 @@ describe("gateway server chat", () => { expect(dispatchInboundMessageMock).toHaveBeenCalled(); }); const sideResult = await sideResultPromise; - expect(sideResult.payload).toMatchObject({ + expectRecordFields(sideResult.payload, { kind: "btw", runId: "idem-btw-block-1", question: "what changed?", @@ -966,18 +983,17 @@ describe("gateway server chat", () => { throw new Error("expected assistant history message"); } const assistantContent = (assistantMessage as { content?: unknown[] }).content ?? []; - expect(assistantContent).toEqual([ - { type: "text", text: "Image reply" }, - expect.objectContaining({ - type: "image", - url: expect.stringContaining("/api/chat/media/outgoing/"), - openUrl: expect.stringContaining("/full"), - alt: "Generated image 1", - mimeType: "image/png", - width: 1, - height: 1, - }), - ]); + expect(assistantContent).toHaveLength(2); + expect(assistantContent[0]).toEqual({ type: "text", text: "Image reply" }); + const imageBlock = expectRecordFields(assistantContent[1], { + type: "image", + alt: "Generated image 1", + mimeType: "image/png", + width: 1, + height: 1, + }); + expect(String(imageBlock.url)).toContain("/api/chat/media/outgoing/"); + expect(String(imageBlock.openUrl)).toContain("/full"); const serializedAssistant = JSON.stringify(assistantMessage); expect(serializedAssistant).not.toContain("data:image/png;base64"); expect(serializedAssistant).not.toContain(pngB64);