From ad0fcf9143617fa52c412588caa85477c121cae5 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 24 Apr 2026 07:22:03 +0100 Subject: [PATCH] perf: tighten auto-reply command tests --- .../reply/agent-runner.media-paths.test.ts | 10 +- src/auto-reply/reply/commands-plugins.test.ts | 58 ++++++ .../reply/commands-plugins.toggle.test.ts | 193 ------------------ 3 files changed, 64 insertions(+), 197 deletions(-) delete mode 100644 src/auto-reply/reply/commands-plugins.toggle.test.ts diff --git a/src/auto-reply/reply/agent-runner.media-paths.test.ts b/src/auto-reply/reply/agent-runner.media-paths.test.ts index 557bd993cb7..b937c7cea0a 100644 --- a/src/auto-reply/reply/agent-runner.media-paths.test.ts +++ b/src/auto-reply/reply/agent-runner.media-paths.test.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import type { TemplateContext } from "../templating.js"; import type { FollowupRun, QueueSettings } from "./queue.js"; import { createMockFollowupRun, createMockTypingController } from "./test-helpers.js"; @@ -117,8 +117,11 @@ function makeRunReplyAgentParams( } describe("runReplyAgent media path normalization", () => { - beforeEach(async () => { - vi.resetModules(); + beforeAll(async () => { + ({ runReplyAgent } = await import("./agent-runner.js")); + }); + + beforeEach(() => { runEmbeddedPiAgentMock.mockReset(); runWithModelFallbackMock.mockReset(); abortEmbeddedPiRunMock.mockReset(); @@ -155,7 +158,6 @@ describe("runReplyAgent media path normalization", () => { model, }), ); - ({ runReplyAgent } = await import("./agent-runner.js")); }); afterEach(() => { diff --git a/src/auto-reply/reply/commands-plugins.test.ts b/src/auto-reply/reply/commands-plugins.test.ts index 15ca8e4b29f..c7ecf1e695e 100644 --- a/src/auto-reply/reply/commands-plugins.test.ts +++ b/src/auto-reply/reply/commands-plugins.test.ts @@ -191,6 +191,64 @@ describe("handlePluginsCommand", () => { expect(result?.reply?.text).toContain("requires operator.admin"); }); + it("enables and disables a discovered plugin", async () => { + validateConfigObjectWithPluginsMock.mockImplementation((next) => ({ ok: true, config: next })); + + const enableParams = buildPluginsParams("/plugins enable superpowers", buildCfg()); + enableParams.command.senderIsOwner = true; + + const enableResult = await handlePluginsCommand(enableParams, true); + expect(enableResult?.reply?.text).toContain('Plugin "superpowers" enabled'); + expect(writeConfigFileMock).toHaveBeenLastCalledWith( + expect.objectContaining({ + plugins: expect.objectContaining({ + entries: expect.objectContaining({ + superpowers: expect.objectContaining({ enabled: true }), + }), + }), + }), + ); + + const disableParams = buildPluginsParams("/plugins disable superpowers", buildCfg()); + disableParams.command.senderIsOwner = true; + + const disableResult = await handlePluginsCommand(disableParams, true); + expect(disableResult?.reply?.text).toContain('Plugin "superpowers" disabled'); + expect(writeConfigFileMock).toHaveBeenLastCalledWith( + expect.objectContaining({ + plugins: expect.objectContaining({ + entries: expect.objectContaining({ + superpowers: expect.objectContaining({ enabled: false }), + }), + }), + }), + ); + }); + + it("resolves write targets by runtime-derived plugin name", async () => { + buildPluginDiagnosticsReportMock.mockReturnValue({ + workspaceDir: "/tmp/plugins-workspace", + plugins: [ + { + id: "superpowers", + name: "Super Powers", + status: "disabled", + format: "openclaw", + bundleFormat: "claude", + }, + ], + }); + validateConfigObjectWithPluginsMock.mockImplementation((next) => ({ ok: true, config: next })); + + const params = buildPluginsParams("/plugins enable Super Powers", buildCfg()); + params.command.senderIsOwner = true; + + const result = await handlePluginsCommand(params, true); + expect(result?.reply?.text).toContain('Plugin "superpowers" enabled'); + expect(buildPluginDiagnosticsReportMock).toHaveBeenCalled(); + expect(buildPluginSnapshotReportMock).not.toHaveBeenCalled(); + }); + it("returns an explicit unauthorized reply for native /plugins list", async () => { const params = buildPluginsParams("/plugins list", buildCfg()); params.command.senderIsOwner = false; diff --git a/src/auto-reply/reply/commands-plugins.toggle.test.ts b/src/auto-reply/reply/commands-plugins.toggle.test.ts deleted file mode 100644 index 97ed696da31..00000000000 --- a/src/auto-reply/reply/commands-plugins.toggle.test.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { afterEach, describe, expect, it, vi } from "vitest"; -import { installedPluginRoot } from "../../../test/helpers/bundled-plugin-paths.js"; -import { createPluginRecord, createPluginStatusReport } from "../../plugins/status.test-helpers.js"; - -const WORKSPACE_PLUGIN_ROOT = installedPluginRoot("/tmp/workspace/.openclaw", "superpowers"); - -const { - readConfigFileSnapshotMock, - validateConfigObjectWithPluginsMock, - writeConfigFileMock, - buildPluginSnapshotReportMock, - buildPluginDiagnosticsReportMock, -} = vi.hoisted(() => ({ - readConfigFileSnapshotMock: vi.fn(), - validateConfigObjectWithPluginsMock: vi.fn(), - writeConfigFileMock: vi.fn(), - buildPluginSnapshotReportMock: vi.fn(), - buildPluginDiagnosticsReportMock: vi.fn(), -})); - -vi.mock("../../config/config.js", async () => { - const actual = - await vi.importActual("../../config/config.js"); - return { - ...actual, - readConfigFileSnapshot: readConfigFileSnapshotMock, - validateConfigObjectWithPlugins: validateConfigObjectWithPluginsMock, - writeConfigFile: writeConfigFileMock, - }; -}); - -vi.mock("../../plugins/status.js", async () => { - const actual = - await vi.importActual("../../plugins/status.js"); - return { - ...actual, - buildPluginSnapshotReport: buildPluginSnapshotReportMock, - buildPluginDiagnosticsReport: buildPluginDiagnosticsReportMock, - }; -}); - -import { handleCommands } from "./commands-core.js"; -import { buildCommandTestParams } from "./commands.test-harness.js"; - -function buildCfg() { - return { - plugins: { - enabled: true, - }, - commands: { - text: true, - plugins: true, - }, - }; -} - -describe("handleCommands /plugins toggle", () => { - afterEach(() => { - readConfigFileSnapshotMock.mockReset(); - validateConfigObjectWithPluginsMock.mockReset(); - writeConfigFileMock.mockReset(); - buildPluginSnapshotReportMock.mockReset(); - buildPluginDiagnosticsReportMock.mockReset(); - }); - - it("enables a discovered plugin", async () => { - const config = buildCfg(); - readConfigFileSnapshotMock.mockResolvedValue({ - valid: true, - path: "/tmp/openclaw.json", - resolved: config, - }); - buildPluginDiagnosticsReportMock.mockReturnValue( - createPluginStatusReport({ - workspaceDir: "/tmp/workspace", - plugins: [ - createPluginRecord({ - id: "superpowers", - format: "bundle", - source: WORKSPACE_PLUGIN_ROOT, - enabled: false, - status: "disabled", - }), - ], - }), - ); - validateConfigObjectWithPluginsMock.mockImplementation((next) => ({ ok: true, config: next })); - writeConfigFileMock.mockResolvedValue(undefined); - - const params = buildCommandTestParams("/plugins enable superpowers", buildCfg()); - params.command.senderIsOwner = true; - - const result = await handleCommands(params); - expect(result.reply?.text).toContain('Plugin "superpowers" enabled'); - expect(writeConfigFileMock).toHaveBeenCalledWith( - expect.objectContaining({ - plugins: expect.objectContaining({ - entries: expect.objectContaining({ - superpowers: expect.objectContaining({ enabled: true }), - }), - }), - }), - ); - }); - - it("disables a discovered plugin", async () => { - const config = buildCfg(); - readConfigFileSnapshotMock.mockResolvedValue({ - valid: true, - path: "/tmp/openclaw.json", - resolved: config, - }); - buildPluginDiagnosticsReportMock.mockReturnValue( - createPluginStatusReport({ - workspaceDir: "/tmp/workspace", - plugins: [ - createPluginRecord({ - id: "superpowers", - format: "bundle", - source: WORKSPACE_PLUGIN_ROOT, - enabled: true, - }), - ], - }), - ); - validateConfigObjectWithPluginsMock.mockImplementation((next) => ({ ok: true, config: next })); - writeConfigFileMock.mockResolvedValue(undefined); - - const params = buildCommandTestParams("/plugins disable superpowers", buildCfg()); - params.command.senderIsOwner = true; - - const result = await handleCommands(params); - expect(result.reply?.text).toContain('Plugin "superpowers" disabled'); - expect(writeConfigFileMock).toHaveBeenCalledWith( - expect.objectContaining({ - plugins: expect.objectContaining({ - entries: expect.objectContaining({ - superpowers: expect.objectContaining({ enabled: false }), - }), - }), - }), - ); - }); - - it("resolves write targets by runtime-derived plugin name", async () => { - const config = buildCfg(); - readConfigFileSnapshotMock.mockResolvedValue({ - valid: true, - path: "/tmp/openclaw.json", - resolved: config, - }); - buildPluginSnapshotReportMock.mockReturnValue( - createPluginStatusReport({ - workspaceDir: "/tmp/workspace", - plugins: [ - createPluginRecord({ - id: "superpowers", - name: "superpowers", - format: "bundle", - source: WORKSPACE_PLUGIN_ROOT, - enabled: false, - status: "disabled", - }), - ], - }), - ); - buildPluginDiagnosticsReportMock.mockReturnValue( - createPluginStatusReport({ - workspaceDir: "/tmp/workspace", - plugins: [ - createPluginRecord({ - id: "superpowers", - name: "Super Powers", - format: "bundle", - source: WORKSPACE_PLUGIN_ROOT, - enabled: false, - status: "disabled", - }), - ], - }), - ); - validateConfigObjectWithPluginsMock.mockImplementation((next) => ({ ok: true, config: next })); - writeConfigFileMock.mockResolvedValue(undefined); - - const params = buildCommandTestParams("/plugins enable Super Powers", buildCfg()); - params.command.senderIsOwner = true; - - const result = await handleCommands(params); - expect(result.reply?.text).toContain('Plugin "superpowers" enabled'); - expect(buildPluginDiagnosticsReportMock).toHaveBeenCalled(); - expect(buildPluginSnapshotReportMock).not.toHaveBeenCalled(); - }); -});