Files
openclaw/extensions/slack/src/channel.test.ts
Peter Steinberger 4320cde91d fix(slack): land #31028 from @taw0002
Co-authored-by: taw0002 <webmaster@sodsolutions.com>
2026-03-02 01:03:39 +00:00

159 lines
4.1 KiB
TypeScript

import type { OpenClawConfig } from "openclaw/plugin-sdk";
import { describe, expect, it, vi } from "vitest";
const handleSlackActionMock = vi.fn();
vi.mock("./runtime.js", () => ({
getSlackRuntime: () => ({
channel: {
slack: {
handleSlackAction: handleSlackActionMock,
},
},
}),
}));
import { slackPlugin } from "./channel.js";
describe("slackPlugin actions", () => {
it("prefers session lookup for announce target routing", () => {
expect(slackPlugin.meta.preferSessionLookupForAnnounceTarget).toBe(true);
});
it("forwards read threadId to Slack action handler", async () => {
handleSlackActionMock.mockResolvedValueOnce({ messages: [], hasMore: false });
const handleAction = slackPlugin.actions?.handleAction;
expect(handleAction).toBeDefined();
await handleAction!({
action: "read",
channel: "slack",
accountId: "default",
cfg: {},
params: {
channelId: "C123",
threadId: "1712345678.123456",
},
});
expect(handleSlackActionMock).toHaveBeenCalledWith(
expect.objectContaining({
action: "readMessages",
channelId: "C123",
threadId: "1712345678.123456",
}),
{},
undefined,
);
});
});
describe("slackPlugin outbound", () => {
const cfg = {
channels: {
slack: {
botToken: "xoxb-test",
appToken: "xapp-test",
},
},
};
it("uses threadId as threadTs fallback for sendText", async () => {
const sendSlack = vi.fn().mockResolvedValue({ messageId: "m-text" });
const sendText = slackPlugin.outbound?.sendText;
expect(sendText).toBeDefined();
const result = await sendText!({
cfg,
to: "C123",
text: "hello",
accountId: "default",
threadId: "1712345678.123456",
deps: { sendSlack },
});
expect(sendSlack).toHaveBeenCalledWith(
"C123",
"hello",
expect.objectContaining({
threadTs: "1712345678.123456",
}),
);
expect(result).toEqual({ channel: "slack", messageId: "m-text" });
});
it("prefers replyToId over threadId for sendMedia", async () => {
const sendSlack = vi.fn().mockResolvedValue({ messageId: "m-media" });
const sendMedia = slackPlugin.outbound?.sendMedia;
expect(sendMedia).toBeDefined();
const result = await sendMedia!({
cfg,
to: "C999",
text: "caption",
mediaUrl: "https://example.com/image.png",
accountId: "default",
replyToId: "1712000000.000001",
threadId: "1712345678.123456",
deps: { sendSlack },
});
expect(sendSlack).toHaveBeenCalledWith(
"C999",
"caption",
expect.objectContaining({
mediaUrl: "https://example.com/image.png",
threadTs: "1712000000.000001",
}),
);
expect(result).toEqual({ channel: "slack", messageId: "m-media" });
});
});
describe("slackPlugin config", () => {
it("treats HTTP mode accounts with bot token + signing secret as configured", async () => {
const cfg: OpenClawConfig = {
channels: {
slack: {
mode: "http",
botToken: "xoxb-http",
signingSecret: "secret-http",
},
},
};
const account = slackPlugin.config.resolveAccount(cfg, "default");
const configured = slackPlugin.config.isConfigured?.(account, cfg);
const snapshot = await slackPlugin.status?.buildAccountSnapshot?.({
account,
cfg,
runtime: undefined,
});
expect(configured).toBe(true);
expect(snapshot?.configured).toBe(true);
});
it("keeps socket mode requiring app token", async () => {
const cfg: OpenClawConfig = {
channels: {
slack: {
mode: "socket",
botToken: "xoxb-socket",
},
},
};
const account = slackPlugin.config.resolveAccount(cfg, "default");
const configured = slackPlugin.config.isConfigured?.(account, cfg);
const snapshot = await slackPlugin.status?.buildAccountSnapshot?.({
account,
cfg,
runtime: undefined,
});
expect(configured).toBe(false);
expect(snapshot?.configured).toBe(false);
});
});