diff --git a/src/plugins/install.e2e.test.ts b/src/plugins/install.e2e.test.ts index 4c6955ea27d..4bb235497bb 100644 --- a/src/plugins/install.e2e.test.ts +++ b/src/plugins/install.e2e.test.ts @@ -4,7 +4,7 @@ import os from "node:os"; import path from "node:path"; import JSZip from "jszip"; import * as tar from "tar"; -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import * as skillScanner from "../security/skill-scanner.js"; import { expectSingleNpmInstallIgnoreScriptsCall, @@ -16,6 +16,10 @@ vi.mock("../process/exec.js", () => ({ })); const tempDirs: string[] = []; +let installPluginFromArchive: typeof import("./install.js").installPluginFromArchive; +let installPluginFromDir: typeof import("./install.js").installPluginFromDir; +let installPluginFromNpmSpec: typeof import("./install.js").installPluginFromNpmSpec; +let runCommandWithTimeout: typeof import("../process/exec.js").runCommandWithTimeout; function makeTempDir() { const dir = path.join(os.tmpdir(), `openclaw-plugin-install-${randomUUID()}`); @@ -120,7 +124,6 @@ function setupPluginInstallDirs() { } async function installFromDirWithWarnings(params: { pluginDir: string; extensionsDir: string }) { - const { installPluginFromDir } = await import("./install.js"); const warnings: string[] = []; const result = await installPluginFromDir({ dirPath: params.pluginDir, @@ -159,7 +162,6 @@ async function expectArchiveInstallReservedSegmentRejection(params: { }); const extensionsDir = path.join(stateDir, "extensions"); - const { installPluginFromArchive } = await import("./install.js"); const result = await installPluginFromArchive({ archivePath, extensionsDir, @@ -182,6 +184,12 @@ afterEach(() => { } }); +beforeAll(async () => { + ({ installPluginFromArchive, installPluginFromDir, installPluginFromNpmSpec } = + await import("./install.js")); + ({ runCommandWithTimeout } = await import("../process/exec.js")); +}); + beforeEach(() => { vi.clearAllMocks(); }); @@ -193,7 +201,6 @@ describe("installPluginFromArchive", () => { version: "0.0.1", }); - const { installPluginFromArchive } = await import("./install.js"); const result = await installPluginFromArchive({ archivePath, extensionsDir, @@ -212,7 +219,6 @@ describe("installPluginFromArchive", () => { version: "0.0.1", }); - const { installPluginFromArchive } = await import("./install.js"); const first = await installPluginFromArchive({ archivePath, extensionsDir, @@ -249,7 +255,6 @@ describe("installPluginFromArchive", () => { fs.writeFileSync(archivePath, buffer); const extensionsDir = path.join(stateDir, "extensions"); - const { installPluginFromArchive } = await import("./install.js"); const result = await installPluginFromArchive({ archivePath, extensionsDir, @@ -278,7 +283,6 @@ describe("installPluginFromArchive", () => { }); const extensionsDir = path.join(stateDir, "extensions"); - const { installPluginFromArchive } = await import("./install.js"); const first = await installPluginFromArchive({ archivePath: archiveV1, extensionsDir, @@ -332,7 +336,6 @@ describe("installPluginFromArchive", () => { }); const extensionsDir = path.join(stateDir, "extensions"); - const { installPluginFromArchive } = await import("./install.js"); const result = await installPluginFromArchive({ archivePath, extensionsDir, @@ -433,7 +436,6 @@ describe("installPluginFromDir", () => { ); fs.writeFileSync(path.join(pluginDir, "dist", "index.js"), "export {};", "utf-8"); - const { runCommandWithTimeout } = await import("../process/exec.js"); const run = vi.mocked(runCommandWithTimeout); run.mockResolvedValue({ code: 0, @@ -444,7 +446,6 @@ describe("installPluginFromDir", () => { termination: "exit", }); - const { installPluginFromDir } = await import("./install.js"); const res = await installPluginFromDir({ dirPath: pluginDir, extensionsDir: path.join(stateDir, "extensions"), @@ -480,7 +481,6 @@ describe("installPluginFromNpmSpec", () => { const extensionsDir = path.join(stateDir, "extensions"); fs.mkdirSync(extensionsDir, { recursive: true }); - const { runCommandWithTimeout } = await import("../process/exec.js"); const run = vi.mocked(runCommandWithTimeout); let packTmpDir = ""; @@ -510,7 +510,6 @@ describe("installPluginFromNpmSpec", () => { throw new Error(`unexpected command: ${argv.join(" ")}`); }); - const { installPluginFromNpmSpec } = await import("./install.js"); const result = await installPluginFromNpmSpec({ spec: "@openclaw/voice-call@0.0.1", extensionsDir, @@ -533,7 +532,6 @@ describe("installPluginFromNpmSpec", () => { }); it("rejects non-registry npm specs", async () => { - const { installPluginFromNpmSpec } = await import("./install.js"); const result = await installPluginFromNpmSpec({ spec: "github:evil/evil" }); expect(result.ok).toBe(false); if (result.ok) { @@ -543,7 +541,6 @@ describe("installPluginFromNpmSpec", () => { }); it("aborts when integrity drift callback rejects the fetched artifact", async () => { - const { runCommandWithTimeout } = await import("../process/exec.js"); const run = vi.mocked(runCommandWithTimeout); run.mockResolvedValue({ code: 0, @@ -564,7 +561,6 @@ describe("installPluginFromNpmSpec", () => { }); const onIntegrityDrift = vi.fn(async () => false); - const { installPluginFromNpmSpec } = await import("./install.js"); const result = await installPluginFromNpmSpec({ spec: "@openclaw/voice-call@0.0.1", expectedIntegrity: "sha512-old", diff --git a/src/plugins/wired-hooks-after-tool-call.e2e.test.ts b/src/plugins/wired-hooks-after-tool-call.e2e.test.ts index d0c74e7f4cf..dae8cb74469 100644 --- a/src/plugins/wired-hooks-after-tool-call.e2e.test.ts +++ b/src/plugins/wired-hooks-after-tool-call.e2e.test.ts @@ -1,7 +1,7 @@ /** * Test: after_tool_call hook wiring (pi-embedded-subscribe.handlers.tools.ts) */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const hookMocks = vi.hoisted(() => ({ runner: { @@ -58,7 +58,15 @@ function createToolHandlerCtx(params: { }; } +let handleToolExecutionStart: typeof import("../agents/pi-embedded-subscribe.handlers.tools.js").handleToolExecutionStart; +let handleToolExecutionEnd: typeof import("../agents/pi-embedded-subscribe.handlers.tools.js").handleToolExecutionEnd; + describe("after_tool_call hook wiring", () => { + beforeAll(async () => { + ({ handleToolExecutionStart, handleToolExecutionEnd } = + await import("../agents/pi-embedded-subscribe.handlers.tools.js")); + }); + beforeEach(() => { hookMocks.runner.hasHooks.mockReset(); hookMocks.runner.hasHooks.mockReturnValue(false); @@ -71,9 +79,6 @@ describe("after_tool_call hook wiring", () => { it("calls runAfterToolCall in handleToolExecutionEnd when hook is registered", async () => { hookMocks.runner.hasHooks.mockReturnValue(true); - const { handleToolExecutionEnd, handleToolExecutionStart } = - await import("../agents/pi-embedded-subscribe.handlers.tools.js"); - const ctx = createToolHandlerCtx({ runId: "test-run-1", agentId: "main", @@ -125,9 +130,6 @@ describe("after_tool_call hook wiring", () => { it("includes error in after_tool_call event on tool failure", async () => { hookMocks.runner.hasHooks.mockReturnValue(true); - const { handleToolExecutionEnd, handleToolExecutionStart } = - await import("../agents/pi-embedded-subscribe.handlers.tools.js"); - const ctx = createToolHandlerCtx({ runId: "test-run-2" }); await handleToolExecutionStart( @@ -166,9 +168,6 @@ describe("after_tool_call hook wiring", () => { it("does not call runAfterToolCall when no hooks registered", async () => { hookMocks.runner.hasHooks.mockReturnValue(false); - const { handleToolExecutionEnd } = - await import("../agents/pi-embedded-subscribe.handlers.tools.js"); - const ctx = createToolHandlerCtx({ runId: "r" }); await handleToolExecutionEnd(