From def3a3ced1fa54e57e551e72a83b9823cf66f43d Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 16 Feb 2026 16:02:18 +0000 Subject: [PATCH] refactor(test): reduce auth and channel setup duplication --- src/commands/auth-choice.e2e.test.ts | 106 ++++++------------ src/commands/channel-test-helpers.ts | 20 ++++ ...s-non-default-telegram-account.e2e.test.ts | 20 +--- src/commands/onboard-channels.e2e.test.ts | 20 +--- 4 files changed, 59 insertions(+), 107 deletions(-) create mode 100644 src/commands/channel-test-helpers.ts diff --git a/src/commands/auth-choice.e2e.test.ts b/src/commands/auth-choice.e2e.test.ts index b2344e11654..3591e2c6bd5 100644 --- a/src/commands/auth-choice.e2e.test.ts +++ b/src/commands/auth-choice.e2e.test.ts @@ -65,6 +65,29 @@ describe("applyAuthChoice", () => { function createPrompter(overrides: Partial): WizardPrompter { return createWizardPrompter(overrides, { defaultSelect: "" }); } + function createSelectFirstOption(): WizardPrompter["select"] { + return vi.fn(async (params) => params.options[0]?.value as never); + } + function createNoopMultiselect(): WizardPrompter["multiselect"] { + return vi.fn(async () => []); + } + function createApiKeyPromptHarness( + overrides: Partial> = {}, + ): { + select: WizardPrompter["select"]; + multiselect: WizardPrompter["multiselect"]; + prompter: WizardPrompter; + runtime: ReturnType; + } { + const select = overrides.select ?? createSelectFirstOption(); + const multiselect = overrides.multiselect ?? createNoopMultiselect(); + return { + select, + multiselect, + prompter: createPrompter({ ...overrides, select, multiselect }), + runtime: createExitThrowingRuntime(), + }; + } async function readAuthProfiles() { return await readAuthProfilesForAgent<{ profiles?: Record; @@ -109,12 +132,7 @@ describe("applyAuthChoice", () => { await setupTempState(); const text = vi.fn().mockResolvedValue("sk-minimax-test"); - const select: WizardPrompter["select"] = vi.fn( - async (params) => params.options[0]?.value as never, - ); - const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []); - const prompter = createPrompter({ select, multiselect, text }); - const runtime = createExitThrowingRuntime(); + const { prompter, runtime } = createApiKeyPromptHarness({ text }); const result = await applyAuthChoice({ authChoice: "minimax-api", @@ -139,12 +157,7 @@ describe("applyAuthChoice", () => { await setupTempState(); const text = vi.fn().mockResolvedValue("sk-minimax-test"); - const select: WizardPrompter["select"] = vi.fn( - async (params) => params.options[0]?.value as never, - ); - const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []); - const prompter = createPrompter({ select, multiselect, text }); - const runtime = createExitThrowingRuntime(); + const { prompter, runtime } = createApiKeyPromptHarness({ text }); const result = await applyAuthChoice({ authChoice: "minimax-api-key-cn", @@ -170,12 +183,7 @@ describe("applyAuthChoice", () => { await setupTempState(); const text = vi.fn().mockResolvedValue("sk-synthetic-test"); - const select: WizardPrompter["select"] = vi.fn( - async (params) => params.options[0]?.value as never, - ); - const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []); - const prompter = createPrompter({ select, multiselect, text }); - const runtime = createExitThrowingRuntime(); + const { prompter, runtime } = createApiKeyPromptHarness({ text }); const result = await applyAuthChoice({ authChoice: "synthetic-api-key", @@ -200,12 +208,7 @@ describe("applyAuthChoice", () => { await setupTempState(); const text = vi.fn().mockResolvedValue("hf-test-token"); - const select: WizardPrompter["select"] = vi.fn( - async (params) => params.options[0]?.value as never, - ); - const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []); - const prompter = createPrompter({ select, multiselect, text }); - const runtime = createExitThrowingRuntime(); + const { prompter, runtime } = createApiKeyPromptHarness({ text }); const result = await applyAuthChoice({ authChoice: "huggingface-api-key", @@ -295,13 +298,8 @@ describe("applyAuthChoice", () => { delete process.env.HUGGINGFACE_HUB_TOKEN; const text = vi.fn().mockResolvedValue("should-not-be-used"); - const select: WizardPrompter["select"] = vi.fn( - async (params) => params.options[0]?.value as never, - ); - const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []); const confirm = vi.fn(async () => false); - const prompter = createPrompter({ select, multiselect, text, confirm }); - const runtime = createExitThrowingRuntime(); + const { prompter, runtime } = createApiKeyPromptHarness({ text, confirm }); const result = await applyAuthChoice({ authChoice: "apiKey", @@ -328,12 +326,7 @@ describe("applyAuthChoice", () => { await setupTempState(); const text = vi.fn().mockResolvedValue("sk-xai-test"); - const select: WizardPrompter["select"] = vi.fn( - async (params) => params.options[0]?.value as never, - ); - const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []); - const prompter = createPrompter({ select, multiselect, text }); - const runtime = createExitThrowingRuntime(); + const { prompter, runtime } = createApiKeyPromptHarness({ text }); const result = await applyAuthChoice({ authChoice: "xai-api-key", @@ -393,12 +386,7 @@ describe("applyAuthChoice", () => { await setupTempState(); const text = vi.fn().mockResolvedValue("sk-opencode-zen-test"); - const select: WizardPrompter["select"] = vi.fn( - async (params) => params.options[0]?.value as never, - ); - const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []); - const prompter = createPrompter({ select, multiselect, text }); - const runtime = createExitThrowingRuntime(); + const { prompter, runtime } = createApiKeyPromptHarness({ text }); const result = await applyAuthChoice({ authChoice: "opencode-zen", @@ -477,13 +465,8 @@ describe("applyAuthChoice", () => { process.env.OPENROUTER_API_KEY = "sk-openrouter-test"; const text = vi.fn(); - const select: WizardPrompter["select"] = vi.fn( - async (params) => params.options[0]?.value as never, - ); - const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []); const confirm = vi.fn(async () => true); - const prompter = createPrompter({ select, multiselect, text, confirm }); - const runtime = createExitThrowingRuntime(); + const { prompter, runtime } = createApiKeyPromptHarness({ text, confirm }); const result = await applyAuthChoice({ authChoice: "openrouter-api-key", @@ -537,13 +520,8 @@ describe("applyAuthChoice", () => { ); const text = vi.fn(); - const select: WizardPrompter["select"] = vi.fn( - async (params) => params.options[0]?.value as never, - ); - const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []); const confirm = vi.fn(async () => true); - const prompter = createPrompter({ select, multiselect, text, confirm }); - const runtime = createExitThrowingRuntime(); + const { prompter, runtime } = createApiKeyPromptHarness({ text, confirm }); const result = await applyAuthChoice({ authChoice: "litellm-api-key", @@ -582,13 +560,8 @@ describe("applyAuthChoice", () => { process.env.AI_GATEWAY_API_KEY = "gateway-test-key"; const text = vi.fn(); - const select: WizardPrompter["select"] = vi.fn( - async (params) => params.options[0]?.value as never, - ); - const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []); const confirm = vi.fn(async () => true); - const prompter = createPrompter({ select, multiselect, text, confirm }); - const runtime = createExitThrowingRuntime(); + const { prompter, runtime } = createApiKeyPromptHarness({ text, confirm }); const result = await applyAuthChoice({ authChoice: "ai-gateway-api-key", @@ -625,13 +598,8 @@ describe("applyAuthChoice", () => { .fn() .mockResolvedValueOnce("cf-account-id") .mockResolvedValueOnce("cf-gateway-id"); - const select: WizardPrompter["select"] = vi.fn( - async (params) => params.options[0]?.value as never, - ); - const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []); const confirm = vi.fn(async () => true); - const prompter = createPrompter({ select, multiselect, text, confirm }); - const runtime = createExitThrowingRuntime(); + const { prompter, runtime } = createApiKeyPromptHarness({ text, confirm }); const result = await applyAuthChoice({ authChoice: "cloudflare-ai-gateway-api-key", @@ -707,11 +675,7 @@ describe("applyAuthChoice", () => { } return "code_manual"; }); - const select: WizardPrompter["select"] = vi.fn( - async (params) => params.options[0]?.value as never, - ); - const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []); - const prompter = createPrompter({ select, multiselect, text }); + const { prompter } = createApiKeyPromptHarness({ text }); const result = await applyAuthChoice({ authChoice: "chutes", diff --git a/src/commands/channel-test-helpers.ts b/src/commands/channel-test-helpers.ts new file mode 100644 index 00000000000..fd7e6f36278 --- /dev/null +++ b/src/commands/channel-test-helpers.ts @@ -0,0 +1,20 @@ +import { discordPlugin } from "../../extensions/discord/src/channel.js"; +import { imessagePlugin } from "../../extensions/imessage/src/channel.js"; +import { signalPlugin } from "../../extensions/signal/src/channel.js"; +import { slackPlugin } from "../../extensions/slack/src/channel.js"; +import { telegramPlugin } from "../../extensions/telegram/src/channel.js"; +import { whatsappPlugin } from "../../extensions/whatsapp/src/channel.js"; +import { setActivePluginRegistry } from "../plugins/runtime.js"; +import { createTestRegistry } from "../test-utils/channel-plugins.js"; + +export function setDefaultChannelPluginRegistryForTests(): void { + const channels = [ + { pluginId: "discord", plugin: discordPlugin, source: "test" }, + { pluginId: "slack", plugin: slackPlugin, source: "test" }, + { pluginId: "telegram", plugin: telegramPlugin, source: "test" }, + { pluginId: "whatsapp", plugin: whatsappPlugin, source: "test" }, + { pluginId: "signal", plugin: signalPlugin, source: "test" }, + { pluginId: "imessage", plugin: imessagePlugin, source: "test" }, + ] as unknown as Parameters[0]; + setActivePluginRegistry(createTestRegistry(channels)); +} diff --git a/src/commands/channels.adds-non-default-telegram-account.e2e.test.ts b/src/commands/channels.adds-non-default-telegram-account.e2e.test.ts index d0f3ee1148e..c73120c39d4 100644 --- a/src/commands/channels.adds-non-default-telegram-account.e2e.test.ts +++ b/src/commands/channels.adds-non-default-telegram-account.e2e.test.ts @@ -1,12 +1,5 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import { discordPlugin } from "../../extensions/discord/src/channel.js"; -import { imessagePlugin } from "../../extensions/imessage/src/channel.js"; -import { signalPlugin } from "../../extensions/signal/src/channel.js"; -import { slackPlugin } from "../../extensions/slack/src/channel.js"; -import { telegramPlugin } from "../../extensions/telegram/src/channel.js"; -import { whatsappPlugin } from "../../extensions/whatsapp/src/channel.js"; -import { setActivePluginRegistry } from "../plugins/runtime.js"; -import { createTestRegistry } from "../test-utils/channel-plugins.js"; +import { setDefaultChannelPluginRegistryForTests } from "./channel-test-helpers.js"; import { baseConfigSnapshot, createTestRuntime } from "./test-runtime-config-helpers.js"; const configMocks = vi.hoisted(() => ({ @@ -56,16 +49,7 @@ describe("channels command", () => { version: 1, profiles: {}, }); - setActivePluginRegistry( - createTestRegistry([ - { pluginId: "discord", plugin: discordPlugin, source: "test" }, - { pluginId: "slack", plugin: slackPlugin, source: "test" }, - { pluginId: "telegram", plugin: telegramPlugin, source: "test" }, - { pluginId: "whatsapp", plugin: whatsappPlugin, source: "test" }, - { pluginId: "signal", plugin: signalPlugin, source: "test" }, - { pluginId: "imessage", plugin: imessagePlugin, source: "test" }, - ]), - ); + setDefaultChannelPluginRegistryForTests(); }); it("adds a non-default telegram account", async () => { diff --git a/src/commands/onboard-channels.e2e.test.ts b/src/commands/onboard-channels.e2e.test.ts index b88a47caedd..827ea313a81 100644 --- a/src/commands/onboard-channels.e2e.test.ts +++ b/src/commands/onboard-channels.e2e.test.ts @@ -1,14 +1,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; import type { WizardPrompter } from "../wizard/prompts.js"; -import { discordPlugin } from "../../extensions/discord/src/channel.js"; -import { imessagePlugin } from "../../extensions/imessage/src/channel.js"; -import { signalPlugin } from "../../extensions/signal/src/channel.js"; -import { slackPlugin } from "../../extensions/slack/src/channel.js"; -import { telegramPlugin } from "../../extensions/telegram/src/channel.js"; -import { whatsappPlugin } from "../../extensions/whatsapp/src/channel.js"; -import { setActivePluginRegistry } from "../plugins/runtime.js"; -import { createTestRegistry } from "../test-utils/channel-plugins.js"; +import { setDefaultChannelPluginRegistryForTests } from "./channel-test-helpers.js"; import { setupChannels } from "./onboard-channels.js"; import { createExitThrowingRuntime, createWizardPrompter } from "./test-wizard-helpers.js"; @@ -40,16 +33,7 @@ vi.mock("./onboard-helpers.js", () => ({ describe("setupChannels", () => { beforeEach(() => { - setActivePluginRegistry( - createTestRegistry([ - { pluginId: "discord", plugin: discordPlugin, source: "test" }, - { pluginId: "slack", plugin: slackPlugin, source: "test" }, - { pluginId: "telegram", plugin: telegramPlugin, source: "test" }, - { pluginId: "whatsapp", plugin: whatsappPlugin, source: "test" }, - { pluginId: "signal", plugin: signalPlugin, source: "test" }, - { pluginId: "imessage", plugin: imessagePlugin, source: "test" }, - ]), - ); + setDefaultChannelPluginRegistryForTests(); }); it("QuickStart uses single-select (no multiselect) and doesn't prompt for Telegram token when WhatsApp is chosen", async () => { const select = vi.fn(async () => "whatsapp");