Skip to content

Commit a64c13a

Browse files
committed
fix(browser): ignore blank Windows install roots
1 parent 7c4292e commit a64c13a

2 files changed

Lines changed: 32 additions & 7 deletions

File tree

extensions/browser/src/browser/chrome.default-browser.test.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Browser tests cover chromeefault browser plugin behavior.
2-
import { beforeEach, describe, expect, it, vi } from "vitest";
2+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
33

44
vi.mock("node:child_process", async () => {
55
const { mockNodeBuiltinModule } = await import("openclaw/plugin-sdk/test-node-mocks");
@@ -72,6 +72,10 @@ describe("browser default executable detection", () => {
7272
vi.mocked(os.homedir).mockReturnValue("/Users/test");
7373
});
7474

75+
afterEach(() => {
76+
vi.unstubAllEnvs();
77+
});
78+
7579
it("prefers default Chromium browser on macOS", () => {
7680
mockMacDefaultBrowser("com.google.Chrome", "/Applications/Google Chrome.app");
7781
mockChromeExecutableExists();
@@ -214,6 +218,25 @@ describe("browser default executable detection", () => {
214218
expect(exe?.path.toLowerCase()).toMatch(/\\google\\chrome\\application\\chrome\.exe$/);
215219
});
216220

221+
it("uses standard Windows install roots when ProgramFiles overrides are blank", () => {
222+
vi.stubEnv("ProgramFiles", " ");
223+
vi.stubEnv("ProgramFiles(x86)", "");
224+
vi.mocked(fs.existsSync).mockImplementation(
225+
(candidate) =>
226+
String(candidate) === "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
227+
);
228+
229+
expect(
230+
resolveBrowserExecutableForPlatform(
231+
{} as Parameters<typeof resolveBrowserExecutableForPlatform>[0],
232+
"win32",
233+
),
234+
).toEqual({
235+
kind: "chrome",
236+
path: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
237+
});
238+
});
239+
217240
it("canonicalizes an explicitly configured Opera launcher", () => {
218241
const installDir = "C:\\Users\\test\\AppData\\Local\\Programs\\Opera";
219242
const launcher = `${installDir}\\launcher.exe`;

extensions/browser/src/browser/chrome.executables.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -666,10 +666,11 @@ function findGoogleChromeExecutableLinux(): BrowserExecutable | null {
666666

667667
/** Find the best Chromium-family executable on Windows. */
668668
function findChromeExecutableWindows(): BrowserExecutable | null {
669-
const localAppData = process.env.LOCALAPPDATA ?? "";
670-
const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
669+
const localAppData = normalizeOptionalString(process.env.LOCALAPPDATA) ?? "";
670+
const programFiles = normalizeOptionalString(process.env.ProgramFiles) ?? "C:\\Program Files";
671671
// Must use bracket notation: variable name contains parentheses.
672-
const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
672+
const programFilesX86 =
673+
normalizeOptionalString(process.env["ProgramFiles(x86)"]) ?? "C:\\Program Files (x86)";
673674
const joinWin = path.win32.join;
674675
const candidates: Array<BrowserExecutable> = [];
675676

@@ -736,9 +737,10 @@ function findChromeExecutableWindows(): BrowserExecutable | null {
736737
}
737738

738739
function findGoogleChromeExecutableWindows(): BrowserExecutable | null {
739-
const localAppData = process.env.LOCALAPPDATA ?? "";
740-
const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
741-
const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
740+
const localAppData = normalizeOptionalString(process.env.LOCALAPPDATA) ?? "";
741+
const programFiles = normalizeOptionalString(process.env.ProgramFiles) ?? "C:\\Program Files";
742+
const programFilesX86 =
743+
normalizeOptionalString(process.env["ProgramFiles(x86)"]) ?? "C:\\Program Files (x86)";
742744
const joinWin = path.win32.join;
743745
const candidates: string[] = [];
744746

0 commit comments

Comments
 (0)