From 41e68c31dbb05f2d47f3c8b52ccedb2c964884a5 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 18 Feb 2026 13:37:50 +0000 Subject: [PATCH] test(channels): dedupe slack arg-menu and discord reply chunk assertions --- .../send.sends-basic-channel-messages.test.ts | 68 +++++++++---------- src/slack/monitor/slash.test.ts | 28 ++++---- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/discord/send.sends-basic-channel-messages.test.ts b/src/discord/send.sends-basic-channel-messages.test.ts index a765eed1f88..7720876f5d4 100644 --- a/src/discord/send.sends-basic-channel-messages.test.ts +++ b/src/discord/send.sends-basic-channel-messages.test.ts @@ -22,6 +22,32 @@ vi.mock("../web/media.js", async () => { }); describe("sendMessageDiscord", () => { + function expectReplyReference( + body: { message_reference?: unknown } | undefined, + messageId: string, + ) { + expect(body?.message_reference).toEqual({ + message_id: messageId, + fail_if_not_exists: false, + }); + } + + async function sendChunkedReplyAndCollectBodies(params: { text: string; mediaUrl?: string }) { + const { rest, postMock } = makeDiscordRest(); + postMock.mockResolvedValue({ id: "msg1", channel_id: "789" }); + await sendMessageDiscord("channel:789", params.text, { + rest, + token: "t", + replyTo: "orig-123", + ...(params.mediaUrl ? { mediaUrl: params.mediaUrl } : {}), + }); + expect(postMock).toHaveBeenCalledTimes(2); + return { + firstBody: postMock.mock.calls[0]?.[1]?.body as { message_reference?: unknown } | undefined, + secondBody: postMock.mock.calls[1]?.[1]?.body as { message_reference?: unknown } | undefined, + }; + } + beforeEach(() => { vi.clearAllMocks(); }); @@ -257,46 +283,20 @@ describe("sendMessageDiscord", () => { }); it("preserves reply reference across all text chunks", async () => { - const { rest, postMock } = makeDiscordRest(); - postMock.mockResolvedValue({ id: "msg1", channel_id: "789" }); - await sendMessageDiscord("channel:789", "a".repeat(2001), { - rest, - token: "t", - replyTo: "orig-123", - }); - expect(postMock).toHaveBeenCalledTimes(2); - const firstBody = postMock.mock.calls[0]?.[1]?.body; - const secondBody = postMock.mock.calls[1]?.[1]?.body; - expect(firstBody?.message_reference).toEqual({ - message_id: "orig-123", - fail_if_not_exists: false, - }); - expect(secondBody?.message_reference).toEqual({ - message_id: "orig-123", - fail_if_not_exists: false, + const { firstBody, secondBody } = await sendChunkedReplyAndCollectBodies({ + text: "a".repeat(2001), }); + expectReplyReference(firstBody, "orig-123"); + expectReplyReference(secondBody, "orig-123"); }); it("preserves reply reference for follow-up text chunks after media caption split", async () => { - const { rest, postMock } = makeDiscordRest(); - postMock.mockResolvedValue({ id: "msg1", channel_id: "789" }); - await sendMessageDiscord("channel:789", "a".repeat(2500), { - rest, - token: "t", + const { firstBody, secondBody } = await sendChunkedReplyAndCollectBodies({ + text: "a".repeat(2500), mediaUrl: "file:///tmp/photo.jpg", - replyTo: "orig-123", - }); - expect(postMock).toHaveBeenCalledTimes(2); - const firstBody = postMock.mock.calls[0]?.[1]?.body; - const secondBody = postMock.mock.calls[1]?.[1]?.body; - expect(firstBody?.message_reference).toEqual({ - message_id: "orig-123", - fail_if_not_exists: false, - }); - expect(secondBody?.message_reference).toEqual({ - message_id: "orig-123", - fail_if_not_exists: false, }); + expectReplyReference(firstBody, "orig-123"); + expectReplyReference(secondBody, "orig-123"); }); }); diff --git a/src/slack/monitor/slash.test.ts b/src/slack/monitor/slash.test.ts index d56ffa6f9a8..4934589a167 100644 --- a/src/slack/monitor/slash.test.ts +++ b/src/slack/monitor/slash.test.ts @@ -300,6 +300,18 @@ async function runCommandHandler(handler: (args: unknown) => Promise) { return { respond, ack }; } +function expectArgMenuLayout(respond: ReturnType): { + type: string; + elements?: Array<{ type?: string; action_id?: string; confirm?: unknown }>; +} { + expect(respond).toHaveBeenCalledTimes(1); + const payload = respond.mock.calls[0]?.[0] as { blocks?: Array<{ type: string }> }; + expect(payload.blocks?.[0]?.type).toBe("header"); + expect(payload.blocks?.[1]?.type).toBe("section"); + expect(payload.blocks?.[2]?.type).toBe("context"); + return findFirstActionsBlock(payload) ?? { type: "actions", elements: [] }; +} + async function runArgMenuAction( handler: (args: unknown) => Promise, params: { @@ -360,13 +372,7 @@ describe("Slack native command argument menus", () => { it("shows a button menu when required args are omitted", async () => { const { respond } = await runCommandHandler(usageHandler); - - expect(respond).toHaveBeenCalledTimes(1); - const payload = respond.mock.calls[0]?.[0] as { blocks?: Array<{ type: string }> }; - expect(payload.blocks?.[0]?.type).toBe("header"); - expect(payload.blocks?.[1]?.type).toBe("section"); - expect(payload.blocks?.[2]?.type).toBe("context"); - const actions = findFirstActionsBlock(payload); + const actions = expectArgMenuLayout(respond); const elementType = actions?.elements?.[0]?.type; expect(elementType).toBe("button"); expect(actions?.elements?.[0]?.confirm).toBeTruthy(); @@ -374,13 +380,7 @@ describe("Slack native command argument menus", () => { it("shows a static_select menu when choices exceed button row size", async () => { const { respond } = await runCommandHandler(reportHandler); - - expect(respond).toHaveBeenCalledTimes(1); - const payload = respond.mock.calls[0]?.[0] as { blocks?: Array<{ type: string }> }; - expect(payload.blocks?.[0]?.type).toBe("header"); - expect(payload.blocks?.[1]?.type).toBe("section"); - expect(payload.blocks?.[2]?.type).toBe("context"); - const actions = findFirstActionsBlock(payload); + const actions = expectArgMenuLayout(respond); const element = actions?.elements?.[0]; expect(element?.type).toBe("static_select"); expect(element?.action_id).toBe("openclaw_cmdarg");