From a631604247b524bfc304d98ed38c09e18b8d2eff Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 28 Mar 2026 08:33:19 +0000 Subject: [PATCH] fix(ci): stabilize browser bundled integration tests --- ...w-tools.browser-plugin.integration.test.ts | 12 +++- ...otstrap.browser-plugin.integration.test.ts | 12 +++- .../cli.browser-plugin.integration.test.ts | 59 ++++++++-------- .../helpers/browser-bundled-plugin-fixture.ts | 68 +++++++++++++++++++ 4 files changed, 120 insertions(+), 31 deletions(-) create mode 100644 test/helpers/browser-bundled-plugin-fixture.ts diff --git a/src/agents/openclaw-tools.browser-plugin.integration.test.ts b/src/agents/openclaw-tools.browser-plugin.integration.test.ts index 8371e562d60..f04e034fc7a 100644 --- a/src/agents/openclaw-tools.browser-plugin.integration.test.ts +++ b/src/agents/openclaw-tools.browser-plugin.integration.test.ts @@ -1,5 +1,7 @@ -import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { createBundledBrowserPluginFixture } from "../../test/helpers/browser-bundled-plugin-fixture.js"; import type { OpenClawConfig } from "../config/config.js"; +import { clearPluginDiscoveryCache } from "../plugins/discovery.js"; import { clearPluginLoaderCache } from "../plugins/loader.js"; import { clearPluginManifestRegistryCache } from "../plugins/manifest-registry.js"; import { resetPluginRuntimeStateForTest } from "../plugins/runtime.js"; @@ -7,17 +9,25 @@ import { createOpenClawTools } from "./openclaw-tools.js"; function resetPluginState() { clearPluginLoaderCache(); + clearPluginDiscoveryCache(); clearPluginManifestRegistryCache(); resetPluginRuntimeStateForTest(); } describe("createOpenClawTools browser plugin integration", () => { + let bundledFixture: ReturnType | null = null; + beforeEach(() => { + bundledFixture = createBundledBrowserPluginFixture(); + vi.stubEnv("OPENCLAW_BUNDLED_PLUGINS_DIR", bundledFixture.rootDir); resetPluginState(); }); afterEach(() => { resetPluginState(); + vi.unstubAllEnvs(); + bundledFixture?.cleanup(); + bundledFixture = null; }); it("loads the bundled browser plugin through normal plugin resolution", () => { diff --git a/src/gateway/server-plugin-bootstrap.browser-plugin.integration.test.ts b/src/gateway/server-plugin-bootstrap.browser-plugin.integration.test.ts index 3d1e67506ee..67011cde309 100644 --- a/src/gateway/server-plugin-bootstrap.browser-plugin.integration.test.ts +++ b/src/gateway/server-plugin-bootstrap.browser-plugin.integration.test.ts @@ -1,5 +1,7 @@ -import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { createBundledBrowserPluginFixture } from "../../test/helpers/browser-bundled-plugin-fixture.js"; import type { OpenClawConfig } from "../config/config.js"; +import { clearPluginDiscoveryCache } from "../plugins/discovery.js"; import { clearPluginLoaderCache } from "../plugins/loader.js"; import { clearPluginManifestRegistryCache } from "../plugins/manifest-registry.js"; import { resetPluginRuntimeStateForTest } from "../plugins/runtime.js"; @@ -9,6 +11,7 @@ import { loadGatewayStartupPlugins } from "./server-plugin-bootstrap.js"; function resetPluginState() { clearPluginLoaderCache(); + clearPluginDiscoveryCache(); clearPluginManifestRegistryCache(); resetPluginRuntimeStateForTest(); } @@ -23,12 +26,19 @@ function createTestLog() { } describe("loadGatewayStartupPlugins browser plugin integration", () => { + let bundledFixture: ReturnType | null = null; + beforeEach(() => { + bundledFixture = createBundledBrowserPluginFixture(); + vi.stubEnv("OPENCLAW_BUNDLED_PLUGINS_DIR", bundledFixture.rootDir); resetPluginState(); }); afterEach(() => { resetPluginState(); + vi.unstubAllEnvs(); + bundledFixture?.cleanup(); + bundledFixture = null; }); it("adds browser.request and the browser control service from the bundled plugin", () => { diff --git a/src/plugins/cli.browser-plugin.integration.test.ts b/src/plugins/cli.browser-plugin.integration.test.ts index a256acf0c40..fd9d55eae85 100644 --- a/src/plugins/cli.browser-plugin.integration.test.ts +++ b/src/plugins/cli.browser-plugin.integration.test.ts @@ -1,54 +1,56 @@ -import { Command } from "commander"; +import path from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { createBundledBrowserPluginFixture } from "../../test/helpers/browser-bundled-plugin-fixture.js"; import type { OpenClawConfig } from "../config/config.js"; -let registerPluginCliCommands: typeof import("./cli.js").registerPluginCliCommands; -let clearPluginLoaderCache: typeof import("./loader.js").clearPluginLoaderCache; -let clearPluginManifestRegistryCache: typeof import("./manifest-registry.js").clearPluginManifestRegistryCache; -let resetPluginRuntimeStateForTest: typeof import("./runtime.js").resetPluginRuntimeStateForTest; +import { clearPluginDiscoveryCache } from "./discovery.js"; +import { clearPluginLoaderCache, loadOpenClawPlugins } from "./loader.js"; +import { clearPluginManifestRegistryCache } from "./manifest-registry.js"; +import { resetPluginRuntimeStateForTest } from "./runtime.js"; function resetPluginState() { clearPluginLoaderCache(); + clearPluginDiscoveryCache(); clearPluginManifestRegistryCache(); resetPluginRuntimeStateForTest(); } describe("registerPluginCliCommands browser plugin integration", () => { - beforeEach(async () => { - ({ clearPluginLoaderCache } = - await vi.importActual("./loader.js")); - ({ clearPluginManifestRegistryCache } = - await vi.importActual("./manifest-registry.js")); - ({ resetPluginRuntimeStateForTest } = - await vi.importActual("./runtime.js")); - ({ registerPluginCliCommands } = await vi.importActual("./cli.js")); + let bundledFixture: ReturnType | null = null; + + beforeEach(() => { + bundledFixture = createBundledBrowserPluginFixture(); + vi.stubEnv("OPENCLAW_BUNDLED_PLUGINS_DIR", bundledFixture.rootDir); resetPluginState(); }); afterEach(() => { resetPluginState(); + vi.unstubAllEnvs(); + bundledFixture?.cleanup(); + bundledFixture = null; }); it("registers the browser command from the bundled browser plugin", () => { - const program = new Command(); - registerPluginCliCommands( - program, - { + const registry = loadOpenClawPlugins({ + config: { plugins: { allow: ["browser"], }, } as OpenClawConfig, - undefined, - { pluginSdkResolution: "dist" }, - ); + cache: false, + env: { + ...process.env, + OPENCLAW_BUNDLED_PLUGINS_DIR: + bundledFixture?.rootDir ?? path.join(process.cwd(), "extensions"), + } as NodeJS.ProcessEnv, + }); - expect(program.commands.map((command) => command.name())).toContain("browser"); + expect(registry.cliRegistrars.flatMap((entry) => entry.commands)).toContain("browser"); }); it("omits the browser command when the bundled browser plugin is disabled", () => { - const program = new Command(); - registerPluginCliCommands( - program, - { + const registry = loadOpenClawPlugins({ + config: { plugins: { allow: ["browser"], entries: { @@ -58,10 +60,9 @@ describe("registerPluginCliCommands browser plugin integration", () => { }, }, } as OpenClawConfig, - undefined, - { pluginSdkResolution: "dist" }, - ); + cache: false, + }); - expect(program.commands.map((command) => command.name())).not.toContain("browser"); + expect(registry.cliRegistrars.flatMap((entry) => entry.commands)).not.toContain("browser"); }); }); diff --git a/test/helpers/browser-bundled-plugin-fixture.ts b/test/helpers/browser-bundled-plugin-fixture.ts new file mode 100644 index 00000000000..2cb3bdaa5f5 --- /dev/null +++ b/test/helpers/browser-bundled-plugin-fixture.ts @@ -0,0 +1,68 @@ +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +const BROWSER_FIXTURE_MANIFEST = { + id: "browser", + configSchema: { + type: "object", + additionalProperties: false, + properties: {}, + }, +}; + +const BROWSER_FIXTURE_ENTRY = `module.exports = { + id: "browser", + name: "Browser", + description: "Bundled browser fixture plugin", + configSchema: { + type: "object", + additionalProperties: false, + properties: {}, + }, + register(api) { + api.registerTool(() => ({ + name: "browser", + label: "browser", + description: "browser fixture tool", + parameters: { + type: "object", + properties: {}, + }, + async execute() { + return { + content: [{ type: "text", text: "ok" }], + details: {}, + }; + }, + })); + api.registerCli(({ program }) => { + program.command("browser"); + }, { commands: ["browser"] }); + api.registerGatewayMethod("browser.request", async () => ({ ok: true }), { + scope: "operator.write", + }); + api.registerService({ + id: "browser-control", + start() {}, + }); + }, +};`; + +export function createBundledBrowserPluginFixture(): { rootDir: string; cleanup: () => void } { + const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-browser-bundled-")); + const pluginDir = path.join(rootDir, "browser"); + fs.mkdirSync(pluginDir, { recursive: true }); + fs.writeFileSync( + path.join(pluginDir, "openclaw.plugin.json"), + JSON.stringify(BROWSER_FIXTURE_MANIFEST, null, 2), + "utf8", + ); + fs.writeFileSync(path.join(pluginDir, "index.js"), BROWSER_FIXTURE_ENTRY, "utf8"); + return { + rootDir, + cleanup() { + fs.rmSync(rootDir, { recursive: true, force: true }); + }, + }; +}