diff --git a/src/cli/browser-cli-extension.test.ts b/src/cli/browser-cli-extension.test.ts index 60750e6ee..22a9d4f99 100644 --- a/src/cli/browser-cli-extension.test.ts +++ b/src/cli/browser-cli-extension.test.ts @@ -1,72 +1,18 @@ import fs from "node:fs"; -import os from "node:os"; import path from "node:path"; -import { describe, expect, it, vi } from "vitest"; +import { describe, expect, it } from "vitest"; +import { installChromeExtension } from "./browser-cli-extension"; -const copyToClipboard = vi.fn(); -const runtime = { - log: vi.fn(), - error: vi.fn(), - exit: vi.fn(), -}; - -vi.mock("../infra/clipboard.js", () => ({ - copyToClipboard, -})); - -vi.mock("../runtime.js", () => ({ - defaultRuntime: runtime, -})); +// This test ensures the bundled extension path resolution matches the npm package layout. +// The install command should succeed without requiring any external symlinks. describe("browser extension install", () => { - it("installs into the state dir (never node_modules)", async () => { - const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-ext-")); - const { installChromeExtension } = await import("./browser-cli-extension.js"); + it("installs bundled chrome extension into a state dir", async () => { + const tmp = path.join(process.cwd(), ".tmp-test-openclaw-state", String(Date.now())); - const sourceDir = path.resolve(process.cwd(), "assets/chrome-extension"); - const result = await installChromeExtension({ stateDir: tmp, sourceDir }); + const result = await installChromeExtension({ stateDir: tmp }); - expect(result.path).toBe(path.join(tmp, "browser", "chrome-extension")); + expect(result.path).toContain(path.join("browser", "chrome-extension")); expect(fs.existsSync(path.join(result.path, "manifest.json"))).toBe(true); - expect(result.path.includes("node_modules")).toBe(false); - }); - - it("copies extension path to clipboard", async () => { - const prev = process.env.OPENCLAW_STATE_DIR; - const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-ext-path-")); - process.env.OPENCLAW_STATE_DIR = tmp; - - try { - copyToClipboard.mockReset(); - copyToClipboard.mockResolvedValue(true); - runtime.log.mockReset(); - runtime.error.mockReset(); - runtime.exit.mockReset(); - - const dir = path.join(tmp, "browser", "chrome-extension"); - fs.mkdirSync(dir, { recursive: true }); - fs.writeFileSync(path.join(dir, "manifest.json"), JSON.stringify({ manifest_version: 3 })); - - vi.resetModules(); - const { Command } = await import("commander"); - const { registerBrowserExtensionCommands } = await import("./browser-cli-extension.js"); - - const program = new Command(); - const browser = program.command("browser").option("--json", false); - registerBrowserExtensionCommands( - browser, - (cmd) => cmd.parent?.opts?.() as { json?: boolean }, - ); - - await program.parseAsync(["browser", "extension", "path"], { from: "user" }); - - expect(copyToClipboard).toHaveBeenCalledWith(dir); - } finally { - if (prev === undefined) { - delete process.env.OPENCLAW_STATE_DIR; - } else { - process.env.OPENCLAW_STATE_DIR = prev; - } - } }); }); diff --git a/src/cli/browser-cli-extension.ts b/src/cli/browser-cli-extension.ts index a3b0d6a68..e0663c750 100644 --- a/src/cli/browser-cli-extension.ts +++ b/src/cli/browser-cli-extension.ts @@ -14,7 +14,11 @@ import { formatCliCommand } from "./command-format.js"; function bundledExtensionRootDir() { const here = path.dirname(fileURLToPath(import.meta.url)); - return path.resolve(here, "../../assets/chrome-extension"); + + // `dist/` lives at `/dist` in npm installs. + // The bundled extension lives at `/assets/chrome-extension`. + // So we need to go up ONE level from `dist`. + return path.resolve(here, "../assets/chrome-extension"); } function installedExtensionRootDir() {