From 25fea00bc72cadfcf09bcdab0883618782bac52a Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 28 Mar 2026 04:43:20 +0000 Subject: [PATCH] test: dedupe plugin utility config suites --- src/plugins/channel-plugin-ids.test.ts | 4 -- src/plugins/cli.test.ts | 46 +++++++++++++-------- src/plugins/installs.test.ts | 18 +++++++++ src/plugins/provider-catalog.test.ts | 31 ++++++++------- src/plugins/slots.test.ts | 55 ++++++++++++++++---------- src/plugins/source-display.test.ts | 37 +++++++++++------ 6 files changed, 123 insertions(+), 68 deletions(-) diff --git a/src/plugins/channel-plugin-ids.test.ts b/src/plugins/channel-plugin-ids.test.ts index d7b5bc9636f..ad1d5975beb 100644 --- a/src/plugins/channel-plugin-ids.test.ts +++ b/src/plugins/channel-plugin-ids.test.ts @@ -70,9 +70,6 @@ function expectStartupPluginIds(config: OpenClawConfig, expected: readonly strin env: process.env, }), ).toEqual(expected); -} - -function expectManifestRegistryFixture() { expect(loadPluginManifestRegistry).toHaveBeenCalled(); } @@ -123,6 +120,5 @@ describe("resolveGatewayStartupPluginIds", () => { ], ] as const)("%s", (_name, config, expected) => { expectStartupPluginIds(config, expected); - expectManifestRegistryFixture(); }); }); diff --git a/src/plugins/cli.test.ts b/src/plugins/cli.test.ts index 68d63cd64d2..0adf2ee9ac0 100644 --- a/src/plugins/cli.test.ts +++ b/src/plugins/cli.test.ts @@ -54,6 +54,33 @@ function expectPluginLoaderConfig(config: OpenClawConfig) { ); } +function createAutoEnabledCliFixture() { + const rawConfig = { + plugins: {}, + channels: { demo: { enabled: true } }, + } as OpenClawConfig; + const autoEnabledConfig = { + ...rawConfig, + plugins: { + entries: { + demo: { enabled: true }, + }, + }, + } as OpenClawConfig; + return { rawConfig, autoEnabledConfig }; +} + +function expectAutoEnabledCliLoad(params: { + rawConfig: OpenClawConfig; + autoEnabledConfig: OpenClawConfig; +}) { + expect(mocks.applyPluginAutoEnable).toHaveBeenCalledWith({ + config: params.rawConfig, + env: process.env, + }); + expectPluginLoaderConfig(params.autoEnabledConfig); +} + describe("registerPluginCliCommands", () => { beforeEach(() => { mocks.memoryRegister.mockClear(); @@ -89,27 +116,12 @@ describe("registerPluginCliCommands", () => { it("loads plugin CLI commands from the auto-enabled config snapshot", () => { const program = createProgram(); - const rawConfig = { - plugins: {}, - channels: { demo: { enabled: true } }, - } as OpenClawConfig; - const autoEnabledConfig = { - ...rawConfig, - plugins: { - entries: { - demo: { enabled: true }, - }, - }, - } as OpenClawConfig; + const { rawConfig, autoEnabledConfig } = createAutoEnabledCliFixture(); mocks.applyPluginAutoEnable.mockReturnValue({ config: autoEnabledConfig, changes: [] }); registerPluginCliCommands(program, rawConfig); - expect(mocks.applyPluginAutoEnable).toHaveBeenCalledWith({ - config: rawConfig, - env: process.env, - }); - expectPluginLoaderConfig(autoEnabledConfig); + expectAutoEnabledCliLoad({ rawConfig, autoEnabledConfig }); expect(mocks.memoryRegister).toHaveBeenCalledWith( expect.objectContaining({ config: autoEnabledConfig, diff --git a/src/plugins/installs.test.ts b/src/plugins/installs.test.ts index d042325f191..2afdfd4096c 100644 --- a/src/plugins/installs.test.ts +++ b/src/plugins/installs.test.ts @@ -23,6 +23,13 @@ function createExpectedResolutionFields( }; } +function expectResolutionFields( + input: Parameters[0], + overrides: Partial>, +) { + expect(buildNpmResolutionInstallFields(input)).toEqual(createExpectedResolutionFields(overrides)); +} + describe("buildNpmResolutionInstallFields", () => { it.each([ { @@ -52,6 +59,17 @@ describe("buildNpmResolutionInstallFields", () => { ] as const)("$name", ({ input, expected }) => { expect(buildNpmResolutionInstallFields(input)).toEqual(expected); }); + + it("keeps missing partial resolution fields undefined", () => { + expectResolutionFields( + { + name: "@openclaw/demo", + }, + { + resolvedName: "@openclaw/demo", + }, + ); + }); }); describe("recordPluginInstall", () => { diff --git a/src/plugins/provider-catalog.test.ts b/src/plugins/provider-catalog.test.ts index 106ee961d3c..fc217bcd623 100644 --- a/src/plugins/provider-catalog.test.ts +++ b/src/plugins/provider-catalog.test.ts @@ -62,6 +62,22 @@ function createSingleCatalogProvider(overrides: Partial & { }; } +function createPairedCatalogProviders( + apiKey: string, + overrides: Partial = {}, +) { + return { + alpha: { + ...createProviderConfig(overrides), + apiKey, + }, + beta: { + ...createProviderConfig(overrides), + apiKey, + }, + }; +} + async function expectSingleCatalogResult(params: { ctx: ProviderCatalogContext; allowExplicitBaseUrl?: boolean; @@ -199,20 +215,7 @@ describe("buildSingleProviderApiKeyCatalog", () => { ctx: createCatalogContext({ apiKeys: { "test-provider": "secret-key" }, }), - expected: { - alpha: { - api: "openai-completions", - baseUrl: "https://default.example/v1", - models: [], - apiKey: "secret-key", - }, - beta: { - api: "openai-completions", - baseUrl: "https://default.example/v1", - models: [], - apiKey: "secret-key", - }, - }, + expected: createPairedCatalogProviders("secret-key"), }); }); }); diff --git a/src/plugins/slots.test.ts b/src/plugins/slots.test.ts index c0ca9ea0a88..a45cf833ecd 100644 --- a/src/plugins/slots.test.ts +++ b/src/plugins/slots.test.ts @@ -68,6 +68,23 @@ describe("applyExclusiveSlotSelection", () => { expect(result.warnings).toHaveLength(0); } + function expectUnchangedSelectionCase(params: { + config: OpenClawConfig; + selectedId: string; + selectedKind?: string; + registry?: { plugins: Array<{ id: string; kind: string }> }; + }) { + const result = applyExclusiveSlotSelection({ + config: params.config, + selectedId: params.selectedId, + ...(params.selectedKind ? { selectedKind: params.selectedKind } : {}), + ...(params.registry ? { registry: params.registry } : {}), + }); + + expectUnchangedSelection(result); + expect(result.config).toBe(params.config); + } + it("selects the slot and disables other entries for the same kind", () => { const config = createMemoryConfig({ slots: { memory: "memory-core" }, @@ -88,19 +105,28 @@ describe("applyExclusiveSlotSelection", () => { }); }); - it("does nothing when the slot already matches", () => { - const config = createMemoryConfig({ - slots: { memory: "memory" }, - }); - const result = applyExclusiveSlotSelection({ - config, + it.each([ + { + name: "does nothing when the slot already matches", + config: createMemoryConfig({ + slots: { memory: "memory" }, + }), selectedId: "memory", selectedKind: "memory", registry: { plugins: [{ id: "memory", kind: "memory" }] }, + }, + { + name: "skips changes when no exclusive slot applies", + config: {} as OpenClawConfig, + selectedId: "custom", + }, + ] as const)("$name", ({ config, selectedId, selectedKind, registry }) => { + expectUnchangedSelectionCase({ + config, + selectedId, + ...(selectedKind ? { selectedKind } : {}), + ...(registry ? { registry } : {}), }); - - expectUnchangedSelection(result); - expect(result.config).toBe(config); }); it.each([ @@ -136,15 +162,4 @@ describe("applyExclusiveSlotSelection", () => { }); expectSelectionWarnings(result.warnings, warningChecks); }); - - it("skips changes when no exclusive slot applies", () => { - const config: OpenClawConfig = {}; - const result = applyExclusiveSlotSelection({ - config, - selectedId: "custom", - }); - - expectUnchangedSelection(result); - expect(result.config).toBe(config); - }); }); diff --git a/src/plugins/source-display.test.ts b/src/plugins/source-display.test.ts index 6a01843c764..175864da63e 100644 --- a/src/plugins/source-display.test.ts +++ b/src/plugins/source-display.test.ts @@ -28,6 +28,22 @@ function expectFormattedSource(params: { expect(out.rootKey).toBe(params.expectedRootKey); } +function expectResolvedSourceRoots(params: { + homeDir: string; + env: NodeJS.ProcessEnv; + workspaceDir: string; + expected: Record<"stock" | "global" | "workspace", string>; +}) { + const roots = withPathResolutionEnv(params.homeDir, params.env, (env) => + resolvePluginSourceRoots({ + env, + workspaceDir: params.workspaceDir, + }), + ); + + expect(roots).toEqual(params.expected); +} + describe("formatPluginSourceForTable", () => { it.each([ { @@ -73,23 +89,18 @@ describe("formatPluginSourceForTable", () => { it("resolves source roots from an explicit env override", () => { const homeDir = path.resolve(path.sep, "tmp", "openclaw-home"); - const roots = withPathResolutionEnv( + expectResolvedSourceRoots({ homeDir, - { + env: { OPENCLAW_BUNDLED_PLUGINS_DIR: "~/bundled", OPENCLAW_STATE_DIR: "~/state", + } as NodeJS.ProcessEnv, + workspaceDir: "~/ws", + expected: { + stock: path.join(homeDir, "bundled"), + global: path.join(homeDir, "state", "extensions"), + workspace: path.join(homeDir, "ws", ".openclaw", "extensions"), }, - (env) => - resolvePluginSourceRoots({ - env, - workspaceDir: "~/ws", - }), - ); - - expect(roots).toEqual({ - stock: path.join(homeDir, "bundled"), - global: path.join(homeDir, "state", "extensions"), - workspace: path.join(homeDir, "ws", ".openclaw", "extensions"), }); }); });