mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-18 05:20:48 +00:00
Tests: replace local channel contracts
This commit is contained in:
@@ -1,49 +0,0 @@
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/discord";
|
||||
import { afterEach, describe, vi } from "vitest";
|
||||
import { installChannelActionsContractSuite } from "../../../src/test-utils/channel-actions-contract.js";
|
||||
import { installChannelPluginContractSuite } from "../../../src/test-utils/channel-plugin-contract.js";
|
||||
|
||||
const discordListActionsMock = vi.fn();
|
||||
const discordGetCapabilitiesMock = vi.fn();
|
||||
|
||||
vi.mock("./runtime.js", () => ({
|
||||
getDiscordRuntime: () => ({
|
||||
channel: {
|
||||
discord: {
|
||||
messageActions: {
|
||||
listActions: discordListActionsMock,
|
||||
getCapabilities: discordGetCapabilitiesMock,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
const { discordPlugin } = await import("./channel.js");
|
||||
|
||||
describe("discordPlugin contract", () => {
|
||||
afterEach(() => {
|
||||
discordListActionsMock.mockReset();
|
||||
discordGetCapabilitiesMock.mockReset();
|
||||
});
|
||||
|
||||
installChannelPluginContractSuite({
|
||||
plugin: discordPlugin,
|
||||
});
|
||||
|
||||
installChannelActionsContractSuite({
|
||||
plugin: discordPlugin,
|
||||
cases: [
|
||||
{
|
||||
name: "forwards runtime-backed Discord actions and capabilities",
|
||||
cfg: {} as OpenClawConfig,
|
||||
expectedActions: ["send", "react", "poll"],
|
||||
expectedCapabilities: ["interactive", "components"],
|
||||
beforeTest: () => {
|
||||
discordListActionsMock.mockReturnValue(["send", "react", "poll"]);
|
||||
discordGetCapabilitiesMock.mockReturnValue(["interactive", "components"]);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
@@ -1,59 +0,0 @@
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/mattermost";
|
||||
import { describe } from "vitest";
|
||||
import { installChannelActionsContractSuite } from "../../../src/test-utils/channel-actions-contract.js";
|
||||
import { installChannelPluginContractSuite } from "../../../src/test-utils/channel-plugin-contract.js";
|
||||
import { mattermostPlugin } from "./channel.js";
|
||||
|
||||
describe("mattermostPlugin contract", () => {
|
||||
installChannelPluginContractSuite({
|
||||
plugin: mattermostPlugin,
|
||||
});
|
||||
|
||||
installChannelActionsContractSuite({
|
||||
plugin: mattermostPlugin,
|
||||
unsupportedAction: "poll",
|
||||
cases: [
|
||||
{
|
||||
name: "configured account exposes send and react",
|
||||
cfg: {
|
||||
channels: {
|
||||
mattermost: {
|
||||
enabled: true,
|
||||
botToken: "test-token",
|
||||
baseUrl: "https://chat.example.com",
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: ["send", "react"],
|
||||
expectedCapabilities: ["buttons"],
|
||||
},
|
||||
{
|
||||
name: "reactions can be disabled while send stays available",
|
||||
cfg: {
|
||||
channels: {
|
||||
mattermost: {
|
||||
enabled: true,
|
||||
botToken: "test-token",
|
||||
baseUrl: "https://chat.example.com",
|
||||
actions: { reactions: false },
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: ["send"],
|
||||
expectedCapabilities: ["buttons"],
|
||||
},
|
||||
{
|
||||
name: "missing bot credentials disables the actions surface",
|
||||
cfg: {
|
||||
channels: {
|
||||
mattermost: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [],
|
||||
expectedCapabilities: [],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
@@ -1,85 +0,0 @@
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/slack";
|
||||
import { describe } from "vitest";
|
||||
import { installChannelActionsContractSuite } from "../../../src/test-utils/channel-actions-contract.js";
|
||||
import { installChannelPluginContractSuite } from "../../../src/test-utils/channel-plugin-contract.js";
|
||||
import { slackPlugin } from "./channel.js";
|
||||
|
||||
describe("slackPlugin contract", () => {
|
||||
installChannelPluginContractSuite({
|
||||
plugin: slackPlugin,
|
||||
});
|
||||
|
||||
installChannelActionsContractSuite({
|
||||
plugin: slackPlugin,
|
||||
unsupportedAction: "poll",
|
||||
cases: [
|
||||
{
|
||||
name: "configured account exposes default Slack actions",
|
||||
cfg: {
|
||||
channels: {
|
||||
slack: {
|
||||
botToken: "xoxb-test",
|
||||
appToken: "xapp-test",
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [
|
||||
"send",
|
||||
"react",
|
||||
"reactions",
|
||||
"read",
|
||||
"edit",
|
||||
"delete",
|
||||
"download-file",
|
||||
"pin",
|
||||
"unpin",
|
||||
"list-pins",
|
||||
"member-info",
|
||||
"emoji-list",
|
||||
],
|
||||
expectedCapabilities: ["blocks"],
|
||||
},
|
||||
{
|
||||
name: "interactive replies add the shared interactive capability",
|
||||
cfg: {
|
||||
channels: {
|
||||
slack: {
|
||||
botToken: "xoxb-test",
|
||||
appToken: "xapp-test",
|
||||
capabilities: {
|
||||
interactiveReplies: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [
|
||||
"send",
|
||||
"react",
|
||||
"reactions",
|
||||
"read",
|
||||
"edit",
|
||||
"delete",
|
||||
"download-file",
|
||||
"pin",
|
||||
"unpin",
|
||||
"list-pins",
|
||||
"member-info",
|
||||
"emoji-list",
|
||||
],
|
||||
expectedCapabilities: ["blocks", "interactive"],
|
||||
},
|
||||
{
|
||||
name: "missing tokens disables the actions surface",
|
||||
cfg: {
|
||||
channels: {
|
||||
slack: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expectedActions: [],
|
||||
expectedCapabilities: [],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
@@ -1,49 +0,0 @@
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/telegram";
|
||||
import { afterEach, describe, vi } from "vitest";
|
||||
import { installChannelActionsContractSuite } from "../../../src/test-utils/channel-actions-contract.js";
|
||||
import { installChannelPluginContractSuite } from "../../../src/test-utils/channel-plugin-contract.js";
|
||||
|
||||
const telegramListActionsMock = vi.fn();
|
||||
const telegramGetCapabilitiesMock = vi.fn();
|
||||
|
||||
vi.mock("./runtime.js", () => ({
|
||||
getTelegramRuntime: () => ({
|
||||
channel: {
|
||||
telegram: {
|
||||
messageActions: {
|
||||
listActions: telegramListActionsMock,
|
||||
getCapabilities: telegramGetCapabilitiesMock,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
const { telegramPlugin } = await import("./channel.js");
|
||||
|
||||
describe("telegramPlugin contract", () => {
|
||||
afterEach(() => {
|
||||
telegramListActionsMock.mockReset();
|
||||
telegramGetCapabilitiesMock.mockReset();
|
||||
});
|
||||
|
||||
installChannelPluginContractSuite({
|
||||
plugin: telegramPlugin,
|
||||
});
|
||||
|
||||
installChannelActionsContractSuite({
|
||||
plugin: telegramPlugin,
|
||||
cases: [
|
||||
{
|
||||
name: "forwards runtime-backed Telegram actions and capabilities",
|
||||
cfg: {} as OpenClawConfig,
|
||||
expectedActions: ["send", "poll", "react"],
|
||||
expectedCapabilities: ["interactive", "buttons"],
|
||||
beforeTest: () => {
|
||||
telegramListActionsMock.mockReturnValue(["send", "poll", "react"]);
|
||||
telegramGetCapabilitiesMock.mockReturnValue(["interactive", "buttons"]);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
@@ -1,53 +0,0 @@
|
||||
import { expect, it } from "vitest";
|
||||
import type { ChannelMessageCapability } from "../channels/plugins/message-capabilities.js";
|
||||
import type { ChannelMessageActionName, ChannelPlugin } from "../channels/plugins/types.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
|
||||
type ChannelActionsContractCase = {
|
||||
name: string;
|
||||
cfg: OpenClawConfig;
|
||||
expectedActions: readonly ChannelMessageActionName[];
|
||||
expectedCapabilities?: readonly ChannelMessageCapability[];
|
||||
beforeTest?: () => void;
|
||||
};
|
||||
|
||||
export function installChannelActionsContractSuite(params: {
|
||||
plugin: Pick<ChannelPlugin, "id" | "actions">;
|
||||
cases: readonly ChannelActionsContractCase[];
|
||||
unsupportedAction?: ChannelMessageActionName;
|
||||
}) {
|
||||
it("exposes the base message actions contract", () => {
|
||||
expect(params.plugin.actions).toBeDefined();
|
||||
expect(typeof params.plugin.actions?.listActions).toBe("function");
|
||||
});
|
||||
|
||||
for (const testCase of params.cases) {
|
||||
it(`actions contract: ${testCase.name}`, () => {
|
||||
testCase.beforeTest?.();
|
||||
|
||||
const actions = params.plugin.actions?.listActions?.({ cfg: testCase.cfg }) ?? [];
|
||||
const capabilities = params.plugin.actions?.getCapabilities?.({ cfg: testCase.cfg }) ?? [];
|
||||
|
||||
expect(actions).toEqual([...new Set(actions)]);
|
||||
expect(capabilities).toEqual([...new Set(capabilities)]);
|
||||
expect(actions.toSorted()).toEqual([...testCase.expectedActions].toSorted());
|
||||
expect(capabilities.toSorted()).toEqual(
|
||||
[...(testCase.expectedCapabilities ?? [])].toSorted(),
|
||||
);
|
||||
|
||||
if (params.plugin.actions?.supportsAction) {
|
||||
for (const action of testCase.expectedActions) {
|
||||
expect(params.plugin.actions.supportsAction({ action })).toBe(true);
|
||||
}
|
||||
if (
|
||||
params.unsupportedAction &&
|
||||
!testCase.expectedActions.includes(params.unsupportedAction)
|
||||
) {
|
||||
expect(params.plugin.actions.supportsAction({ action: params.unsupportedAction })).toBe(
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import { expect, it } from "vitest";
|
||||
import type { ChannelPlugin } from "../channels/plugins/types.js";
|
||||
|
||||
export function installChannelPluginContractSuite(params: {
|
||||
plugin: Pick<ChannelPlugin, "id" | "meta" | "capabilities" | "config">;
|
||||
}) {
|
||||
it("satisfies the base channel plugin contract", () => {
|
||||
const { plugin } = params;
|
||||
|
||||
expect(typeof plugin.id).toBe("string");
|
||||
expect(plugin.id.trim()).not.toBe("");
|
||||
|
||||
expect(plugin.meta.id).toBe(plugin.id);
|
||||
expect(plugin.meta.label.trim()).not.toBe("");
|
||||
expect(plugin.meta.selectionLabel.trim()).not.toBe("");
|
||||
expect(plugin.meta.docsPath).toMatch(/^\/channels\//);
|
||||
expect(plugin.meta.blurb.trim()).not.toBe("");
|
||||
|
||||
expect(plugin.capabilities.chatTypes.length).toBeGreaterThan(0);
|
||||
|
||||
expect(typeof plugin.config.listAccountIds).toBe("function");
|
||||
expect(typeof plugin.config.resolveAccount).toBe("function");
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user