diff --git a/extensions/browser/src/doctor-browser.test.ts b/extensions/browser/src/doctor-browser.test.ts index 83cb4dab01ab..91996cb6ba12 100644 --- a/extensions/browser/src/doctor-browser.test.ts +++ b/extensions/browser/src/doctor-browser.test.ts @@ -1,10 +1,15 @@ // Browser tests cover doctor browser plugin behavior. -import { describe, expect, it, vi } from "vitest"; +import fs from "node:fs"; +import path from "node:path"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { useAutoCleanupTempDirTracker } from "../test-support.js"; import { maybeArchiveLegacyClawdBrowserProfileResidue, noteChromeMcpBrowserReadiness, } from "./doctor-browser.js"; +const tempDirs = useAutoCleanupTempDirTracker(afterEach); + function requireFirstNoteText(noteFn: ReturnType): string { const [call] = noteFn.mock.calls; if (!call) { @@ -301,6 +306,55 @@ describe("browser doctor readiness", () => { }); }); +describe("browser plugin package layout", () => { + async function expectRepairLayout(layout: "source" | "built") { + const packageRoot = fs.realpathSync(tempDirs.make("openclaw-browser-doctor-")); + const moduleDir = layout === "source" ? path.join(packageRoot, "src") : packageRoot; + const modulePath = path.join( + moduleDir, + layout === "source" ? "doctor-browser.ts" : "browser-doctor.js", + ); + fs.mkdirSync(moduleDir, { recursive: true }); + fs.writeFileSync(path.join(packageRoot, "package.json"), "{}"); + + const repairOwnedChromeExtensionNativeHosts = vi.fn(async () => ({ + changes: [], + warnings: [], + })); + vi.resetModules(); + vi.doMock("node:url", async () => ({ + ...(await vi.importActual("node:url")), + fileURLToPath: () => modulePath, + })); + vi.doMock("./browser/extension-install.js", () => ({ + browserExtensionStatus: vi.fn(), + FOUNDATION_CHROME_WEB_STORE_URL: "https://example.invalid", + repairOwnedChromeExtensionNativeHosts, + })); + + try { + const { maybeRepairOwnedChromeExtensionNativeHosts } = await import("./doctor-browser.js"); + await maybeRepairOwnedChromeExtensionNativeHosts(); + expect(repairOwnedChromeExtensionNativeHosts).toHaveBeenCalledWith({ + bundledDir: path.join(packageRoot, "chrome-extension"), + pluginRoot: packageRoot, + }); + } finally { + vi.doUnmock("node:url"); + vi.doUnmock("./browser/extension-install.js"); + vi.resetModules(); + } + } + + it("resolves assets from the source package root", async () => { + await expectRepairLayout("source"); + }); + + it("resolves assets from the built package root", async () => { + await expectRepairLayout("built"); + }); +}); + describe("legacy clawd browser profile cleanup", () => { it("archives stale clawd residue with the safe trash mover", async () => { const movePathToTrash = vi.fn(async () => "/tmp/openclaw-home/browser/.trash/clawd"); diff --git a/extensions/browser/src/doctor-browser.ts b/extensions/browser/src/doctor-browser.ts index abbada7ad8b0..3df76b566cc1 100644 --- a/extensions/browser/src/doctor-browser.ts +++ b/extensions/browser/src/doctor-browser.ts @@ -35,7 +35,10 @@ const REMOTE_DEBUGGING_PAGES = [ "brave://inspect/#remote-debugging", "edge://inspect/#remote-debugging", ].join(", "); -const BROWSER_PLUGIN_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const BROWSER_MODULE_DIR = path.dirname(fileURLToPath(import.meta.url)); +const BROWSER_PLUGIN_ROOT = fs.existsSync(path.join(BROWSER_MODULE_DIR, "package.json")) + ? BROWSER_MODULE_DIR + : path.dirname(BROWSER_MODULE_DIR); const BUNDLED_CHROME_EXTENSION_DIR = path.join(BROWSER_PLUGIN_ROOT, "chrome-extension"); type ExistingSessionProfile = {