From 2fe38b0201d8deac31d0b4a52e4f0f5eccf274ff Mon Sep 17 00:00:00 2001 From: Zoher Ghadyali Date: Tue, 24 Mar 2026 16:23:09 -0700 Subject: [PATCH] fix(browser): add Edge LaunchServices bundle IDs for macOS default browser detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/browser/chrome.default-browser.test.ts | 48 ++++++++++++++++++++++ src/browser/chrome.executables.ts | 6 +++ 2 files changed, 54 insertions(+) diff --git a/src/browser/chrome.default-browser.test.ts b/src/browser/chrome.default-browser.test.ts index 6dfa5d05472..4c29939e820 100644 --- a/src/browser/chrome.default-browser.test.ts +++ b/src/browser/chrome.default-browser.test.ts @@ -82,6 +82,54 @@ describe("browser default executable detection", () => { 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[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(); diff --git a/src/browser/chrome.executables.ts b/src/browser/chrome.executables.ts index 6ef7bc0b155..9a45e92a0a9 100644 --- a/src/browser/chrome.executables.ts +++ b/src/browser/chrome.executables.ts @@ -23,6 +23,12 @@ const CHROMIUM_BUNDLE_IDS = new Set([ "com.microsoft.EdgeBeta", "com.microsoft.EdgeDev", "com.microsoft.EdgeCanary", + // Edge LaunchServices IDs (used in macOS default browser registration — + // these differ from CFBundleIdentifier and are what plutil returns) + "com.microsoft.edgemac", + "com.microsoft.edgemac.beta", + "com.microsoft.edgemac.dev", + "com.microsoft.edgemac.canary", "org.chromium.Chromium", "com.vivaldi.Vivaldi", "com.operasoftware.Opera",