From e67be773d60cba85eb68d27c6d6f2dd0e882d40a Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 4 Apr 2026 00:34:48 +0900 Subject: [PATCH] test(contracts): isolate action registry --- ...n-actions.registry-backed.contract.test.ts | 3 +- .../plugins/contracts/registry-actions.ts | 213 +++++++++++++++++ src/channels/plugins/contracts/registry.ts | 216 +----------------- 3 files changed, 216 insertions(+), 216 deletions(-) create mode 100644 src/channels/plugins/contracts/registry-actions.ts diff --git a/src/channels/plugins/contracts/plugin-actions.registry-backed.contract.test.ts b/src/channels/plugins/contracts/plugin-actions.registry-backed.contract.test.ts index 761e8ed65c1..9896fb56919 100644 --- a/src/channels/plugins/contracts/plugin-actions.registry-backed.contract.test.ts +++ b/src/channels/plugins/contracts/plugin-actions.registry-backed.contract.test.ts @@ -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()) { diff --git a/src/channels/plugins/contracts/registry-actions.ts b/src/channels/plugins/contracts/registry-actions.ts new file mode 100644 index 00000000000..f4761f98892 --- /dev/null +++ b/src/channels/plugins/contracts/registry-actions.ts @@ -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; + 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; +} diff --git a/src/channels/plugins/contracts/registry.ts b/src/channels/plugins/contracts/registry.ts index fc212a47745..a907d51b097 100644 --- a/src/channels/plugins/contracts/registry.ts +++ b/src/channels/plugins/contracts/registry.ts @@ -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; }; -type ActionsContractEntry = { - id: string; - plugin: Pick; - 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,