From 5ce2ed3bd274fa32983b55638bcc7fa6a19a7b02 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 17 Mar 2026 04:36:18 +0000 Subject: [PATCH] refactor(telegram): share native command test fixtures --- ...ot-native-commands.fixture-test-support.ts | 128 ++++++++++++++++++ .../bot-native-commands.menu-test-support.ts | 96 ++----------- .../bot-native-commands.session-meta.test.ts | 119 +++------------- .../src/bot-native-commands.test-helpers.ts | 50 +------ 4 files changed, 166 insertions(+), 227 deletions(-) create mode 100644 extensions/telegram/src/bot-native-commands.fixture-test-support.ts diff --git a/extensions/telegram/src/bot-native-commands.fixture-test-support.ts b/extensions/telegram/src/bot-native-commands.fixture-test-support.ts new file mode 100644 index 00000000000..ab2439d65ec --- /dev/null +++ b/extensions/telegram/src/bot-native-commands.fixture-test-support.ts @@ -0,0 +1,128 @@ +import { vi } from "vitest"; +import type { OpenClawConfig } from "../../../src/config/config.js"; +import type { TelegramAccountConfig } from "../../../src/config/types.js"; +import type { RuntimeEnv } from "../../../src/runtime.js"; + +export type NativeCommandTestParams = { + bot: { + api: { + setMyCommands: ReturnType; + sendMessage: ReturnType; + }; + command: ReturnType; + }; + cfg: OpenClawConfig; + runtime: RuntimeEnv; + accountId: string; + telegramCfg: TelegramAccountConfig; + allowFrom: string[]; + groupAllowFrom: string[]; + replyToMode: string; + textLimit: number; + useAccessGroups: boolean; + nativeEnabled: boolean; + nativeSkillsEnabled: boolean; + nativeDisabledExplicit: boolean; + resolveGroupPolicy: () => { allowlistEnabled: boolean; allowed: boolean }; + resolveTelegramGroupConfig: () => { + groupConfig: undefined; + topicConfig: undefined; + }; + shouldSkipUpdate: () => boolean; + opts: { token: string }; +}; + +export function createDeferred() { + let resolve!: (value: T | PromiseLike) => void; + const promise = new Promise((res) => { + resolve = res; + }); + return { promise, resolve }; +} + +export function createNativeCommandTestParams( + params: Partial = {}, +): NativeCommandTestParams { + const log = vi.fn(); + return { + bot: + params.bot ?? + ({ + api: { + setMyCommands: vi.fn().mockResolvedValue(undefined), + sendMessage: vi.fn().mockResolvedValue(undefined), + }, + command: vi.fn(), + } as NativeCommandTestParams["bot"]), + cfg: params.cfg ?? ({} as OpenClawConfig), + runtime: params.runtime ?? ({ log } as RuntimeEnv), + accountId: params.accountId ?? "default", + telegramCfg: params.telegramCfg ?? ({} as TelegramAccountConfig), + allowFrom: params.allowFrom ?? [], + groupAllowFrom: params.groupAllowFrom ?? [], + replyToMode: params.replyToMode ?? "off", + textLimit: params.textLimit ?? 4000, + useAccessGroups: params.useAccessGroups ?? false, + nativeEnabled: params.nativeEnabled ?? true, + nativeSkillsEnabled: params.nativeSkillsEnabled ?? false, + nativeDisabledExplicit: params.nativeDisabledExplicit ?? false, + resolveGroupPolicy: + params.resolveGroupPolicy ?? + (() => + ({ + allowlistEnabled: false, + allowed: true, + }) as ReturnType), + resolveTelegramGroupConfig: + params.resolveTelegramGroupConfig ?? + (() => ({ groupConfig: undefined, topicConfig: undefined })), + shouldSkipUpdate: params.shouldSkipUpdate ?? (() => false), + opts: params.opts ?? { token: "token" }, + }; +} + +export function createTelegramPrivateCommandContext(params?: { + match?: string; + messageId?: number; + date?: number; + chatId?: number; + userId?: number; + username?: string; +}) { + return { + match: params?.match ?? "", + message: { + message_id: params?.messageId ?? 1, + date: params?.date ?? Math.floor(Date.now() / 1000), + chat: { id: params?.chatId ?? 100, type: "private" as const }, + from: { id: params?.userId ?? 200, username: params?.username ?? "bob" }, + }, + }; +} + +export function createTelegramTopicCommandContext(params?: { + match?: string; + messageId?: number; + date?: number; + chatId?: number; + title?: string; + threadId?: number; + userId?: number; + username?: string; +}) { + return { + match: params?.match ?? "", + message: { + message_id: params?.messageId ?? 2, + date: params?.date ?? Math.floor(Date.now() / 1000), + chat: { + id: params?.chatId ?? -1001234567890, + type: "supergroup" as const, + title: params?.title ?? "OpenClaw", + is_forum: true, + }, + message_thread_id: params?.threadId ?? 42, + from: { id: params?.userId ?? 200, username: params?.username ?? "bob" }, + }, + }; +} diff --git a/extensions/telegram/src/bot-native-commands.menu-test-support.ts b/extensions/telegram/src/bot-native-commands.menu-test-support.ts index 9af54d3d1bc..241c50ac6be 100644 --- a/extensions/telegram/src/bot-native-commands.menu-test-support.ts +++ b/extensions/telegram/src/bot-native-commands.menu-test-support.ts @@ -1,38 +1,11 @@ import { expect, vi } from "vitest"; import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { TelegramAccountConfig } from "../../../src/config/types.js"; import type { RuntimeEnv } from "../../../src/runtime.js"; - -type NativeCommandBot = { - api: { - setMyCommands: ReturnType; - sendMessage: ReturnType; - }; - command: ReturnType; -}; - -type RegisterTelegramNativeCommandsParams = { - bot: NativeCommandBot; - cfg: OpenClawConfig; - runtime: RuntimeEnv; - accountId: string; - telegramCfg: TelegramAccountConfig; - allowFrom: string[]; - groupAllowFrom: string[]; - replyToMode: string; - textLimit: number; - useAccessGroups: boolean; - nativeEnabled: boolean; - nativeSkillsEnabled: boolean; - nativeDisabledExplicit: boolean; - resolveGroupPolicy: () => { allowlistEnabled: boolean; allowed: boolean }; - resolveTelegramGroupConfig: () => { - groupConfig: undefined; - topicConfig: undefined; - }; - shouldSkipUpdate: () => boolean; - opts: { token: string }; -}; +import { + createNativeCommandTestParams as createBaseNativeCommandTestParams, + createTelegramPrivateCommandContext, + type NativeCommandTestParams as RegisterTelegramNativeCommandsParams, +} from "./bot-native-commands.fixture-test-support.js"; type RegisteredCommand = { command: string; @@ -98,61 +71,12 @@ export function createNativeCommandTestParams( cfg: OpenClawConfig, params: Partial = {}, ): RegisterTelegramNativeCommandsParams { - return { - bot: - params.bot ?? - ({ - api: { - setMyCommands: vi.fn().mockResolvedValue(undefined), - sendMessage: vi.fn().mockResolvedValue(undefined), - }, - command: vi.fn(), - } as unknown as RegisterTelegramNativeCommandsParams["bot"]), + return createBaseNativeCommandTestParams({ cfg, runtime: params.runtime ?? ({} as RuntimeEnv), - accountId: params.accountId ?? "default", - telegramCfg: params.telegramCfg ?? ({} as TelegramAccountConfig), - allowFrom: params.allowFrom ?? [], - groupAllowFrom: params.groupAllowFrom ?? [], - replyToMode: params.replyToMode ?? "off", - textLimit: params.textLimit ?? 4000, - useAccessGroups: params.useAccessGroups ?? false, - nativeEnabled: params.nativeEnabled ?? true, - nativeSkillsEnabled: params.nativeSkillsEnabled ?? true, - nativeDisabledExplicit: params.nativeDisabledExplicit ?? false, - resolveGroupPolicy: - params.resolveGroupPolicy ?? - (() => - ({ - allowlistEnabled: false, - allowed: true, - }) as ReturnType), - resolveTelegramGroupConfig: - params.resolveTelegramGroupConfig ?? - (() => ({ - groupConfig: undefined, - topicConfig: undefined, - })), - shouldSkipUpdate: params.shouldSkipUpdate ?? (() => false), - opts: params.opts ?? { token: "token" }, - }; + nativeSkillsEnabled: true, + ...params, + }); } -export function createPrivateCommandContext(params?: { - match?: string; - messageId?: number; - date?: number; - chatId?: number; - userId?: number; - username?: string; -}) { - return { - match: params?.match ?? "", - message: { - message_id: params?.messageId ?? 1, - date: params?.date ?? Math.floor(Date.now() / 1000), - chat: { id: params?.chatId ?? 123, type: "private" as const }, - from: { id: params?.userId ?? 456, username: params?.username ?? "alice" }, - }, - }; -} +export { createTelegramPrivateCommandContext as createPrivateCommandContext }; diff --git a/extensions/telegram/src/bot-native-commands.session-meta.test.ts b/extensions/telegram/src/bot-native-commands.session-meta.test.ts index 6160afccf01..0a75b12fc1a 100644 --- a/extensions/telegram/src/bot-native-commands.session-meta.test.ts +++ b/extensions/telegram/src/bot-native-commands.session-meta.test.ts @@ -1,12 +1,17 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import type { OpenClawConfig } from "../../../src/config/config.js"; +import { + createDeferred, + createNativeCommandTestParams, + createTelegramPrivateCommandContext, + createTelegramTopicCommandContext, + type NativeCommandTestParams, +} from "./bot-native-commands.fixture-test-support.js"; import { registerTelegramNativeCommands, type RegisterTelegramHandlerParams, } from "./bot-native-commands.js"; -type RegisterTelegramNativeCommandsParams = Parameters[0]; - // All mocks scoped to this file only — does not affect bot-native-commands.test.ts type ResolveConfiguredAcpBindingRecordFn = @@ -101,93 +106,13 @@ vi.mock("./bot/delivery.js", () => ({ deliverReplies: deliveryMocks.deliverReplies, })); -function createDeferred() { - let resolve!: (value: T | PromiseLike) => void; - const promise = new Promise((res) => { - resolve = res; - }); - return { promise, resolve }; -} - -function createNativeCommandTestParams( - params: Partial = {}, -): RegisterTelegramNativeCommandsParams { - const log = vi.fn(); - return { - bot: - params.bot ?? - ({ - api: { - setMyCommands: vi.fn().mockResolvedValue(undefined), - sendMessage: vi.fn().mockResolvedValue(undefined), - }, - command: vi.fn(), - } as unknown as RegisterTelegramNativeCommandsParams["bot"]), - cfg: params.cfg ?? ({} as OpenClawConfig), - runtime: - params.runtime ?? ({ log } as unknown as RegisterTelegramNativeCommandsParams["runtime"]), - accountId: params.accountId ?? "default", - telegramCfg: params.telegramCfg ?? ({} as RegisterTelegramNativeCommandsParams["telegramCfg"]), - allowFrom: params.allowFrom ?? [], - groupAllowFrom: params.groupAllowFrom ?? [], - replyToMode: params.replyToMode ?? "off", - textLimit: params.textLimit ?? 4000, - useAccessGroups: params.useAccessGroups ?? false, - nativeEnabled: params.nativeEnabled ?? true, - nativeSkillsEnabled: params.nativeSkillsEnabled ?? false, - nativeDisabledExplicit: params.nativeDisabledExplicit ?? false, - resolveGroupPolicy: - params.resolveGroupPolicy ?? - (() => - ({ - allowlistEnabled: false, - allowed: true, - }) as ReturnType), - resolveTelegramGroupConfig: - params.resolveTelegramGroupConfig ?? - (() => ({ groupConfig: undefined, topicConfig: undefined })), - shouldSkipUpdate: params.shouldSkipUpdate ?? (() => false), - opts: params.opts ?? { token: "token" }, - }; -} - type TelegramCommandHandler = (ctx: unknown) => Promise; -function buildStatusCommandContext() { - return { - match: "", - message: { - message_id: 1, - date: Math.floor(Date.now() / 1000), - chat: { id: 100, type: "private" as const }, - from: { id: 200, username: "bob" }, - }, - }; -} - -function buildStatusTopicCommandContext() { - return { - match: "", - message: { - message_id: 2, - date: Math.floor(Date.now() / 1000), - chat: { - id: -1001234567890, - type: "supergroup" as const, - title: "OpenClaw", - is_forum: true, - }, - message_thread_id: 42, - from: { id: 200, username: "bob" }, - }, - }; -} - function registerAndResolveStatusHandler(params: { cfg: OpenClawConfig; allowFrom?: string[]; groupAllowFrom?: string[]; - telegramCfg?: RegisterTelegramNativeCommandsParams["telegramCfg"]; + telegramCfg?: NativeCommandTestParams["telegramCfg"]; resolveTelegramGroupConfig?: RegisterTelegramHandlerParams["resolveTelegramGroupConfig"]; }): { handler: TelegramCommandHandler; @@ -211,7 +136,7 @@ function registerAndResolveCommandHandlerBase(params: { allowFrom: string[]; groupAllowFrom: string[]; useAccessGroups: boolean; - telegramCfg?: RegisterTelegramNativeCommandsParams["telegramCfg"]; + telegramCfg?: NativeCommandTestParams["telegramCfg"]; resolveTelegramGroupConfig?: RegisterTelegramHandlerParams["resolveTelegramGroupConfig"]; }): { handler: TelegramCommandHandler; @@ -238,7 +163,7 @@ function registerAndResolveCommandHandlerBase(params: { command: vi.fn((name: string, cb: TelegramCommandHandler) => { commandHandlers.set(name, cb); }), - } as unknown as Parameters[0]["bot"], + } as unknown as NativeCommandTestParams["bot"], cfg, allowFrom, groupAllowFrom, @@ -259,7 +184,7 @@ function registerAndResolveCommandHandler(params: { allowFrom?: string[]; groupAllowFrom?: string[]; useAccessGroups?: boolean; - telegramCfg?: RegisterTelegramNativeCommandsParams["telegramCfg"]; + telegramCfg?: NativeCommandTestParams["telegramCfg"]; resolveTelegramGroupConfig?: RegisterTelegramHandlerParams["resolveTelegramGroupConfig"]; }): { handler: TelegramCommandHandler; @@ -344,7 +269,7 @@ describe("registerTelegramNativeCommands — session metadata", () => { it("calls recordSessionMetaFromInbound after a native slash command", async () => { const cfg: OpenClawConfig = {}; const { handler } = registerAndResolveStatusHandler({ cfg }); - await handler(buildStatusCommandContext()); + await handler(createTelegramPrivateCommandContext()); expect(sessionMocks.recordSessionMetaFromInbound).toHaveBeenCalledTimes(1); const call = ( @@ -363,7 +288,7 @@ describe("registerTelegramNativeCommands — session metadata", () => { const cfg: OpenClawConfig = {}; const { handler } = registerAndResolveStatusHandler({ cfg }); - const runPromise = handler(buildStatusCommandContext()); + const runPromise = handler(createTelegramPrivateCommandContext()); await vi.waitFor(() => { expect(sessionMocks.recordSessionMetaFromInbound).toHaveBeenCalledTimes(1); @@ -402,7 +327,7 @@ describe("registerTelegramNativeCommands — session metadata", () => { }, }, }); - await handler(buildStatusCommandContext()); + await handler(createTelegramPrivateCommandContext()); const deliveredCall = deliveryMocks.deliverReplies.mock.calls[0]?.[0] as | DeliverRepliesParams @@ -446,7 +371,7 @@ describe("registerTelegramNativeCommands — session metadata", () => { }, }, }); - await handler(buildStatusCommandContext()); + await handler(createTelegramPrivateCommandContext()); expect(deliveryMocks.deliverReplies).not.toHaveBeenCalled(); }); @@ -463,7 +388,7 @@ describe("registerTelegramNativeCommands — session metadata", () => { cfg: {}, telegramCfg: { silentErrorReplies: true }, }); - await handler(buildStatusCommandContext()); + await handler(createTelegramPrivateCommandContext()); const deliveredCall = deliveryMocks.deliverReplies.mock.calls[0]?.[0] as | DeliverRepliesParams @@ -491,7 +416,7 @@ describe("registerTelegramNativeCommands — session metadata", () => { allowFrom: ["200"], groupAllowFrom: ["200"], }); - await handler(buildStatusTopicCommandContext()); + await handler(createTelegramTopicCommandContext()); expect(persistentBindingMocks.resolveConfiguredAcpBindingRecord).toHaveBeenCalledTimes(1); expect(persistentBindingMocks.ensureConfiguredAcpBindingSession).toHaveBeenCalledTimes(1); @@ -519,7 +444,7 @@ describe("registerTelegramNativeCommands — session metadata", () => { topicConfig: { agentId: "zu" }, }), }); - await handler(buildStatusTopicCommandContext()); + await handler(createTelegramTopicCommandContext()); const dispatchCall = ( replyMocks.dispatchReplyWithBufferedBlockDispatcher.mock.calls as unknown as Array< @@ -542,7 +467,7 @@ describe("registerTelegramNativeCommands — session metadata", () => { allowFrom: ["200"], groupAllowFrom: ["200"], }); - await handler(buildStatusTopicCommandContext()); + await handler(createTelegramTopicCommandContext()); expect(sessionBindingMocks.resolveByConversation).toHaveBeenCalledWith({ channel: "telegram", @@ -577,7 +502,7 @@ describe("registerTelegramNativeCommands — session metadata", () => { allowFrom: ["200"], groupAllowFrom: ["200"], }); - await handler(buildStatusTopicCommandContext()); + await handler(createTelegramTopicCommandContext()); expect(replyMocks.dispatchReplyWithBufferedBlockDispatcher).not.toHaveBeenCalled(); expect(sendMessage).toHaveBeenCalledWith( @@ -604,7 +529,7 @@ describe("registerTelegramNativeCommands — session metadata", () => { groupAllowFrom: [], useAccessGroups: true, }); - await handler(buildStatusTopicCommandContext()); + await handler(createTelegramTopicCommandContext()); expectUnauthorizedNewCommandBlocked(sendMessage); }); @@ -619,7 +544,7 @@ describe("registerTelegramNativeCommands — session metadata", () => { groupAllowFrom: [], useAccessGroups: true, }); - await handler(buildStatusTopicCommandContext()); + await handler(createTelegramTopicCommandContext()); expectUnauthorizedNewCommandBlocked(sendMessage); }); diff --git a/extensions/telegram/src/bot-native-commands.test-helpers.ts b/extensions/telegram/src/bot-native-commands.test-helpers.ts index a39bdd23da6..f443040b17d 100644 --- a/extensions/telegram/src/bot-native-commands.test-helpers.ts +++ b/extensions/telegram/src/bot-native-commands.test-helpers.ts @@ -4,9 +4,12 @@ import type { TelegramAccountConfig } from "openclaw/plugin-sdk/config-runtime"; import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import type { MockFn } from "openclaw/plugin-sdk/test-utils"; import { vi } from "vitest"; +import { + createNativeCommandTestParams, + type NativeCommandTestParams, +} from "./bot-native-commands.fixture-test-support.js"; import { registerTelegramNativeCommands } from "./bot-native-commands.js"; -type RegisterTelegramNativeCommandsParams = Parameters[0]; type GetPluginCommandSpecsFn = typeof import("openclaw/plugin-sdk/plugin-runtime").getPluginCommandSpecs; type MatchPluginCommandFn = typeof import("openclaw/plugin-sdk/plugin-runtime").matchPluginCommand; @@ -89,48 +92,7 @@ vi.mock("./bot/delivery.js", () => ({ deliverReplies: deliveryMocks.deliverRepli vi.mock("openclaw/plugin-sdk/conversation-runtime", () => ({ readChannelAllowFromStore: vi.fn(async () => []), })); - -export function createNativeCommandTestParams( - params: Partial = {}, -): RegisterTelegramNativeCommandsParams { - const log = vi.fn(); - return { - bot: - params.bot ?? - ({ - api: { - setMyCommands: vi.fn().mockResolvedValue(undefined), - sendMessage: vi.fn().mockResolvedValue(undefined), - }, - command: vi.fn(), - } as unknown as RegisterTelegramNativeCommandsParams["bot"]), - cfg: params.cfg ?? ({} as OpenClawConfig), - runtime: - params.runtime ?? ({ log } as unknown as RegisterTelegramNativeCommandsParams["runtime"]), - accountId: params.accountId ?? "default", - telegramCfg: params.telegramCfg ?? ({} as RegisterTelegramNativeCommandsParams["telegramCfg"]), - allowFrom: params.allowFrom ?? [], - groupAllowFrom: params.groupAllowFrom ?? [], - replyToMode: params.replyToMode ?? "off", - textLimit: params.textLimit ?? 4000, - useAccessGroups: params.useAccessGroups ?? false, - nativeEnabled: params.nativeEnabled ?? true, - nativeSkillsEnabled: params.nativeSkillsEnabled ?? false, - nativeDisabledExplicit: params.nativeDisabledExplicit ?? false, - resolveGroupPolicy: - params.resolveGroupPolicy ?? - (() => - ({ - allowlistEnabled: false, - allowed: true, - }) as ReturnType), - resolveTelegramGroupConfig: - params.resolveTelegramGroupConfig ?? - (() => ({ groupConfig: undefined, topicConfig: undefined })), - shouldSkipUpdate: params.shouldSkipUpdate ?? (() => false), - opts: params.opts ?? { token: "token" }, - }; -} +export { createNativeCommandTestParams }; export function createNativeCommandsHarness(params?: { cfg?: OpenClawConfig; @@ -158,7 +120,7 @@ export function createNativeCommandsHarness(params?: { } as const; registerTelegramNativeCommands({ - bot: bot as unknown as Parameters[0]["bot"], + bot: bot as unknown as NativeCommandTestParams["bot"], cfg: params?.cfg ?? ({} as OpenClawConfig), runtime: params?.runtime ?? ({ log } as unknown as RuntimeEnv), accountId: "default",