From 0e3c7269cf648d23c11f0f711241f3e8d9ba6c35 Mon Sep 17 00:00:00 2001 From: Vance Ingalls Date: Tue, 14 Jul 2026 23:36:20 +0000 Subject: [PATCH] test(cli): parameterize browser-install error hint across darwin/win32/linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Miga review nit on #2443. Existing test only covered darwin/arm64 by default; parameterize via it.each across process.platform so each platform's Chrome-path hint from browserPathHintForPlatform is asserted in the rethrown error message. — Via Co-Authored-By: Claude Opus 4.7 --- packages/cli/src/browser/manager.test.ts | 102 +++++++++++++++-------- 1 file changed, 68 insertions(+), 34 deletions(-) diff --git a/packages/cli/src/browser/manager.test.ts b/packages/cli/src/browser/manager.test.ts index 6da857cee..edc522947 100644 --- a/packages/cli/src/browser/manager.test.ts +++ b/packages/cli/src/browser/manager.test.ts @@ -703,15 +703,18 @@ describe("installWithCorruptArchiveRecovery", () => { // time and had to discover `HYPERFRAMES_BROWSER_PATH` on their own. The raw // error propagated straight through `downloadBrowser` without naming the // escape hatch. This guards the rewrap so the next reporter sees the hint. +// +// Parameterized across all three OS families because `browserPathHintForPlatform` +// branches on `process.platform` and each branch has to survive on its own — +// the field reporter was macOS but the same rewrap is what a Windows or Linux +// (non-ARM) user would see next time providers fail, and each branch names a +// different Chrome install path that has to be spelled correctly. describe("downloadBrowser — install failure surfaces HYPERFRAMES_BROWSER_PATH hint", () => { const origPlatform = process.platform; const origArch = process.arch; beforeEach(() => { vi.resetModules(); - // Simulate the reporter's environment: macOS on Apple Silicon. - Object.defineProperty(process, "platform", { value: "darwin", configurable: true }); - Object.defineProperty(process, "arch", { value: "arm64", configurable: true }); delete process.env["HYPERFRAMES_BROWSER_PATH"]; installChildProcessMocks(); }); @@ -726,40 +729,71 @@ describe("downloadBrowser — install failure surfaces HYPERFRAMES_BROWSER_PATH vi.doUnmock("@puppeteer/browsers"); }); - it("rethrows a non-corrupt install failure with an HYPERFRAMES_BROWSER_PATH hint and preserves the original via cause", async () => { - // No cache, no system Chrome — forces the download-of-last-resort path - // that ends in @puppeteer/browsers install(). - installFsMocks({ existing: new Set([CACHE_ROOT]) }); - const rawMsg = "All providers failed for chrome-headless-shell 152.0.7928.2"; - const originalError = new Error(rawMsg); - installPuppeteerBrowsersMock({ - installedInHfCache: [], - installImpl: async () => { - throw originalError; - }, - }); + // Note: linux/arm64 is deliberately excluded — `downloadBrowser` short-circuits + // into `ensureLinuxArmBrowser` before it ever reaches the install() call this + // suite guards (chrome-headless-shell has no linux-arm64 build; see `isLinuxArm` + // at the top of `downloadBrowser`). Use linux/x64 to exercise the linux branch + // of `browserPathHintForPlatform`. + it.each([ + { + label: "darwin/arm64", + platform: "darwin", + arch: "arm64", + expectedPathHint: "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", + }, + { + label: "win32/x64", + platform: "win32", + arch: "x64", + expectedPathHint: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe", + }, + { + label: "linux/x64", + platform: "linux", + arch: "x64", + expectedPathHint: "/usr/bin/google-chrome", + }, + ])( + "rethrows a non-corrupt install failure with an HYPERFRAMES_BROWSER_PATH hint and preserves the original via cause ($label)", + async ({ platform, arch, expectedPathHint }) => { + Object.defineProperty(process, "platform", { value: platform, configurable: true }); + Object.defineProperty(process, "arch", { value: arch, configurable: true }); - const { ensureBrowser } = await import("./manager.js"); + // No cache, no system Chrome — forces the download-of-last-resort path + // that ends in @puppeteer/browsers install(). + installFsMocks({ existing: new Set([CACHE_ROOT]) }); + const rawMsg = "All providers failed for chrome-headless-shell 152.0.7928.2"; + const originalError = new Error(rawMsg); + installPuppeteerBrowsersMock({ + installedInHfCache: [], + installImpl: async () => { + throw originalError; + }, + }); - let caught: unknown; - try { - await ensureBrowser(); - } catch (err) { - caught = err; - } + const { ensureBrowser } = await import("./manager.js"); - expect(caught).toBeInstanceOf(Error); - const msg = (caught as Error).message; - // Names the escape-hatch env var by name (that's the entire point). - expect(msg).toContain("HYPERFRAMES_BROWSER_PATH"); - // Includes the platform-specific example path (macOS here). - expect(msg).toContain("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"); - // Keeps the original provider-failure text so the user can still - // diagnose the underlying cause from the surfaced message. - expect(msg).toContain(rawMsg); - // Structured `cause` chain intact for tooling that walks it. - expect((caught as Error).cause).toBe(originalError); - }); + let caught: unknown; + try { + await ensureBrowser(); + } catch (err) { + caught = err; + } + + expect(caught).toBeInstanceOf(Error); + const msg = (caught as Error).message; + // Names the escape-hatch env var by name (that's the entire point). + expect(msg).toContain("HYPERFRAMES_BROWSER_PATH"); + // Includes the platform-specific example path from + // `browserPathHintForPlatform`. + expect(msg).toContain(expectedPathHint); + // Keeps the original provider-failure text so the user can still + // diagnose the underlying cause from the surfaced message. + expect(msg).toContain(rawMsg); + // Structured `cause` chain intact for tooling that walks it. + expect((caught as Error).cause).toBe(originalError); + }, + ); }); // Regression guard for HF#2103: `hyperframes render` hung forever on macOS