From f48f0957f5c8077e26f60cc32750bca5dbb2cf97 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 20 Apr 2026 19:32:15 +0100 Subject: [PATCH] test: share channel setup fixtures --- src/flows/channel-setup.status.test.ts | 96 ++++++----------- src/flows/channel-setup.test-helpers.ts | 48 +++++++++ src/flows/channel-setup.test.ts | 135 +++++++----------------- 3 files changed, 119 insertions(+), 160 deletions(-) create mode 100644 src/flows/channel-setup.test-helpers.ts diff --git a/src/flows/channel-setup.status.test.ts b/src/flows/channel-setup.status.test.ts index 82604b8a576..27ccf3fad59 100644 --- a/src/flows/channel-setup.status.test.ts +++ b/src/flows/channel-setup.status.test.ts @@ -1,7 +1,10 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; +import { + makeCatalogEntry, + makeChannelSetupEntries, + makeMeta, +} from "./channel-setup.test-helpers.js"; -type ChannelMeta = import("../channels/plugins/types.core.js").ChannelMeta; -type ChannelPluginCatalogEntry = import("../channels/plugins/catalog.js").ChannelPluginCatalogEntry; type ListChatChannels = typeof import("../channels/chat-meta.js").listChatChannels; type ResolveChannelSetupEntries = typeof import("../commands/channel-setup/discovery.js").resolveChannelSetupEntries; @@ -13,37 +16,7 @@ type NoteChannelPrimerChannels = Parameters< typeof import("./channel-setup.status.js").noteChannelPrimer >[1]; -function makeMeta(id: string, label: string, overrides: Partial = {}): ChannelMeta { - return { - id: id as ChannelMeta["id"], - label, - selectionLabel: overrides.selectionLabel ?? label, - docsPath: overrides.docsPath ?? `/channels/${id}`, - blurb: overrides.blurb ?? "", - ...overrides, - }; -} - -function makeCatalogEntry( - id: string, - label: string, - overrides: Partial = {}, -): ChannelPluginCatalogEntry { - return { - id, - pluginId: overrides.pluginId ?? id, - meta: makeMeta(id, label, overrides.meta), - install: overrides.install ?? { npmSpec: `@openclaw/${id}` }, - ...overrides, - }; -} - -const listChatChannels = vi.hoisted(() => - vi.fn(() => [ - makeMeta("discord", "Discord"), - makeMeta("bluebubbles", "BlueBubbles"), - ]), -); +const listChatChannels = vi.hoisted(() => vi.fn(() => [])); const resolveChannelSetupEntries = vi.hoisted(() => vi.fn(() => ({ entries: [], @@ -102,13 +75,7 @@ describe("resolveChannelSetupSelectionContributions", () => { makeMeta("discord", "Discord"), makeMeta("bluebubbles", "BlueBubbles"), ]); - resolveChannelSetupEntries.mockReturnValue({ - entries: [], - installedCatalogEntries: [], - installableCatalogEntries: [], - installedCatalogById: new Map(), - installableCatalogById: new Map(), - }); + resolveChannelSetupEntries.mockReturnValue(makeChannelSetupEntries()); formatChannelPrimerLine.mockImplementation( (meta: { label: string; blurb: string }) => `${meta.label}: ${meta.blurb}`, ); @@ -247,13 +214,12 @@ describe("resolveChannelSetupSelectionContributions", () => { it("sanitizes channel labels in status note lines", async () => { listChatChannels.mockReturnValue([makeMeta("discord", "Discord\u001B[31m\nCore\u0007")]); - resolveChannelSetupEntries.mockReturnValue({ - entries: [], - installedCatalogEntries: [makeCatalogEntry("matrix", "Matrix\u001B[2K\nPlugin\u0007")], - installableCatalogEntries: [makeCatalogEntry("zalo", "Zalo\u001B[2K\nPlugin\u0007")], - installedCatalogById: new Map(), - installableCatalogById: new Map(), - }); + resolveChannelSetupEntries.mockReturnValue( + makeChannelSetupEntries({ + installedCatalogEntries: [makeCatalogEntry("matrix", "Matrix\u001B[2K\nPlugin\u0007")], + installableCatalogEntries: [makeCatalogEntry("zalo", "Zalo\u001B[2K\nPlugin\u0007")], + }), + ); const summary = await collectChannelStatus({ cfg: {} as never, @@ -297,27 +263,25 @@ describe("resolveChannelSetupSelectionContributions", () => { }); it("sanitizes channel metadata before selection notes", () => { - resolveChannelSetupEntries.mockReturnValue({ - entries: [ - { - id: "zalo", - meta: { + resolveChannelSetupEntries.mockReturnValue( + makeChannelSetupEntries({ + entries: [ + { id: "zalo", - label: "Zalo\u001B[31m\nBot\u0007", - selectionLabel: "Zalo", - docsPath: "/channels/zalo", - docsLabel: "Docs\u001B[2K\nLabel", - blurb: "Setup\u001B[2K\nhelp\u0007", - selectionDocsPrefix: "Docs\u001B[2K\nPrefix", - selectionExtras: ["Extra\u001B[2K\nOne", "\u001B[31m\u0007"], + meta: { + id: "zalo", + label: "Zalo\u001B[31m\nBot\u0007", + selectionLabel: "Zalo", + docsPath: "/channels/zalo", + docsLabel: "Docs\u001B[2K\nLabel", + blurb: "Setup\u001B[2K\nhelp\u0007", + selectionDocsPrefix: "Docs\u001B[2K\nPrefix", + selectionExtras: ["Extra\u001B[2K\nOne", "\u001B[31m\u0007"], + }, }, - }, - ], - installedCatalogEntries: [], - installableCatalogEntries: [], - installedCatalogById: new Map(), - installableCatalogById: new Map(), - }); + ], + }), + ); const lines = resolveChannelSelectionNoteLines({ cfg: {} as never, diff --git a/src/flows/channel-setup.test-helpers.ts b/src/flows/channel-setup.test-helpers.ts new file mode 100644 index 00000000000..97a4f1aa912 --- /dev/null +++ b/src/flows/channel-setup.test-helpers.ts @@ -0,0 +1,48 @@ +type ChannelMeta = import("../channels/plugins/types.core.js").ChannelMeta; +type ChannelPluginCatalogEntry = import("../channels/plugins/catalog.js").ChannelPluginCatalogEntry; +type ResolveChannelSetupEntries = + typeof import("../commands/channel-setup/discovery.js").resolveChannelSetupEntries; + +type ChannelSetupEntries = ReturnType; + +export function makeMeta( + id: string, + label: string, + overrides: Partial = {}, +): ChannelMeta { + return { + id: id as ChannelMeta["id"], + label, + selectionLabel: overrides.selectionLabel ?? label, + docsPath: overrides.docsPath ?? `/channels/${id}`, + blurb: overrides.blurb ?? "", + ...overrides, + }; +} + +export function makeCatalogEntry( + id: string, + label: string, + overrides: Partial = {}, +): ChannelPluginCatalogEntry { + return { + id, + pluginId: overrides.pluginId ?? id, + meta: makeMeta(id, label, overrides.meta), + install: overrides.install ?? { npmSpec: `@openclaw/${id}` }, + ...overrides, + }; +} + +export function makeChannelSetupEntries( + overrides: Partial = {}, +): ChannelSetupEntries { + return { + entries: [], + installedCatalogEntries: [], + installableCatalogEntries: [], + installedCatalogById: new Map(), + installableCatalogById: new Map(), + ...overrides, + }; +} diff --git a/src/flows/channel-setup.test.ts b/src/flows/channel-setup.test.ts index 7e6121e55ee..17f24553233 100644 --- a/src/flows/channel-setup.test.ts +++ b/src/flows/channel-setup.test.ts @@ -1,7 +1,10 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; +import { + makeCatalogEntry, + makeChannelSetupEntries, + makeMeta, +} from "./channel-setup.test-helpers.js"; -type ChannelMeta = import("../channels/plugins/types.core.js").ChannelMeta; -type ChannelPluginCatalogEntry = import("../channels/plugins/catalog.js").ChannelPluginCatalogEntry; type ChannelSetupPlugin = import("../channels/plugins/setup-wizard-types.js").ChannelSetupPlugin; type ResolveChannelSetupEntries = typeof import("../commands/channel-setup/discovery.js").resolveChannelSetupEntries; @@ -10,31 +13,6 @@ type LoadChannelSetupPluginRegistrySnapshotForChannel = typeof import("../commands/channel-setup/plugin-install.js").loadChannelSetupPluginRegistrySnapshotForChannel; type PluginRegistry = ReturnType; -function makeMeta(id: string, label: string, overrides: Partial = {}): ChannelMeta { - return { - id: id as ChannelMeta["id"], - label, - selectionLabel: overrides.selectionLabel ?? label, - docsPath: overrides.docsPath ?? `/channels/${id}`, - blurb: overrides.blurb ?? "", - ...overrides, - }; -} - -function makeCatalogEntry( - id: string, - label: string, - overrides: Partial = {}, -): ChannelPluginCatalogEntry { - return { - id, - pluginId: overrides.pluginId ?? id, - origin: overrides.origin, - meta: makeMeta(id, label, overrides.meta), - install: overrides.install ?? { npmSpec: `@openclaw/${id}` }, - }; -} - function makeSetupPlugin(params: { id: string; label: string; @@ -51,6 +29,18 @@ function makeSetupPlugin(params: { }; } +function externalChatSetupEntries(overrides: Partial> = {}) { + return makeChannelSetupEntries({ + entries: [ + { + id: "external-chat", + meta: makeMeta("external-chat", "External Chat"), + }, + ], + ...overrides, + }); +} + function makePluginRegistry(overrides: Partial = {}): PluginRegistry { return { plugins: [], @@ -199,13 +189,7 @@ describe("setupChannels workspace shadow exclusion", () => { listActiveChannelSetupPlugins.mockReturnValue([]); listChannelSetupPlugins.mockReturnValue([]); loadChannelSetupPluginRegistrySnapshotForChannel.mockReturnValue(makePluginRegistry()); - resolveChannelSetupEntries.mockReturnValue({ - entries: [], - installedCatalogEntries: [], - installableCatalogEntries: [], - installedCatalogById: new Map(), - installableCatalogById: new Map(), - }); + resolveChannelSetupEntries.mockReturnValue(makeChannelSetupEntries()); collectChannelStatus.mockResolvedValue({ installedPlugins: [], catalogEntries: [], @@ -270,18 +254,7 @@ describe("setupChannels workspace shadow exclusion", () => { }); it("defers status and setup-plugin loads until a channel is selected", async () => { - resolveChannelSetupEntries.mockReturnValue({ - entries: [ - { - id: "external-chat", - meta: makeMeta("external-chat", "External Chat"), - }, - ], - installedCatalogEntries: [], - installableCatalogEntries: [], - installedCatalogById: new Map(), - installableCatalogById: new Map(), - }); + resolveChannelSetupEntries.mockReturnValue(externalChatSetupEntries()); const select = vi.fn(async () => "__done__"); await setupChannels( @@ -366,18 +339,20 @@ describe("setupChannels workspace shadow exclusion", () => { setupWizard, }); listActiveChannelSetupPlugins.mockReturnValue([activePlugin]); - resolveChannelSetupEntries.mockReturnValue({ - entries: [ - { - id: "custom-chat", - meta: makeMeta("custom-chat", "Custom Chat"), - }, - ], - installedCatalogEntries: [], - installableCatalogEntries: [], - installedCatalogById: new Map(), - installableCatalogById: new Map(), - }); + resolveChannelSetupEntries.mockReturnValue( + makeChannelSetupEntries({ + entries: [ + { + id: "custom-chat", + meta: makeMeta("custom-chat", "Custom Chat"), + }, + ], + installedCatalogEntries: [], + installableCatalogEntries: [], + installedCatalogById: new Map(), + installableCatalogById: new Map(), + }), + ); const select = vi.fn().mockResolvedValueOnce("custom-chat").mockResolvedValueOnce("__done__"); const next = await setupChannels( @@ -435,18 +410,12 @@ describe("setupChannels workspace shadow exclusion", () => { pluginId: "external-chat", origin: "bundled", }); - resolveChannelSetupEntries.mockReturnValue({ - entries: [ - { - id: "external-chat", - meta: makeMeta("external-chat", "External Chat"), - }, - ], - installedCatalogEntries: [installedCatalogEntry], - installableCatalogEntries: [], - installedCatalogById: new Map([["external-chat", installedCatalogEntry]]), - installableCatalogById: new Map(), - }); + resolveChannelSetupEntries.mockReturnValue( + externalChatSetupEntries({ + installedCatalogEntries: [installedCatalogEntry], + installedCatalogById: new Map([["external-chat", installedCatalogEntry]]), + }), + ); loadChannelSetupPluginRegistrySnapshotForChannel.mockReturnValue( makePluginRegistry({ channels: [ @@ -507,18 +476,7 @@ describe("setupChannels workspace shadow exclusion", () => { })), configure: vi.fn(), }; - resolveChannelSetupEntries.mockReturnValue({ - entries: [ - { - id: "external-chat", - meta: makeMeta("external-chat", "External Chat"), - }, - ], - installedCatalogEntries: [], - installableCatalogEntries: [], - installedCatalogById: new Map(), - installableCatalogById: new Map(), - }); + resolveChannelSetupEntries.mockReturnValue(externalChatSetupEntries()); const select = vi.fn().mockResolvedValueOnce("external-chat").mockResolvedValueOnce("__done__"); const note = vi.fn(async () => undefined); const cfg = { @@ -556,18 +514,7 @@ describe("setupChannels workspace shadow exclusion", () => { }); it("honors global plugin disablement before lazy channel setup loads plugins", async () => { - resolveChannelSetupEntries.mockReturnValue({ - entries: [ - { - id: "external-chat", - meta: makeMeta("external-chat", "External Chat"), - }, - ], - installedCatalogEntries: [], - installableCatalogEntries: [], - installedCatalogById: new Map(), - installableCatalogById: new Map(), - }); + resolveChannelSetupEntries.mockReturnValue(externalChatSetupEntries()); const select = vi.fn().mockResolvedValueOnce("external-chat").mockResolvedValueOnce("__done__"); const note = vi.fn(async () => undefined); const cfg = {