mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-11 01:01:13 +00:00
137 lines
3.7 KiB
TypeScript
137 lines
3.7 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const sendMessageSlackMock = vi.hoisted(() => vi.fn());
|
|
const hasHooksMock = vi.hoisted(() => vi.fn());
|
|
const runMessageSendingMock = vi.hoisted(() => vi.fn());
|
|
|
|
vi.mock("./send.js", () => ({
|
|
sendMessageSlack: (...args: unknown[]) => sendMessageSlackMock(...args),
|
|
}));
|
|
|
|
vi.mock("openclaw/plugin-sdk/plugin-runtime", () => ({
|
|
getGlobalHookRunner: () => ({
|
|
hasHooks: (...args: unknown[]) => hasHooksMock(...args),
|
|
runMessageSending: (...args: unknown[]) => runMessageSendingMock(...args),
|
|
}),
|
|
}));
|
|
|
|
let slackOutbound: typeof import("./outbound-adapter.js").slackOutbound;
|
|
({ slackOutbound } = await import("./outbound-adapter.js"));
|
|
|
|
describe("slackOutbound", () => {
|
|
const cfg = {
|
|
channels: {
|
|
slack: {
|
|
botToken: "xoxb-test",
|
|
appToken: "xapp-test",
|
|
},
|
|
},
|
|
};
|
|
|
|
beforeEach(() => {
|
|
sendMessageSlackMock.mockReset();
|
|
hasHooksMock.mockReset();
|
|
runMessageSendingMock.mockReset();
|
|
hasHooksMock.mockReturnValue(false);
|
|
});
|
|
|
|
it("sends payload media first, then finalizes with blocks", async () => {
|
|
sendMessageSlackMock
|
|
.mockResolvedValueOnce({ messageId: "m-media-1" })
|
|
.mockResolvedValueOnce({ messageId: "m-media-2" })
|
|
.mockResolvedValueOnce({ messageId: "m-final" });
|
|
|
|
const result = await slackOutbound.sendPayload!({
|
|
cfg,
|
|
to: "C123",
|
|
text: "",
|
|
payload: {
|
|
text: "final text",
|
|
mediaUrls: ["https://example.com/1.png", "https://example.com/2.png"],
|
|
channelData: {
|
|
slack: {
|
|
blocks: [
|
|
{
|
|
type: "section",
|
|
text: { type: "plain_text", text: "Block body" },
|
|
},
|
|
],
|
|
},
|
|
},
|
|
},
|
|
mediaLocalRoots: ["/tmp/workspace"],
|
|
accountId: "default",
|
|
});
|
|
|
|
expect(sendMessageSlackMock).toHaveBeenCalledTimes(3);
|
|
expect(sendMessageSlackMock).toHaveBeenNthCalledWith(
|
|
1,
|
|
"C123",
|
|
"",
|
|
expect.objectContaining({
|
|
cfg,
|
|
mediaUrl: "https://example.com/1.png",
|
|
mediaLocalRoots: ["/tmp/workspace"],
|
|
}),
|
|
);
|
|
expect(sendMessageSlackMock).toHaveBeenNthCalledWith(
|
|
2,
|
|
"C123",
|
|
"",
|
|
expect.objectContaining({
|
|
cfg,
|
|
mediaUrl: "https://example.com/2.png",
|
|
mediaLocalRoots: ["/tmp/workspace"],
|
|
}),
|
|
);
|
|
expect(sendMessageSlackMock).toHaveBeenNthCalledWith(
|
|
3,
|
|
"C123",
|
|
"final text",
|
|
expect.objectContaining({
|
|
cfg,
|
|
blocks: [
|
|
{
|
|
type: "section",
|
|
text: { type: "plain_text", text: "Block body" },
|
|
},
|
|
],
|
|
}),
|
|
);
|
|
expect(result).toEqual({ channel: "slack", messageId: "m-final" });
|
|
});
|
|
|
|
it("cancels sendMedia when message_sending hooks block it", async () => {
|
|
hasHooksMock.mockReturnValue(true);
|
|
runMessageSendingMock.mockResolvedValue({ cancel: true });
|
|
|
|
const result = await slackOutbound.sendMedia!({
|
|
cfg,
|
|
to: "C123",
|
|
text: "caption",
|
|
mediaUrl: "https://example.com/image.png",
|
|
accountId: "default",
|
|
replyToId: "1712000000.000001",
|
|
});
|
|
|
|
expect(runMessageSendingMock).toHaveBeenCalledWith(
|
|
{
|
|
to: "C123",
|
|
content: "caption",
|
|
metadata: {
|
|
threadTs: "1712000000.000001",
|
|
channelId: "C123",
|
|
mediaUrl: "https://example.com/image.png",
|
|
},
|
|
},
|
|
{ channelId: "slack", accountId: "default" },
|
|
);
|
|
expect(sendMessageSlackMock).not.toHaveBeenCalled();
|
|
expect(result).toMatchObject({
|
|
channel: "slack",
|
|
messageId: "cancelled-by-hook",
|
|
meta: { cancelled: true },
|
|
});
|
|
});
|
|
});
|