From c14f4af2cc67dd3cdc29b70cd1ac48c34869ed91 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 10 May 2026 18:59:02 +0100 Subject: [PATCH] test: clear slack block send broad matchers --- extensions/slack/src/send.blocks.test.ts | 138 ++++++++++------------- 1 file changed, 61 insertions(+), 77 deletions(-) diff --git a/extensions/slack/src/send.blocks.test.ts b/extensions/slack/src/send.blocks.test.ts index a6a90edc21b..7461d1527b2 100644 --- a/extensions/slack/src/send.blocks.test.ts +++ b/extensions/slack/src/send.blocks.test.ts @@ -10,6 +10,29 @@ const { sendMessageSlack } = await import("./send.js"); const SLACK_TEST_CFG = { channels: { slack: { botToken: "xoxb-test" } } }; const SLACK_TEXT_LIMIT = 8000; +type MockCallSource = { mock: { calls: Array> } }; + +function mockObjectArg( + source: MockCallSource, + label: string, + callIndex = 0, + argIndex = 0, +): Record { + const call = source.mock.calls[callIndex]; + if (!call) { + throw new Error(`Expected ${label} call ${callIndex} to exist`); + } + const value = call[argIndex]; + if (!value || typeof value !== "object") { + throw new Error(`Expected ${label} call ${callIndex} argument ${argIndex} to be an object`); + } + return value as Record; +} + +function postedMessage(client: ReturnType, callIndex = 0) { + return mockObjectArg(client.chat.postMessage, "chat.postMessage", callIndex); +} + function slackDnsRequestError(): Error { return Object.assign(new Error("A request error occurred: getaddrinfo EAI_AGAIN slack.com"), { code: "slack_webapi_request_error", @@ -127,12 +150,8 @@ describe("sendMessageSlack chunking", () => { }); expect(client.chat.postMessage).toHaveBeenCalledTimes(1); - expect(client.chat.postMessage).toHaveBeenCalledWith( - expect.objectContaining({ - channel: "C123", - text: message, - }), - ); + expect(postedMessage(client).channel).toBe("C123"); + expect(postedMessage(client).text).toBe(message); }); it("splits oversized fallback text through the normal Slack sender", async () => { @@ -168,25 +187,19 @@ describe("sendMessageSlack blocks", () => { }); expect(client.conversations.open).not.toHaveBeenCalled(); - expect(client.chat.postMessage).toHaveBeenCalledWith( - expect.objectContaining({ - channel: "C123", - text: "Shared a Block Kit message", - blocks: [{ type: "divider" }], - }), - ); - expect(result).toMatchObject({ messageId: "171234.567", channelId: "C123" }); - expect(result.receipt).toMatchObject({ - primaryPlatformMessageId: "171234.567", - platformMessageIds: ["171234.567"], - parts: [ - expect.objectContaining({ - platformMessageId: "171234.567", - kind: "card", - raw: expect.objectContaining({ channel: "slack", channelId: "C123" }), - }), - ], - }); + const post = postedMessage(client); + expect(post.channel).toBe("C123"); + expect(post.text).toBe("Shared a Block Kit message"); + expect(post.blocks).toEqual([{ type: "divider" }]); + expect(result.messageId).toBe("171234.567"); + expect(result.channelId).toBe("C123"); + expect(result.receipt.primaryPlatformMessageId).toBe("171234.567"); + expect(result.receipt.platformMessageIds).toEqual(["171234.567"]); + const receiptPart = result.receipt.parts[0]; + expect(receiptPart?.platformMessageId).toBe("171234.567"); + expect(receiptPart?.kind).toBe("card"); + expect((receiptPart?.raw as Record | undefined)?.channel).toBe("slack"); + expect((receiptPart?.raw as Record | undefined)?.channelId).toBe("C123"); }); it("posts user-target block messages directly without conversations.open", async () => { @@ -201,13 +214,10 @@ describe("sendMessageSlack blocks", () => { }); expect(client.conversations.open).not.toHaveBeenCalled(); - expect(client.chat.postMessage).toHaveBeenCalledWith( - expect.objectContaining({ - channel: "U123", - text: "Shared a Block Kit message", - }), - ); - expect(result).toMatchObject({ messageId: "171234.567", channelId: "U123" }); + expect(postedMessage(client).channel).toBe("U123"); + expect(postedMessage(client).text).toBe("Shared a Block Kit message"); + expect(result.messageId).toBe("171234.567"); + expect(result.channelId).toBe("U123"); expect(result.receipt.platformMessageIds).toEqual(["171234.567"]); }); @@ -224,13 +234,10 @@ describe("sendMessageSlack blocks", () => { }); expect(client.chat.postMessage).toHaveBeenCalledTimes(2); - expect(result).toMatchObject({ messageId: "171234.999", channelId: "C123" }); - expect(result.receipt.parts[0]).toEqual( - expect.objectContaining({ - platformMessageId: "171234.999", - kind: "text", - }), - ); + expect(result.messageId).toBe("171234.999"); + expect(result.channelId).toBe("C123"); + expect(result.receipt.parts[0]?.platformMessageId).toBe("171234.999"); + expect(result.receipt.parts[0]?.kind).toBe("text"); }); it("retries Slack conversations.open DNS request errors for threaded DMs", async () => { @@ -247,10 +254,10 @@ describe("sendMessageSlack blocks", () => { }); expect(client.conversations.open).toHaveBeenCalledTimes(2); - expect(client.chat.postMessage).toHaveBeenCalledWith( - expect.objectContaining({ channel: "D123", thread_ts: "171234.100" }), - ); - expect(result).toMatchObject({ messageId: "171234.567", channelId: "D123" }); + expect(postedMessage(client).channel).toBe("D123"); + expect(postedMessage(client).thread_ts).toBe("171234.100"); + expect(result.messageId).toBe("171234.567"); + expect(result.channelId).toBe("D123"); expect(result.receipt.threadId).toBe("171234.100"); }); @@ -266,13 +273,9 @@ describe("sendMessageSlack blocks", () => { }); expect(client.chat.postMessage).toHaveBeenCalledTimes(2); - expect(client.chat.postMessage.mock.calls[0]?.[0]).toEqual( - expect.objectContaining({ - thread_ts: "171234.100", - reply_broadcast: true, - }), - ); - expect(client.chat.postMessage.mock.calls[1]?.[0]).not.toHaveProperty("reply_broadcast"); + expect(postedMessage(client).thread_ts).toBe("171234.100"); + expect(postedMessage(client).reply_broadcast).toBe(true); + expect(postedMessage(client, 1)).not.toHaveProperty("reply_broadcast"); }); it("does not pass reply_broadcast when no thread is selected", async () => { @@ -285,11 +288,7 @@ describe("sendMessageSlack blocks", () => { replyBroadcast: true, }); - expect(client.chat.postMessage).toHaveBeenCalledWith( - expect.not.objectContaining({ - reply_broadcast: true, - }), - ); + expect(postedMessage(client)).not.toHaveProperty("reply_broadcast"); }); it("does not retry Slack platform errors", async () => { @@ -322,11 +321,7 @@ describe("sendMessageSlack blocks", () => { blocks: [{ type: "image", image_url: "https://example.com/a.png", alt_text: "Build chart" }], }); - expect(client.chat.postMessage).toHaveBeenCalledWith( - expect.objectContaining({ - text: "Build chart", - }), - ); + expect(postedMessage(client).text).toBe("Build chart"); }); it("derives fallback text from video blocks", async () => { @@ -346,11 +341,7 @@ describe("sendMessageSlack blocks", () => { ], }); - expect(client.chat.postMessage).toHaveBeenCalledWith( - expect.objectContaining({ - text: "Release demo", - }), - ); + expect(postedMessage(client).text).toBe("Release demo"); }); it("derives fallback text from file blocks", async () => { @@ -362,11 +353,7 @@ describe("sendMessageSlack blocks", () => { blocks: [{ type: "file", source: "remote", external_id: "F123" }], }); - expect(client.chat.postMessage).toHaveBeenCalledWith( - expect.objectContaining({ - text: "Shared a file", - }), - ); + expect(postedMessage(client).text).toBe("Shared a file"); }); it("caps long fallback text while preserving blocks", async () => { @@ -390,13 +377,10 @@ describe("sendMessageSlack blocks", () => { blocks, }); - expect(client.chat.postMessage).toHaveBeenCalledWith( - expect.objectContaining({ - text: expect.stringMatching(/…$/), - blocks, - }), - ); - expect(client.chat.postMessage.mock.calls[0]?.[0].text).toHaveLength(SLACK_TEXT_LIMIT); + const post = postedMessage(client); + expect(String(post.text).endsWith("…")).toBe(true); + expect(post.blocks).toBe(blocks); + expect(post.text).toHaveLength(SLACK_TEXT_LIMIT); }); it("rejects blocks combined with mediaUrl", async () => {