mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-28 02:12:07 +00:00
macOS registers Edge as 'com.microsoft.edgemac' in LaunchServices, which differs from the CFBundleIdentifier 'com.microsoft.Edge' in the app's own Info.plist. Without recognising the LaunchServices IDs, Edge users who set Edge as their default browser are not detected as having a Chromium browser. Add the four com.microsoft.edgemac* variants to CHROMIUM_BUNDLE_IDS and a corresponding test that mocks the LaunchServices → osascript resolution path for Edge.
145 lines
5.1 KiB
TypeScript
145 lines
5.1 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
vi.mock("node:child_process", () => ({
|
|
execFileSync: vi.fn(),
|
|
}));
|
|
vi.mock("node:fs", () => {
|
|
const existsSync = vi.fn();
|
|
const readFileSync = vi.fn();
|
|
const module = { existsSync, readFileSync };
|
|
return {
|
|
...module,
|
|
default: module,
|
|
};
|
|
});
|
|
vi.mock("node:os", () => {
|
|
const homedir = vi.fn();
|
|
const module = { homedir };
|
|
return {
|
|
...module,
|
|
default: module,
|
|
};
|
|
});
|
|
import { execFileSync } from "node:child_process";
|
|
import * as fs from "node:fs";
|
|
import os from "node:os";
|
|
|
|
async function loadResolveBrowserExecutableForPlatform() {
|
|
const mod = await import("./chrome.executables.js");
|
|
return mod.resolveBrowserExecutableForPlatform;
|
|
}
|
|
|
|
describe("browser default executable detection", () => {
|
|
const launchServicesPlist = "com.apple.launchservices.secure.plist";
|
|
const chromeExecutablePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
|
|
let resolveBrowserExecutableForPlatform: Awaited<
|
|
ReturnType<typeof loadResolveBrowserExecutableForPlatform>
|
|
>;
|
|
|
|
function mockMacDefaultBrowser(bundleId: string, appPath = ""): void {
|
|
vi.mocked(execFileSync).mockImplementation((cmd, args) => {
|
|
const argsStr = Array.isArray(args) ? args.join(" ") : "";
|
|
if (cmd === "/usr/bin/plutil" && argsStr.includes("LSHandlers")) {
|
|
return JSON.stringify([{ LSHandlerURLScheme: "http", LSHandlerRoleAll: bundleId }]);
|
|
}
|
|
if (cmd === "/usr/bin/osascript" && argsStr.includes("path to application id")) {
|
|
return appPath;
|
|
}
|
|
if (cmd === "/usr/bin/defaults") {
|
|
return "Google Chrome";
|
|
}
|
|
return "";
|
|
});
|
|
}
|
|
|
|
function mockChromeExecutableExists(): void {
|
|
vi.mocked(fs.existsSync).mockImplementation((p) => {
|
|
const value = String(p);
|
|
if (value.includes(launchServicesPlist)) {
|
|
return true;
|
|
}
|
|
return value.includes(chromeExecutablePath);
|
|
});
|
|
}
|
|
|
|
beforeEach(async () => {
|
|
vi.resetModules();
|
|
vi.clearAllMocks();
|
|
vi.mocked(os.homedir).mockReturnValue("/Users/test");
|
|
resolveBrowserExecutableForPlatform = await loadResolveBrowserExecutableForPlatform();
|
|
});
|
|
|
|
it("prefers default Chromium browser on macOS", async () => {
|
|
mockMacDefaultBrowser("com.google.Chrome", "/Applications/Google Chrome.app");
|
|
mockChromeExecutableExists();
|
|
|
|
const exe = resolveBrowserExecutableForPlatform(
|
|
{} as Parameters<typeof resolveBrowserExecutableForPlatform>[0],
|
|
"darwin",
|
|
);
|
|
|
|
expect(exe?.path).toContain("Google Chrome.app/Contents/MacOS/Google Chrome");
|
|
expect(exe?.kind).toBe("chrome");
|
|
});
|
|
|
|
it("detects Edge via LaunchServices bundle ID (com.microsoft.edgemac)", async () => {
|
|
const edgeExecutablePath = "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge";
|
|
// macOS LaunchServices registers Edge as "com.microsoft.edgemac", which
|
|
// differs from the CFBundleIdentifier "com.microsoft.Edge" in the app's
|
|
// own Info.plist. Both must be recognised.
|
|
//
|
|
// The existsSync mock deliberately only returns true for the Edge path
|
|
// when checked via the resolved osascript/defaults path — Chrome's
|
|
// fallback candidate path is the only other "existing" binary. This
|
|
// ensures the test fails if the default-browser detection branch is
|
|
// broken, because the fallback candidate list would return Chrome, not
|
|
// Edge.
|
|
vi.mocked(execFileSync).mockImplementation((cmd, args) => {
|
|
const argsStr = Array.isArray(args) ? args.join(" ") : "";
|
|
if (cmd === "/usr/bin/plutil" && argsStr.includes("LSHandlers")) {
|
|
return JSON.stringify([
|
|
{ LSHandlerURLScheme: "http", LSHandlerRoleAll: "com.microsoft.edgemac" },
|
|
]);
|
|
}
|
|
if (cmd === "/usr/bin/osascript" && argsStr.includes("path to application id")) {
|
|
return "/Applications/Microsoft Edge.app/";
|
|
}
|
|
if (cmd === "/usr/bin/defaults") {
|
|
return "Microsoft Edge";
|
|
}
|
|
return "";
|
|
});
|
|
vi.mocked(fs.existsSync).mockImplementation((p) => {
|
|
const value = String(p);
|
|
if (value.includes(launchServicesPlist)) {
|
|
return true;
|
|
}
|
|
// Only Edge (via osascript resolution) and Chrome (fallback candidate)
|
|
// "exist". If default-browser detection breaks, the resolver would
|
|
// return Chrome from the fallback list — not Edge — failing the assert.
|
|
return value === edgeExecutablePath || value.includes(chromeExecutablePath);
|
|
});
|
|
const resolveBrowserExecutableForPlatform = await loadResolveBrowserExecutableForPlatform();
|
|
|
|
const exe = resolveBrowserExecutableForPlatform(
|
|
{} as Parameters<typeof resolveBrowserExecutableForPlatform>[0],
|
|
"darwin",
|
|
);
|
|
|
|
expect(exe?.path).toBe(edgeExecutablePath);
|
|
expect(exe?.kind).toBe("edge");
|
|
});
|
|
|
|
it("falls back when default browser is non-Chromium on macOS", async () => {
|
|
mockMacDefaultBrowser("com.apple.Safari");
|
|
mockChromeExecutableExists();
|
|
|
|
const exe = resolveBrowserExecutableForPlatform(
|
|
{} as Parameters<typeof resolveBrowserExecutableForPlatform>[0],
|
|
"darwin",
|
|
);
|
|
|
|
expect(exe?.path).toContain("Google Chrome.app/Contents/MacOS/Google Chrome");
|
|
});
|
|
});
|