test(contracts): isolate action registry

This commit is contained in:
Vincent Koc
2026-04-04 00:34:48 +09:00
parent 3d8a039149
commit e67be773d6
3 changed files with 216 additions and 216 deletions

View File

@@ -1,5 +1,6 @@
import { describe } from "vitest";
import { getActionContractRegistry, getPluginContractRegistry } from "./registry.js";
import { getActionContractRegistry } from "./registry-actions.js";
import { getPluginContractRegistry } from "./registry.js";
import { installChannelActionsContractSuite, installChannelPluginContractSuite } from "./suites.js";
for (const entry of getPluginContractRegistry()) {

View File

@@ -0,0 +1,213 @@
import type { OpenClawConfig } from "../../../config/config.js";
import { requireBundledChannelPlugin } from "../bundled.js";
import type { ChannelPlugin } from "../types.js";
type ActionsContractEntry = {
id: string;
plugin: Pick<ChannelPlugin, "id" | "actions">;
unsupportedAction?: string;
cases: Array<{
name: string;
cfg: OpenClawConfig;
expectedActions: string[];
expectedCapabilities?: string[];
beforeTest?: () => void;
}>;
};
let actionContractRegistryCache: ActionsContractEntry[] | undefined;
export function getActionContractRegistry(): ActionsContractEntry[] {
actionContractRegistryCache ??= [
{
id: "slack",
plugin: requireBundledChannelPlugin("slack"),
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",
"upload-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",
"upload-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: [],
},
],
},
{
id: "mattermost",
plugin: requireBundledChannelPlugin("mattermost"),
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: [],
},
],
},
{
id: "telegram",
plugin: requireBundledChannelPlugin("telegram"),
cases: [
{
name: "exposes configured Telegram actions and capabilities",
cfg: {
channels: {
telegram: {
botToken: "123:telegram-test-token",
},
},
} as OpenClawConfig,
expectedActions: [
"send",
"poll",
"react",
"delete",
"edit",
"topic-create",
"topic-edit",
],
expectedCapabilities: ["interactive", "buttons"],
},
],
},
{
id: "discord",
plugin: requireBundledChannelPlugin("discord"),
cases: [
{
name: "describes configured Discord actions and capabilities",
cfg: {
channels: {
discord: {
token: "Bot token-main",
actions: {
polls: true,
reactions: true,
permissions: false,
messages: false,
pins: false,
threads: false,
search: false,
stickers: false,
memberInfo: false,
roleInfo: false,
emojiUploads: false,
stickerUploads: false,
channelInfo: false,
channels: false,
voiceStatus: false,
events: false,
roles: false,
moderation: false,
presence: false,
},
},
},
} as OpenClawConfig,
expectedActions: ["send", "poll", "react", "reactions", "emoji-list"],
expectedCapabilities: ["interactive", "components"],
},
],
},
];
return actionContractRegistryCache;
}

View File

@@ -1,15 +1,10 @@
import { vi } from "vitest";
import type { OpenClawConfig } from "../../../config/config.js";
import {
listLineAccountIds,
resolveDefaultLineAccountId,
resolveLineAccount,
} from "../../../plugin-sdk/line.js";
import {
listBundledChannelPlugins,
requireBundledChannelPlugin,
setBundledChannelRuntime,
} from "../bundled.js";
import { listBundledChannelPlugins, setBundledChannelRuntime } from "../bundled.js";
import type { ChannelPlugin } from "../types.js";
import { channelPluginSurfaceKeys, type ChannelPluginSurface } from "./manifest.js";
@@ -22,19 +17,6 @@ type PluginContractEntry = {
plugin: Pick<ChannelPlugin, "id" | "meta" | "capabilities" | "config">;
};
type ActionsContractEntry = {
id: string;
plugin: Pick<ChannelPlugin, "id" | "actions">;
unsupportedAction?: string;
cases: Array<{
name: string;
cfg: OpenClawConfig;
expectedActions: string[];
expectedCapabilities?: string[];
beforeTest?: () => void;
}>;
};
type SurfaceContractEntry = {
id: string;
plugin: Pick<
@@ -93,7 +75,6 @@ vi.mock(buildBundledPluginModuleId("matrix", "runtime-api.js"), async () => {
});
let pluginContractRegistryCache: PluginContractEntry[] | undefined;
let actionContractRegistryCache: ActionsContractEntry[] | undefined;
let surfaceContractRegistryCache: SurfaceContractEntry[] | undefined;
let threadingContractRegistryCache: ThreadingContractEntry[] | undefined;
let directoryContractRegistryCache: DirectoryContractEntry[] | undefined;
@@ -106,201 +87,6 @@ export function getPluginContractRegistry(): PluginContractEntry[] {
return pluginContractRegistryCache;
}
export function getActionContractRegistry(): ActionsContractEntry[] {
actionContractRegistryCache ??= [
{
id: "slack",
plugin: requireBundledChannelPlugin("slack"),
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",
"upload-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",
"upload-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: [],
},
],
},
{
id: "mattermost",
plugin: requireBundledChannelPlugin("mattermost"),
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: [],
},
],
},
{
id: "telegram",
plugin: requireBundledChannelPlugin("telegram"),
cases: [
{
name: "exposes configured Telegram actions and capabilities",
cfg: {
channels: {
telegram: {
botToken: "123:telegram-test-token",
},
},
} as OpenClawConfig,
expectedActions: [
"send",
"poll",
"react",
"delete",
"edit",
"topic-create",
"topic-edit",
],
expectedCapabilities: ["interactive", "buttons"],
},
],
},
{
id: "discord",
plugin: requireBundledChannelPlugin("discord"),
cases: [
{
name: "describes configured Discord actions and capabilities",
cfg: {
channels: {
discord: {
token: "Bot token-main",
actions: {
polls: true,
reactions: true,
permissions: false,
messages: false,
pins: false,
threads: false,
search: false,
stickers: false,
memberInfo: false,
roleInfo: false,
emojiUploads: false,
stickerUploads: false,
channelInfo: false,
channels: false,
voiceStatus: false,
events: false,
roles: false,
moderation: false,
presence: false,
},
},
},
} as OpenClawConfig,
expectedActions: ["send", "poll", "react", "reactions", "emoji-list"],
expectedCapabilities: ["interactive", "components"],
},
],
},
];
return actionContractRegistryCache;
}
export function getSurfaceContractRegistry(): SurfaceContractEntry[] {
surfaceContractRegistryCache ??= listBundledChannelPlugins().map((plugin) => ({
id: plugin.id,