fix(studio): resolve Chrome on Windows (#2878)

This commit is contained in:
Miguel Ángel
2026-07-29 17:31:40 +02:00
committed by GitHub
parent 6cab53a681
commit d8d626537b
2 changed files with 40 additions and 7 deletions
+19 -1
View File
@@ -1,6 +1,7 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const launch = vi.fn();
const originalBrowserPath = process.env["HYPERFRAMES_BROWSER_PATH"];
vi.mock("puppeteer-core", () => ({
default: { launch },
@@ -8,10 +9,19 @@ vi.mock("puppeteer-core", () => ({
describe("generateThumbnail", () => {
beforeEach(() => {
process.env["HYPERFRAMES_BROWSER_PATH"] = process.execPath;
launch.mockReset();
launch.mockRejectedValue(new Error("browser launch failed"));
});
afterEach(() => {
if (originalBrowserPath === undefined) {
delete process.env["HYPERFRAMES_BROWSER_PATH"];
} else {
process.env["HYPERFRAMES_BROWSER_PATH"] = originalBrowserPath;
}
});
it("contains browser launch failures and retries them on the next request", async () => {
const { generateThumbnail } = await import("./vite.browser");
const options = {
@@ -47,4 +57,12 @@ describe("findSystemChrome", () => {
).toBe("/custom/browser");
expect(pathExists).toHaveBeenCalledTimes(1);
});
it("finds a standard Windows Chrome installation", async () => {
const { findSystemChrome } = await import("./vite.browser");
const chromePath = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";
const pathExists = vi.fn((path: string) => path === chromePath);
expect(findSystemChrome({}, pathExists, "win32")).toBe(chromePath);
});
});
+21 -6
View File
@@ -2,6 +2,7 @@
import { existsSync } from "node:fs";
import { createHash } from "node:crypto";
import { win32 as pathWin32 } from "node:path";
import {
createStudioDevRenderBodyScripts,
readStudioDevManualEditManifestContent,
@@ -14,20 +15,34 @@ import { seekThumbnailPreview } from "./vite.thumbnail";
let _browser: import("puppeteer-core").Browser | null = null;
let _browserLaunchPromise: Promise<import("puppeteer-core").Browser> | null = null;
const CHROME_PATHS = [
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"/usr/bin/google-chrome",
"/usr/bin/chromium-browser",
];
function systemChromePaths(env: NodeJS.ProcessEnv, platform: NodeJS.Platform): string[] {
if (platform === "win32") {
const programFiles = env["PROGRAMFILES"] ?? "C:\\Program Files";
const programFilesX86 = env["PROGRAMFILES(X86)"] ?? "C:\\Program Files (x86)";
const localAppData = env["LOCALAPPDATA"];
return [
pathWin32.join(programFiles, "Google", "Chrome", "Application", "chrome.exe"),
pathWin32.join(programFilesX86, "Google", "Chrome", "Application", "chrome.exe"),
...(localAppData
? [pathWin32.join(localAppData, "Google", "Chrome", "Application", "chrome.exe")]
: []),
];
}
if (platform === "darwin") {
return ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"];
}
return ["/usr/bin/google-chrome", "/usr/bin/chromium-browser"];
}
/** Resolve the same explicit browser overrides used by the CLI before system paths. */
export function findSystemChrome(
env: NodeJS.ProcessEnv = process.env,
pathExists: (path: string) => boolean = existsSync,
platform: NodeJS.Platform = process.platform,
): string | undefined {
const override = env["HYPERFRAMES_BROWSER_PATH"] ?? env["PRODUCER_HEADLESS_SHELL_PATH"];
if (override && pathExists(override)) return override;
return CHROME_PATHS.find((path) => pathExists(path));
return systemChromePaths(env, platform).find((path) => pathExists(path));
}
async function getSharedBrowser(): Promise<import("puppeteer-core").Browser | null> {