"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var registry_exports = {}; __export(registry_exports, { Registry: () => Registry, browserDirectoryToMarkerFilePath: () => browserDirectoryToMarkerFilePath, buildPlaywrightCLICommand: () => buildPlaywrightCLICommand, defaultCacheDirectory: () => defaultCacheDirectory, defaultRegistryDirectory: () => defaultRegistryDirectory, findChromiumChannelBestEffort: () => findChromiumChannelBestEffort, installBrowsersForNpmInstall: () => installBrowsersForNpmInstall, registry: () => registry, registryDirectory: () => registryDirectory, writeDockerVersion: () => import_dependencies3.writeDockerVersion }); module.exports = __toCommonJS(registry_exports); var import_fs = __toESM(require("fs")); var import_os = __toESM(require("os")); var import_path = __toESM(require("path")); var util = __toESM(require("util")); var import_browserFetcher = require("./browserFetcher"); var import_dependencies = require("./dependencies"); var import_dependencies2 = require("./dependencies"); var import_utils = require("../../utils"); var import_ascii = require("../utils/ascii"); var import_debugLogger = require("../utils/debugLogger"); var import_hostPlatform = require("../utils/hostPlatform"); var import_network = require("../utils/network"); var import_spawnAsync = require("../utils/spawnAsync"); var import_userAgent = require("../utils/userAgent"); var import_utilsBundle = require("../../utilsBundle"); var import_fileUtils = require("../utils/fileUtils"); var import_dependencies3 = require("./dependencies"); const PACKAGE_PATH = import_path.default.join(__dirname, "..", "..", ".."); const BIN_PATH = import_path.default.join(__dirname, "..", "..", "..", "bin"); const PLAYWRIGHT_CDN_MIRRORS = [ "https://cdn.playwright.dev/dbazure/download/playwright", // ESRP CDN "https://playwright.download.prss.microsoft.com/dbazure/download/playwright", // Directly hit ESRP CDN "https://cdn.playwright.dev" // Hit the Storage Bucket directly ]; if (process.env.PW_TEST_CDN_THAT_SHOULD_WORK) { for (let i = 0; i < PLAYWRIGHT_CDN_MIRRORS.length; i++) { const cdn = PLAYWRIGHT_CDN_MIRRORS[i]; if (cdn !== process.env.PW_TEST_CDN_THAT_SHOULD_WORK) { const parsedCDN = new URL(cdn); parsedCDN.hostname = parsedCDN.hostname + ".does-not-resolve.playwright.dev"; PLAYWRIGHT_CDN_MIRRORS[i] = parsedCDN.toString(); } } } const EXECUTABLE_PATHS = { "chromium": { "": void 0, "linux-x64": ["chrome-linux64", "chrome"], "linux-arm64": ["chrome-linux", "chrome"], // non-cft build "mac-x64": ["chrome-mac-x64", "Google Chrome for Testing.app", "Contents", "MacOS", "Google Chrome for Testing"], "mac-arm64": ["chrome-mac-arm64", "Google Chrome for Testing.app", "Contents", "MacOS", "Google Chrome for Testing"], "win-x64": ["chrome-win64", "chrome.exe"] }, "chromium-headless-shell": { "": void 0, "linux-x64": ["chrome-headless-shell-linux64", "chrome-headless-shell"], "linux-arm64": ["chrome-linux", "headless_shell"], // non-cft build "mac-x64": ["chrome-headless-shell-mac-x64", "chrome-headless-shell"], "mac-arm64": ["chrome-headless-shell-mac-arm64", "chrome-headless-shell"], "win-x64": ["chrome-headless-shell-win64", "chrome-headless-shell.exe"] }, "chromium-tip-of-tree": { "": void 0, "linux-x64": ["chrome-linux64", "chrome"], "linux-arm64": ["chrome-linux", "chrome"], // non-cft build "mac-x64": ["chrome-mac-x64", "Google Chrome for Testing.app", "Contents", "MacOS", "Google Chrome for Testing"], "mac-arm64": ["chrome-mac-arm64", "Google Chrome for Testing.app", "Contents", "MacOS", "Google Chrome for Testing"], "win-x64": ["chrome-win64", "chrome.exe"] }, "chromium-tip-of-tree-headless-shell": { "": void 0, "linux-x64": ["chrome-headless-shell-linux64", "chrome-headless-shell"], "linux-arm64": ["chrome-linux", "headless_shell"], // non-cft build "mac-x64": ["chrome-headless-shell-mac-x64", "chrome-headless-shell"], "mac-arm64": ["chrome-headless-shell-mac-arm64", "chrome-headless-shell"], "win-x64": ["chrome-headless-shell-win64", "chrome-headless-shell.exe"] }, "firefox": { "": void 0, "linux-x64": ["firefox", "firefox"], "linux-arm64": ["firefox", "firefox"], "mac-x64": ["firefox", "Nightly.app", "Contents", "MacOS", "firefox"], "mac-arm64": ["firefox", "Nightly.app", "Contents", "MacOS", "firefox"], "win-x64": ["firefox", "firefox.exe"] }, "webkit": { "": void 0, "linux-x64": ["pw_run.sh"], "linux-arm64": ["pw_run.sh"], "mac-x64": ["pw_run.sh"], "mac-arm64": ["pw_run.sh"], "win-x64": ["Playwright.exe"] }, "ffmpeg": { "": void 0, "linux-x64": ["ffmpeg-linux"], "linux-arm64": ["ffmpeg-linux"], "mac-x64": ["ffmpeg-mac"], "mac-arm64": ["ffmpeg-mac"], "win-x64": ["ffmpeg-win64.exe"] }, "winldd": { "": void 0, "linux-x64": void 0, "linux-arm64": void 0, "mac-x64": void 0, "mac-arm64": void 0, "win-x64": ["PrintDeps.exe"] } }; function cftUrl(suffix) { return ({ browserVersion }) => { return { path: `builds/cft/${browserVersion}/${suffix}`, mirrors: [ "https://cdn.playwright.dev" ] }; }; } const DOWNLOAD_PATHS = { "chromium": { "": void 0, "ubuntu18.04-x64": void 0, "ubuntu20.04-x64": cftUrl("linux64/chrome-linux64.zip"), "ubuntu22.04-x64": cftUrl("linux64/chrome-linux64.zip"), "ubuntu24.04-x64": cftUrl("linux64/chrome-linux64.zip"), "ubuntu18.04-arm64": void 0, "ubuntu20.04-arm64": "builds/chromium/%s/chromium-linux-arm64.zip", "ubuntu22.04-arm64": "builds/chromium/%s/chromium-linux-arm64.zip", "ubuntu24.04-arm64": "builds/chromium/%s/chromium-linux-arm64.zip", "debian11-x64": cftUrl("linux64/chrome-linux64.zip"), "debian11-arm64": "builds/chromium/%s/chromium-linux-arm64.zip", "debian12-x64": cftUrl("linux64/chrome-linux64.zip"), "debian12-arm64": "builds/chromium/%s/chromium-linux-arm64.zip", "debian13-x64": cftUrl("linux64/chrome-linux64.zip"), "debian13-arm64": "builds/chromium/%s/chromium-linux-arm64.zip", "mac10.13": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac10.14": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac10.15": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac11": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac11-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"), "mac12": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac12-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"), "mac13": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac13-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"), "mac14": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac14-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"), "mac15": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac15-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"), "win64": cftUrl("win64/chrome-win64.zip") }, "chromium-headless-shell": { "": void 0, "ubuntu18.04-x64": void 0, "ubuntu20.04-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"), "ubuntu22.04-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"), "ubuntu24.04-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"), "ubuntu18.04-arm64": void 0, "ubuntu20.04-arm64": "builds/chromium/%s/chromium-headless-shell-linux-arm64.zip", "ubuntu22.04-arm64": "builds/chromium/%s/chromium-headless-shell-linux-arm64.zip", "ubuntu24.04-arm64": "builds/chromium/%s/chromium-headless-shell-linux-arm64.zip", "debian11-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"), "debian11-arm64": "builds/chromium/%s/chromium-headless-shell-linux-arm64.zip", "debian12-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"), "debian12-arm64": "builds/chromium/%s/chromium-headless-shell-linux-arm64.zip", "debian13-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"), "debian13-arm64": "builds/chromium/%s/chromium-headless-shell-linux-arm64.zip", "mac10.13": void 0, "mac10.14": void 0, "mac10.15": void 0, "mac11": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"), "mac11-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"), "mac12": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"), "mac12-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"), "mac13": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"), "mac13-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"), "mac14": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"), "mac14-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"), "mac15": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"), "mac15-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"), "win64": cftUrl("win64/chrome-headless-shell-win64.zip") }, "chromium-tip-of-tree": { "": void 0, "ubuntu18.04-x64": void 0, "ubuntu20.04-x64": cftUrl("linux64/chrome-linux64.zip"), "ubuntu22.04-x64": cftUrl("linux64/chrome-linux64.zip"), "ubuntu24.04-x64": cftUrl("linux64/chrome-linux64.zip"), "ubuntu18.04-arm64": void 0, "ubuntu20.04-arm64": "builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip", "ubuntu22.04-arm64": "builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip", "ubuntu24.04-arm64": "builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip", "debian11-x64": cftUrl("linux64/chrome-linux64.zip"), "debian11-arm64": "builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip", "debian12-x64": cftUrl("linux64/chrome-linux64.zip"), "debian12-arm64": "builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip", "debian13-x64": cftUrl("linux64/chrome-linux64.zip"), "debian13-arm64": "builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-linux-arm64.zip", "mac10.13": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac10.14": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac10.15": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac11": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac11-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"), "mac12": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac12-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"), "mac13": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac13-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"), "mac14": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac14-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"), "mac15": cftUrl("mac-x64/chrome-mac-x64.zip"), "mac15-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"), "win64": cftUrl("win64/chrome-win64.zip") }, "chromium-tip-of-tree-headless-shell": { "": void 0, "ubuntu18.04-x64": void 0, "ubuntu20.04-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"), "ubuntu22.04-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"), "ubuntu24.04-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"), "ubuntu18.04-arm64": void 0, "ubuntu20.04-arm64": "builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-headless-shell-linux-arm64.zip", "ubuntu22.04-arm64": "builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-headless-shell-linux-arm64.zip", "ubuntu24.04-arm64": "builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-headless-shell-linux-arm64.zip", "debian11-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"), "debian11-arm64": "builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-headless-shell-linux-arm64.zip", "debian12-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"), "debian12-arm64": "builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-headless-shell-linux-arm64.zip", "debian13-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"), "debian13-arm64": "builds/chromium-tip-of-tree/%s/chromium-tip-of-tree-headless-shell-linux-arm64.zip", "mac10.13": void 0, "mac10.14": void 0, "mac10.15": void 0, "mac11": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"), "mac11-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"), "mac12": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"), "mac12-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"), "mac13": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"), "mac13-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"), "mac14": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"), "mac14-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"), "mac15": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"), "mac15-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"), "win64": cftUrl("win64/chrome-headless-shell-win64.zip") }, "firefox": { "": void 0, "ubuntu18.04-x64": void 0, "ubuntu20.04-x64": "builds/firefox/%s/firefox-ubuntu-20.04.zip", "ubuntu22.04-x64": "builds/firefox/%s/firefox-ubuntu-22.04.zip", "ubuntu24.04-x64": "builds/firefox/%s/firefox-ubuntu-24.04.zip", "ubuntu18.04-arm64": void 0, "ubuntu20.04-arm64": "builds/firefox/%s/firefox-ubuntu-20.04-arm64.zip", "ubuntu22.04-arm64": "builds/firefox/%s/firefox-ubuntu-22.04-arm64.zip", "ubuntu24.04-arm64": "builds/firefox/%s/firefox-ubuntu-24.04-arm64.zip", "debian11-x64": "builds/firefox/%s/firefox-debian-11.zip", "debian11-arm64": "builds/firefox/%s/firefox-debian-11-arm64.zip", "debian12-x64": "builds/firefox/%s/firefox-debian-12.zip", "debian12-arm64": "builds/firefox/%s/firefox-debian-12-arm64.zip", "debian13-x64": "builds/firefox/%s/firefox-debian-13.zip", "debian13-arm64": "builds/firefox/%s/firefox-debian-13-arm64.zip", "mac10.13": "builds/firefox/%s/firefox-mac.zip", "mac10.14": "builds/firefox/%s/firefox-mac.zip", "mac10.15": "builds/firefox/%s/firefox-mac.zip", "mac11": "builds/firefox/%s/firefox-mac.zip", "mac11-arm64": "builds/firefox/%s/firefox-mac-arm64.zip", "mac12": "builds/firefox/%s/firefox-mac.zip", "mac12-arm64": "builds/firefox/%s/firefox-mac-arm64.zip", "mac13": "builds/firefox/%s/firefox-mac.zip", "mac13-arm64": "builds/firefox/%s/firefox-mac-arm64.zip", "mac14": "builds/firefox/%s/firefox-mac.zip", "mac14-arm64": "builds/firefox/%s/firefox-mac-arm64.zip", "mac15": "builds/firefox/%s/firefox-mac.zip", "mac15-arm64": "builds/firefox/%s/firefox-mac-arm64.zip", "win64": "builds/firefox/%s/firefox-win64.zip" }, "firefox-beta": { "": void 0, "ubuntu18.04-x64": void 0, "ubuntu20.04-x64": "builds/firefox-beta/%s/firefox-beta-ubuntu-20.04.zip", "ubuntu22.04-x64": "builds/firefox-beta/%s/firefox-beta-ubuntu-22.04.zip", "ubuntu24.04-x64": "builds/firefox-beta/%s/firefox-beta-ubuntu-24.04.zip", "ubuntu18.04-arm64": void 0, "ubuntu20.04-arm64": void 0, "ubuntu22.04-arm64": "builds/firefox-beta/%s/firefox-beta-ubuntu-22.04-arm64.zip", "ubuntu24.04-arm64": "builds/firefox-beta/%s/firefox-beta-ubuntu-24.04-arm64.zip", "debian11-x64": "builds/firefox-beta/%s/firefox-beta-debian-11.zip", "debian11-arm64": "builds/firefox-beta/%s/firefox-beta-debian-11-arm64.zip", "debian12-x64": "builds/firefox-beta/%s/firefox-beta-debian-12.zip", "debian12-arm64": "builds/firefox-beta/%s/firefox-beta-debian-12-arm64.zip", "debian13-x64": "builds/firefox-beta/%s/firefox-beta-debian-12.zip", "debian13-arm64": "builds/firefox-beta/%s/firefox-beta-debian-12-arm64.zip", "mac10.13": "builds/firefox-beta/%s/firefox-beta-mac.zip", "mac10.14": "builds/firefox-beta/%s/firefox-beta-mac.zip", "mac10.15": "builds/firefox-beta/%s/firefox-beta-mac.zip", "mac11": "builds/firefox-beta/%s/firefox-beta-mac.zip", "mac11-arm64": "builds/firefox-beta/%s/firefox-beta-mac-arm64.zip", "mac12": "builds/firefox-beta/%s/firefox-beta-mac.zip", "mac12-arm64": "builds/firefox-beta/%s/firefox-beta-mac-arm64.zip", "mac13": "builds/firefox-beta/%s/firefox-beta-mac.zip", "mac13-arm64": "builds/firefox-beta/%s/firefox-beta-mac-arm64.zip", "mac14": "builds/firefox-beta/%s/firefox-beta-mac.zip", "mac14-arm64": "builds/firefox-beta/%s/firefox-beta-mac-arm64.zip", "mac15": "builds/firefox-beta/%s/firefox-beta-mac.zip", "mac15-arm64": "builds/firefox-beta/%s/firefox-beta-mac-arm64.zip", "win64": "builds/firefox-beta/%s/firefox-beta-win64.zip" }, "webkit": { "": void 0, "ubuntu18.04-x64": void 0, "ubuntu20.04-x64": "builds/webkit/%s/webkit-ubuntu-20.04.zip", "ubuntu22.04-x64": "builds/webkit/%s/webkit-ubuntu-22.04.zip", "ubuntu24.04-x64": "builds/webkit/%s/webkit-ubuntu-24.04.zip", "ubuntu18.04-arm64": void 0, "ubuntu20.04-arm64": "builds/webkit/%s/webkit-ubuntu-20.04-arm64.zip", "ubuntu22.04-arm64": "builds/webkit/%s/webkit-ubuntu-22.04-arm64.zip", "ubuntu24.04-arm64": "builds/webkit/%s/webkit-ubuntu-24.04-arm64.zip", "debian11-x64": "builds/webkit/%s/webkit-debian-11.zip", "debian11-arm64": "builds/webkit/%s/webkit-debian-11-arm64.zip", "debian12-x64": "builds/webkit/%s/webkit-debian-12.zip", "debian12-arm64": "builds/webkit/%s/webkit-debian-12-arm64.zip", "debian13-x64": "builds/webkit/%s/webkit-debian-13.zip", "debian13-arm64": "builds/webkit/%s/webkit-debian-13-arm64.zip", "mac10.13": void 0, "mac10.14": void 0, "mac10.15": void 0, "mac11": void 0, "mac11-arm64": void 0, "mac12": void 0, "mac12-arm64": void 0, "mac13": void 0, "mac13-arm64": void 0, "mac14": "builds/webkit/%s/webkit-mac-14.zip", "mac14-arm64": "builds/webkit/%s/webkit-mac-14-arm64.zip", "mac15": "builds/webkit/%s/webkit-mac-15.zip", "mac15-arm64": "builds/webkit/%s/webkit-mac-15-arm64.zip", "win64": "builds/webkit/%s/webkit-win64.zip" }, "ffmpeg": { "": void 0, "ubuntu18.04-x64": void 0, "ubuntu20.04-x64": "builds/ffmpeg/%s/ffmpeg-linux.zip", "ubuntu22.04-x64": "builds/ffmpeg/%s/ffmpeg-linux.zip", "ubuntu24.04-x64": "builds/ffmpeg/%s/ffmpeg-linux.zip", "ubuntu18.04-arm64": void 0, "ubuntu20.04-arm64": "builds/ffmpeg/%s/ffmpeg-linux-arm64.zip", "ubuntu22.04-arm64": "builds/ffmpeg/%s/ffmpeg-linux-arm64.zip", "ubuntu24.04-arm64": "builds/ffmpeg/%s/ffmpeg-linux-arm64.zip", "debian11-x64": "builds/ffmpeg/%s/ffmpeg-linux.zip", "debian11-arm64": "builds/ffmpeg/%s/ffmpeg-linux-arm64.zip", "debian12-x64": "builds/ffmpeg/%s/ffmpeg-linux.zip", "debian12-arm64": "builds/ffmpeg/%s/ffmpeg-linux-arm64.zip", "debian13-x64": "builds/ffmpeg/%s/ffmpeg-linux.zip", "debian13-arm64": "builds/ffmpeg/%s/ffmpeg-linux-arm64.zip", "mac10.13": "builds/ffmpeg/%s/ffmpeg-mac.zip", "mac10.14": "builds/ffmpeg/%s/ffmpeg-mac.zip", "mac10.15": "builds/ffmpeg/%s/ffmpeg-mac.zip", "mac11": "builds/ffmpeg/%s/ffmpeg-mac.zip", "mac11-arm64": "builds/ffmpeg/%s/ffmpeg-mac-arm64.zip", "mac12": "builds/ffmpeg/%s/ffmpeg-mac.zip", "mac12-arm64": "builds/ffmpeg/%s/ffmpeg-mac-arm64.zip", "mac13": "builds/ffmpeg/%s/ffmpeg-mac.zip", "mac13-arm64": "builds/ffmpeg/%s/ffmpeg-mac-arm64.zip", "mac14": "builds/ffmpeg/%s/ffmpeg-mac.zip", "mac14-arm64": "builds/ffmpeg/%s/ffmpeg-mac-arm64.zip", "mac15": "builds/ffmpeg/%s/ffmpeg-mac.zip", "mac15-arm64": "builds/ffmpeg/%s/ffmpeg-mac-arm64.zip", "win64": "builds/ffmpeg/%s/ffmpeg-win64.zip" }, "winldd": { "": void 0, "ubuntu18.04-x64": void 0, "ubuntu20.04-x64": void 0, "ubuntu22.04-x64": void 0, "ubuntu24.04-x64": void 0, "ubuntu18.04-arm64": void 0, "ubuntu20.04-arm64": void 0, "ubuntu22.04-arm64": void 0, "ubuntu24.04-arm64": void 0, "debian11-x64": void 0, "debian11-arm64": void 0, "debian12-x64": void 0, "debian12-arm64": void 0, "debian13-x64": void 0, "debian13-arm64": void 0, "mac10.13": void 0, "mac10.14": void 0, "mac10.15": void 0, "mac11": void 0, "mac11-arm64": void 0, "mac12": void 0, "mac12-arm64": void 0, "mac13": void 0, "mac13-arm64": void 0, "mac14": void 0, "mac14-arm64": void 0, "mac15": void 0, "mac15-arm64": void 0, "win64": "builds/winldd/%s/winldd-win64.zip" }, "android": { "": "builds/android/%s/android.zip", "ubuntu18.04-x64": void 0, "ubuntu20.04-x64": "builds/android/%s/android.zip", "ubuntu22.04-x64": "builds/android/%s/android.zip", "ubuntu24.04-x64": "builds/android/%s/android.zip", "ubuntu18.04-arm64": void 0, "ubuntu20.04-arm64": "builds/android/%s/android.zip", "ubuntu22.04-arm64": "builds/android/%s/android.zip", "ubuntu24.04-arm64": "builds/android/%s/android.zip", "debian11-x64": "builds/android/%s/android.zip", "debian11-arm64": "builds/android/%s/android.zip", "debian12-x64": "builds/android/%s/android.zip", "debian12-arm64": "builds/android/%s/android.zip", "debian13-x64": "builds/android/%s/android.zip", "debian13-arm64": "builds/android/%s/android.zip", "mac10.13": "builds/android/%s/android.zip", "mac10.14": "builds/android/%s/android.zip", "mac10.15": "builds/android/%s/android.zip", "mac11": "builds/android/%s/android.zip", "mac11-arm64": "builds/android/%s/android.zip", "mac12": "builds/android/%s/android.zip", "mac12-arm64": "builds/android/%s/android.zip", "mac13": "builds/android/%s/android.zip", "mac13-arm64": "builds/android/%s/android.zip", "mac14": "builds/android/%s/android.zip", "mac14-arm64": "builds/android/%s/android.zip", "mac15": "builds/android/%s/android.zip", "mac15-arm64": "builds/android/%s/android.zip", "win64": "builds/android/%s/android.zip" } }; const defaultCacheDirectory = (() => { if (process.platform === "linux") return process.env.XDG_CACHE_HOME || import_path.default.join(import_os.default.homedir(), ".cache"); if (process.platform === "darwin") return import_path.default.join(import_os.default.homedir(), "Library", "Caches"); if (process.platform === "win32") return process.env.LOCALAPPDATA || import_path.default.join(import_os.default.homedir(), "AppData", "Local"); throw new Error("Unsupported platform: " + process.platform); })(); const defaultRegistryDirectory = import_path.default.join(defaultCacheDirectory, "ms-playwright"); const registryDirectory = (() => { let result; const envDefined = (0, import_utils.getFromENV)("PLAYWRIGHT_BROWSERS_PATH"); if (envDefined === "0") result = import_path.default.join(__dirname, "..", "..", "..", ".local-browsers"); else if (envDefined) result = envDefined; else result = defaultRegistryDirectory; if (!import_path.default.isAbsolute(result)) { result = import_path.default.resolve((0, import_utils.getFromENV)("INIT_CWD") || process.cwd(), result); } return result; })(); function isBrowserDirectory(browserDirectory) { const baseName = import_path.default.basename(browserDirectory); for (const browserName of allDownloadableDirectoriesThatEverExisted) { if (baseName.startsWith(browserName.replace(/-/g, "_") + "-")) return true; } return false; } function readDescriptors(browsersJSON) { return browsersJSON["browsers"].map((obj) => { const name = obj.name; const revisionOverride = (obj.revisionOverrides || {})[import_hostPlatform.hostPlatform]; const revision = revisionOverride || obj.revision; const browserDirectoryPrefix = revisionOverride ? `${name}_${import_hostPlatform.hostPlatform}_special` : `${name}`; const descriptor = { name, revision, hasRevisionOverride: !!revisionOverride, // We only put browser version for the supported operating systems. browserVersion: revisionOverride ? void 0 : obj.browserVersion, title: obj["title"], installByDefault: !!obj.installByDefault, // Method `isBrowserDirectory` determines directory to be browser iff // it starts with some browser name followed by '-'. Some browser names // are prefixes of others, e.g. 'webkit' is a prefix of `webkit-technology-preview`. // To avoid older registries erroneously removing 'webkit-technology-preview', we have to // ensure that browser folders to never include dashes inside. dir: import_path.default.join(registryDirectory, browserDirectoryPrefix.replace(/-/g, "_") + "-" + revision) }; return descriptor; }); } const allDownloadableDirectoriesThatEverExisted = ["android", "chromium", "firefox", "webkit", "ffmpeg", "firefox-beta", "chromium-tip-of-tree", "chromium-headless-shell", "chromium-tip-of-tree-headless-shell", "winldd"]; const chromiumAliases = ["chrome-for-testing"]; class Registry { constructor(browsersJSON) { const descriptors = readDescriptors(browsersJSON); const findExecutablePath = (dir, name) => { const tokens = EXECUTABLE_PATHS[name][import_hostPlatform.shortPlatform]; return tokens ? import_path.default.join(dir, ...tokens) : void 0; }; const executablePathOrDie = (name, e, installByDefault, sdkLanguage) => { if (!e) throw new Error(`${name} is not supported on ${import_hostPlatform.hostPlatform}`); const installCommand = buildPlaywrightCLICommand(sdkLanguage, `install${installByDefault ? "" : " " + name}`); if (!(0, import_fileUtils.canAccessFile)(e)) { const currentDockerVersion = (0, import_dependencies.readDockerVersionSync)(); const preferredDockerVersion = currentDockerVersion ? (0, import_dependencies.dockerVersion)(currentDockerVersion.dockerImageNameTemplate) : null; const isOutdatedDockerImage = currentDockerVersion && preferredDockerVersion && currentDockerVersion.dockerImageName !== preferredDockerVersion.dockerImageName; const isFfmpeg = name === "ffmpeg"; let prettyMessage; if (isOutdatedDockerImage) { prettyMessage = [ `Looks like Playwright was just updated to ${preferredDockerVersion.driverVersion}.`, `Please update docker image as well.`, `- current: ${currentDockerVersion.dockerImageName}`, `- required: ${preferredDockerVersion.dockerImageName}`, ``, `<3 Playwright Team` ].join("\n"); } else if (isFfmpeg) { prettyMessage = [ `Video rendering requires ffmpeg binary.`, `Downloading it will not affect any of the system-wide settings.`, `Please run the following command:`, ``, ` ${buildPlaywrightCLICommand(sdkLanguage, "install ffmpeg")}`, ``, `<3 Playwright Team` ].join("\n"); } else { prettyMessage = [ `Looks like Playwright was just installed or updated.`, `Please run the following command to download new browser${installByDefault ? "s" : ""}:`, ``, ` ${installCommand}`, ``, `<3 Playwright Team` ].join("\n"); } throw new Error(`Executable doesn't exist at ${e} ${(0, import_ascii.wrapInASCIIBox)(prettyMessage, 1)}`); } return e; }; this._executables = []; const chromium = descriptors.find((d) => d.name === "chromium"); const chromiumExecutable = findExecutablePath(chromium.dir, "chromium"); this._executables.push({ name: "chromium", browserName: "chromium", directory: chromium.dir, executablePath: () => chromiumExecutable, executablePathOrDie: (sdkLanguage) => executablePathOrDie("chromium", chromiumExecutable, chromium.installByDefault, sdkLanguage), installType: chromium.installByDefault ? "download-by-default" : "download-on-demand", _validateHostRequirements: (sdkLanguage) => this._validateHostRequirements(sdkLanguage, chromium.dir, ["chrome-linux"], [], ["chrome-win"]), downloadURLs: this._downloadURLs(chromium), title: chromium.title, revision: chromium.revision, browserVersion: chromium.browserVersion, _install: (force) => this._downloadExecutable(chromium, force, chromiumExecutable), _dependencyGroup: "chromium", _isHermeticInstallation: true }); const chromiumHeadlessShell = descriptors.find((d) => d.name === "chromium-headless-shell"); const chromiumHeadlessShellExecutable = findExecutablePath(chromiumHeadlessShell.dir, "chromium-headless-shell"); this._executables.push({ name: "chromium-headless-shell", browserName: "chromium", directory: chromiumHeadlessShell.dir, executablePath: () => chromiumHeadlessShellExecutable, executablePathOrDie: (sdkLanguage) => executablePathOrDie("chromium", chromiumHeadlessShellExecutable, chromiumHeadlessShell.installByDefault, sdkLanguage), installType: chromiumHeadlessShell.installByDefault ? "download-by-default" : "download-on-demand", _validateHostRequirements: (sdkLanguage) => this._validateHostRequirements(sdkLanguage, chromiumHeadlessShell.dir, ["chrome-linux"], [], ["chrome-win"]), downloadURLs: this._downloadURLs(chromiumHeadlessShell), title: chromiumHeadlessShell.title, revision: chromiumHeadlessShell.revision, browserVersion: chromiumHeadlessShell.browserVersion, _install: (force) => this._downloadExecutable(chromiumHeadlessShell, force, chromiumHeadlessShellExecutable), _dependencyGroup: "chromium", _isHermeticInstallation: true }); const chromiumTipOfTreeHeadlessShell = descriptors.find((d) => d.name === "chromium-tip-of-tree-headless-shell"); const chromiumTipOfTreeHeadlessShellExecutable = findExecutablePath(chromiumTipOfTreeHeadlessShell.dir, "chromium-tip-of-tree-headless-shell"); this._executables.push({ name: "chromium-tip-of-tree-headless-shell", browserName: "chromium", directory: chromiumTipOfTreeHeadlessShell.dir, executablePath: () => chromiumTipOfTreeHeadlessShellExecutable, executablePathOrDie: (sdkLanguage) => executablePathOrDie("chromium", chromiumTipOfTreeHeadlessShellExecutable, chromiumTipOfTreeHeadlessShell.installByDefault, sdkLanguage), installType: chromiumTipOfTreeHeadlessShell.installByDefault ? "download-by-default" : "download-on-demand", _validateHostRequirements: (sdkLanguage) => this._validateHostRequirements(sdkLanguage, chromiumTipOfTreeHeadlessShell.dir, ["chrome-linux"], [], ["chrome-win"]), downloadURLs: this._downloadURLs(chromiumTipOfTreeHeadlessShell), title: chromiumTipOfTreeHeadlessShell.title, revision: chromiumTipOfTreeHeadlessShell.revision, browserVersion: chromiumTipOfTreeHeadlessShell.browserVersion, _install: (force) => this._downloadExecutable(chromiumTipOfTreeHeadlessShell, force, chromiumTipOfTreeHeadlessShellExecutable), _dependencyGroup: "chromium", _isHermeticInstallation: true }); const chromiumTipOfTree = descriptors.find((d) => d.name === "chromium-tip-of-tree"); const chromiumTipOfTreeExecutable = findExecutablePath(chromiumTipOfTree.dir, "chromium-tip-of-tree"); this._executables.push({ name: "chromium-tip-of-tree", browserName: "chromium", directory: chromiumTipOfTree.dir, executablePath: () => chromiumTipOfTreeExecutable, executablePathOrDie: (sdkLanguage) => executablePathOrDie("chromium-tip-of-tree", chromiumTipOfTreeExecutable, chromiumTipOfTree.installByDefault, sdkLanguage), installType: chromiumTipOfTree.installByDefault ? "download-by-default" : "download-on-demand", _validateHostRequirements: (sdkLanguage) => this._validateHostRequirements(sdkLanguage, chromiumTipOfTree.dir, ["chrome-linux"], [], ["chrome-win"]), downloadURLs: this._downloadURLs(chromiumTipOfTree), title: chromiumTipOfTree.title, revision: chromiumTipOfTree.revision, browserVersion: chromiumTipOfTree.browserVersion, _install: (force) => this._downloadExecutable(chromiumTipOfTree, force, chromiumTipOfTreeExecutable), _dependencyGroup: "chromium", _isHermeticInstallation: true }); this._executables.push(this._createChromiumChannel("chrome", { "linux": "/opt/google/chrome/chrome", "darwin": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", "win32": `\\Google\\Chrome\\Application\\chrome.exe` }, () => this._installChromiumChannel("chrome", { "linux": "reinstall_chrome_stable_linux.sh", "darwin": "reinstall_chrome_stable_mac.sh", "win32": "reinstall_chrome_stable_win.ps1" }))); this._executables.push(this._createChromiumChannel("chrome-beta", { "linux": "/opt/google/chrome-beta/chrome", "darwin": "/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta", "win32": `\\Google\\Chrome Beta\\Application\\chrome.exe` }, () => this._installChromiumChannel("chrome-beta", { "linux": "reinstall_chrome_beta_linux.sh", "darwin": "reinstall_chrome_beta_mac.sh", "win32": "reinstall_chrome_beta_win.ps1" }))); this._executables.push(this._createChromiumChannel("chrome-dev", { "linux": "/opt/google/chrome-unstable/chrome", "darwin": "/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev", "win32": `\\Google\\Chrome Dev\\Application\\chrome.exe` })); this._executables.push(this._createChromiumChannel("chrome-canary", { "linux": "/opt/google/chrome-canary/chrome", "darwin": "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary", "win32": `\\Google\\Chrome SxS\\Application\\chrome.exe` })); this._executables.push(this._createChromiumChannel("msedge", { "linux": "/opt/microsoft/msedge/msedge", "darwin": "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge", "win32": `\\Microsoft\\Edge\\Application\\msedge.exe` }, () => this._installMSEdgeChannel("msedge", { "linux": "reinstall_msedge_stable_linux.sh", "darwin": "reinstall_msedge_stable_mac.sh", "win32": "reinstall_msedge_stable_win.ps1" }))); this._executables.push(this._createChromiumChannel("msedge-beta", { "linux": "/opt/microsoft/msedge-beta/msedge", "darwin": "/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta", "win32": `\\Microsoft\\Edge Beta\\Application\\msedge.exe` }, () => this._installMSEdgeChannel("msedge-beta", { "darwin": "reinstall_msedge_beta_mac.sh", "linux": "reinstall_msedge_beta_linux.sh", "win32": "reinstall_msedge_beta_win.ps1" }))); this._executables.push(this._createChromiumChannel("msedge-dev", { "linux": "/opt/microsoft/msedge-dev/msedge", "darwin": "/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev", "win32": `\\Microsoft\\Edge Dev\\Application\\msedge.exe` }, () => this._installMSEdgeChannel("msedge-dev", { "darwin": "reinstall_msedge_dev_mac.sh", "linux": "reinstall_msedge_dev_linux.sh", "win32": "reinstall_msedge_dev_win.ps1" }))); this._executables.push(this._createChromiumChannel("msedge-canary", { "linux": "", "darwin": "/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary", "win32": `\\Microsoft\\Edge SxS\\Application\\msedge.exe` })); this._executables.push(this._createBidiFirefoxChannel("moz-firefox", { "linux": "/snap/bin/firefox", "darwin": "/Applications/Firefox.app/Contents/MacOS/firefox", "win32": "\\Mozilla Firefox\\firefox.exe" })); this._executables.push(this._createBidiFirefoxChannel("moz-firefox-beta", { "linux": "/opt/firefox-beta/firefox", "darwin": "/Applications/Firefox.app/Contents/MacOS/firefox", "win32": "\\Mozilla Firefox\\firefox.exe" })); this._executables.push(this._createBidiFirefoxChannel("moz-firefox-nightly", { "linux": "/opt/firefox-nightly/firefox", "darwin": "/Applications/Firefox Nightly.app/Contents/MacOS/firefox", "win32": "\\Mozilla Firefox\\firefox.exe" })); const firefox = descriptors.find((d) => d.name === "firefox"); const firefoxExecutable = findExecutablePath(firefox.dir, "firefox"); this._executables.push({ name: "firefox", browserName: "firefox", directory: firefox.dir, executablePath: () => firefoxExecutable, executablePathOrDie: (sdkLanguage) => executablePathOrDie("firefox", firefoxExecutable, firefox.installByDefault, sdkLanguage), installType: firefox.installByDefault ? "download-by-default" : "download-on-demand", _validateHostRequirements: (sdkLanguage) => this._validateHostRequirements(sdkLanguage, firefox.dir, ["firefox"], [], ["firefox"]), downloadURLs: this._downloadURLs(firefox), title: firefox.title, revision: firefox.revision, browserVersion: firefox.browserVersion, _install: (force) => this._downloadExecutable(firefox, force, firefoxExecutable), _dependencyGroup: "firefox", _isHermeticInstallation: true }); const firefoxBeta = descriptors.find((d) => d.name === "firefox-beta"); const firefoxBetaExecutable = findExecutablePath(firefoxBeta.dir, "firefox"); this._executables.push({ name: "firefox-beta", browserName: "firefox", directory: firefoxBeta.dir, executablePath: () => firefoxBetaExecutable, executablePathOrDie: (sdkLanguage) => executablePathOrDie("firefox-beta", firefoxBetaExecutable, firefoxBeta.installByDefault, sdkLanguage), installType: firefoxBeta.installByDefault ? "download-by-default" : "download-on-demand", _validateHostRequirements: (sdkLanguage) => this._validateHostRequirements(sdkLanguage, firefoxBeta.dir, ["firefox"], [], ["firefox"]), downloadURLs: this._downloadURLs(firefoxBeta), title: firefoxBeta.title, revision: firefoxBeta.revision, browserVersion: firefoxBeta.browserVersion, _install: (force) => this._downloadExecutable(firefoxBeta, force, firefoxBetaExecutable), _dependencyGroup: "firefox", _isHermeticInstallation: true }); const webkit = descriptors.find((d) => d.name === "webkit"); const webkitExecutable = findExecutablePath(webkit.dir, "webkit"); const webkitLinuxLddDirectories = [ import_path.default.join("minibrowser-gtk"), import_path.default.join("minibrowser-gtk", "bin"), import_path.default.join("minibrowser-gtk", "lib"), import_path.default.join("minibrowser-gtk", "sys", "lib"), import_path.default.join("minibrowser-wpe"), import_path.default.join("minibrowser-wpe", "bin"), import_path.default.join("minibrowser-wpe", "lib"), import_path.default.join("minibrowser-wpe", "sys", "lib") ]; this._executables.push({ name: "webkit", browserName: "webkit", directory: webkit.dir, executablePath: () => webkitExecutable, executablePathOrDie: (sdkLanguage) => executablePathOrDie("webkit", webkitExecutable, webkit.installByDefault, sdkLanguage), installType: webkit.installByDefault ? "download-by-default" : "download-on-demand", _validateHostRequirements: (sdkLanguage) => this._validateHostRequirements(sdkLanguage, webkit.dir, webkitLinuxLddDirectories, ["libGLESv2.so.2", "libx264.so"], [""]), downloadURLs: this._downloadURLs(webkit), title: webkit.title, revision: webkit.revision, browserVersion: webkit.browserVersion, _install: (force) => this._downloadExecutable(webkit, force, webkitExecutable), _dependencyGroup: "webkit", _isHermeticInstallation: true }); this._executables.push({ name: "webkit-wsl", browserName: "webkit", directory: webkit.dir, executablePath: () => webkitExecutable, executablePathOrDie: (sdkLanguage) => executablePathOrDie("webkit", webkitExecutable, webkit.installByDefault, sdkLanguage), installType: "download-on-demand", title: "Webkit in WSL", _validateHostRequirements: (sdkLanguage) => Promise.resolve(), _isHermeticInstallation: true, _install: async () => { if (process.platform !== "win32") throw new Error(`WebKit via WSL is only supported on Windows`); const script = import_path.default.join(BIN_PATH, "install_webkit_wsl.ps1"); const { code } = await (0, import_spawnAsync.spawnAsync)("powershell.exe", [ "-ExecutionPolicy", "Bypass", "-File", script ], { stdio: "inherit" }); if (code !== 0) throw new Error(`Failed to install WebKit via WSL`); } }); const ffmpeg = descriptors.find((d) => d.name === "ffmpeg"); const ffmpegExecutable = findExecutablePath(ffmpeg.dir, "ffmpeg"); this._executables.push({ name: "ffmpeg", browserName: void 0, directory: ffmpeg.dir, executablePath: () => ffmpegExecutable, executablePathOrDie: (sdkLanguage) => executablePathOrDie("ffmpeg", ffmpegExecutable, ffmpeg.installByDefault, sdkLanguage), installType: ffmpeg.installByDefault ? "download-by-default" : "download-on-demand", _validateHostRequirements: () => Promise.resolve(), downloadURLs: this._downloadURLs(ffmpeg), title: ffmpeg.title, revision: ffmpeg.revision, _install: (force) => this._downloadExecutable(ffmpeg, force, ffmpegExecutable), _dependencyGroup: "tools", _isHermeticInstallation: true }); const winldd = descriptors.find((d) => d.name === "winldd"); const winlddExecutable = findExecutablePath(winldd.dir, "winldd"); this._executables.push({ name: "winldd", browserName: void 0, directory: winldd.dir, executablePath: () => winlddExecutable, executablePathOrDie: (sdkLanguage) => executablePathOrDie("winldd", winlddExecutable, winldd.installByDefault, sdkLanguage), installType: process.platform === "win32" ? "download-by-default" : "none", _validateHostRequirements: () => Promise.resolve(), downloadURLs: this._downloadURLs(winldd), title: winldd.title, revision: winldd.revision, _install: (force) => this._downloadExecutable(winldd, force, winlddExecutable), _dependencyGroup: "tools", _isHermeticInstallation: true }); const android = descriptors.find((d) => d.name === "android"); this._executables.push({ name: "android", browserName: void 0, directory: android.dir, executablePath: () => void 0, executablePathOrDie: () => "", installType: "download-on-demand", _validateHostRequirements: () => Promise.resolve(), downloadURLs: this._downloadURLs(android), title: android.title, revision: android.revision, _install: (force) => this._downloadExecutable(android, force), _dependencyGroup: "tools", _isHermeticInstallation: true }); } _createChromiumChannel(name, lookAt, install) { const executablePath = (sdkLanguage, shouldThrow) => { const suffix = lookAt[process.platform]; if (!suffix) { if (shouldThrow) throw new Error(`Chromium distribution '${name}' is not supported on ${process.platform}`); return void 0; } const prefixes = process.platform === "win32" ? [ process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env["PROGRAMFILES(X86)"], // In some cases there is no PROGRAMFILES/(86) env var set but HOMEDRIVE is set. process.env.HOMEDRIVE + "\\Program Files", process.env.HOMEDRIVE + "\\Program Files (x86)" ].filter(Boolean) : [""]; for (const prefix of prefixes) { const executablePath2 = import_path.default.join(prefix, suffix); if ((0, import_fileUtils.canAccessFile)(executablePath2)) return executablePath2; } if (!shouldThrow) return void 0; const location = prefixes.length ? ` at ${import_path.default.join(prefixes[0], suffix)}` : ``; const installation = install ? ` Run "${buildPlaywrightCLICommand(sdkLanguage, "install " + name)}"` : ""; throw new Error(`Chromium distribution '${name}' is not found${location}${installation}`); }; return { name, browserName: "chromium", directory: void 0, executablePath: () => executablePath("", false), executablePathOrDie: (sdkLanguage) => executablePath(sdkLanguage, true), installType: install ? "install-script" : "none", _validateHostRequirements: () => Promise.resolve(), _isHermeticInstallation: false, _install: install }; } _createBidiFirefoxChannel(name, lookAt, install) { const executablePath = (sdkLanguage, shouldThrow) => { const suffix = lookAt[process.platform]; if (!suffix) { if (shouldThrow) throw new Error(`Firefox distribution '${name}' is not supported on ${process.platform}`); return void 0; } const prefixes = process.platform === "win32" ? [ process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env["PROGRAMFILES(X86)"], // In some cases there is no PROGRAMFILES/(86) env var set but HOMEDRIVE is set. process.env.HOMEDRIVE + "\\Program Files", process.env.HOMEDRIVE + "\\Program Files (x86)" ].filter(Boolean) : [""]; for (const prefix of prefixes) { const executablePath2 = import_path.default.join(prefix, suffix); if ((0, import_fileUtils.canAccessFile)(executablePath2)) return executablePath2; } if (shouldThrow) throw new Error(`Cannot find Firefox installation for channel '${name}' at the standard system paths. ${`Tried paths: ${prefixes.map((p) => import_path.default.join(p, suffix)).join("\n ")}`}`); return void 0; }; return { name, browserName: "firefox", directory: void 0, executablePath: () => executablePath("", false), executablePathOrDie: (sdkLanguage) => executablePath(sdkLanguage, true), installType: "none", _validateHostRequirements: () => Promise.resolve(), _isHermeticInstallation: true, _install: install }; } executables() { return this._executables; } findExecutable(name) { return this._executables.find((b) => b.name === name); } defaultExecutables() { return this._executables.filter((e) => e.installType === "download-by-default"); } _dedupe(executables) { return Array.from(new Set(executables)); } async _validateHostRequirements(sdkLanguage, browserDirectory, linuxLddDirectories, dlOpenLibraries, windowsExeAndDllDirectories) { if (import_os.default.platform() === "linux") return await (0, import_dependencies2.validateDependenciesLinux)(sdkLanguage, linuxLddDirectories.map((d) => import_path.default.join(browserDirectory, d)), dlOpenLibraries); if (import_os.default.platform() === "win32" && import_os.default.arch() === "x64") return await (0, import_dependencies2.validateDependenciesWindows)(sdkLanguage, windowsExeAndDllDirectories.map((d) => import_path.default.join(browserDirectory, d))); } async installDeps(executablesToInstallDeps, dryRun) { const executables = this._dedupe(executablesToInstallDeps); const targets = /* @__PURE__ */ new Set(); for (const executable of executables) { if (executable._dependencyGroup) targets.add(executable._dependencyGroup); } targets.add("tools"); if (import_os.default.platform() === "win32") return await (0, import_dependencies2.installDependenciesWindows)(targets, dryRun); if (import_os.default.platform() === "linux") return await (0, import_dependencies2.installDependenciesLinux)(targets, dryRun); } async install(executablesToInstall, options) { const executables = this._dedupe(executablesToInstall); await import_fs.default.promises.mkdir(registryDirectory, { recursive: true }); const lockfilePath = import_path.default.join(registryDirectory, "__dirlock"); const linksDir = import_path.default.join(registryDirectory, ".links"); let releaseLock; try { releaseLock = await import_utilsBundle.lockfile.lock(registryDirectory, { retries: { // Retry 20 times during 10 minutes with // exponential back-off. // See documentation at: https://www.npmjs.com/package/retry#retrytimeoutsoptions retries: 20, factor: 1.27579 }, onCompromised: (err) => { throw new Error(`${err.message} Path: ${lockfilePath}`); }, lockfilePath }); await import_fs.default.promises.mkdir(linksDir, { recursive: true }); await import_fs.default.promises.writeFile(import_path.default.join(linksDir, (0, import_utils.calculateSha1)(PACKAGE_PATH)), PACKAGE_PATH); if (!(0, import_utils.getAsBooleanFromENV)("PLAYWRIGHT_SKIP_BROWSER_GC")) await this._validateInstallationCache(linksDir); for (const executable of executables) { if (!executable._install) throw new Error(`ERROR: Playwright does not support installing ${executable.name}`); if (!(0, import_utils.getAsBooleanFromENV)("CI") && !executable._isHermeticInstallation && !options?.force && executable.executablePath()) { const { embedderName } = (0, import_userAgent.getEmbedderName)(); const command = buildPlaywrightCLICommand(embedderName, "install --force " + executable.name); process.stderr.write("\n" + (0, import_ascii.wrapInASCIIBox)([ `ATTENTION: "${executable.name}" is already installed on the system!`, ``, `"${executable.name}" installation is not hermetic; installing newer version`, `requires *removal* of a current installation first.`, ``, `To *uninstall* current version and re-install latest "${executable.name}":`, ``, `- Close all running instances of "${executable.name}", if any`, `- Use "--force" to install browser:`, ``, ` ${command}`, ``, `<3 Playwright Team` ].join("\n"), 1) + "\n\n"); return; } await executable._install(!!options?.force); } } catch (e) { if (e.code === "ELOCKED") { const rmCommand = process.platform === "win32" ? "rm -R" : "rm -rf"; throw new Error("\n" + (0, import_ascii.wrapInASCIIBox)([ `An active lockfile is found at:`, ``, ` ${lockfilePath}`, ``, `Either:`, `- wait a few minutes if other Playwright is installing browsers in parallel`, `- remove lock manually with:`, ``, ` ${rmCommand} ${lockfilePath}`, ``, `<3 Playwright Team` ].join("\n"), 1)); } else { throw e; } } finally { if (releaseLock) await releaseLock(); } } async uninstall(all) { const linksDir = import_path.default.join(registryDirectory, ".links"); if (all) { const links = await import_fs.default.promises.readdir(linksDir).catch(() => []); for (const link of links) await import_fs.default.promises.unlink(import_path.default.join(linksDir, link)); } else { await import_fs.default.promises.unlink(import_path.default.join(linksDir, (0, import_utils.calculateSha1)(PACKAGE_PATH))).catch(() => { }); } await this._validateInstallationCache(linksDir); return { numberOfBrowsersLeft: (await import_fs.default.promises.readdir(registryDirectory).catch(() => [])).filter((browserDirectory) => isBrowserDirectory(browserDirectory)).length }; } async validateHostRequirementsForExecutablesIfNeeded(executables, sdkLanguage) { if ((0, import_utils.getAsBooleanFromENV)("PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS")) { process.stderr.write("Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.\n"); return; } for (const executable of executables) await this._validateHostRequirementsForExecutableIfNeeded(executable, sdkLanguage); } async _validateHostRequirementsForExecutableIfNeeded(executable, sdkLanguage) { const kMaximumReValidationPeriod = 30 * 24 * 60 * 60 * 1e3; if (!executable.directory) return; const markerFile = import_path.default.join(executable.directory, "DEPENDENCIES_VALIDATED"); if (await import_fs.default.promises.stat(markerFile).then((stat) => Date.now() - stat.mtime.getTime() < kMaximumReValidationPeriod).catch(() => false)) return; import_debugLogger.debugLogger.log("install", `validating host requirements for "${executable.name}"`); try { await executable._validateHostRequirements(sdkLanguage); import_debugLogger.debugLogger.log("install", `validation passed for ${executable.name}`); } catch (error) { import_debugLogger.debugLogger.log("install", `validation failed for ${executable.name}`); throw error; } await import_fs.default.promises.writeFile(markerFile, "").catch(() => { }); } _downloadURLs(descriptor) { const paths = DOWNLOAD_PATHS[descriptor.name]; const downloadPathTemplate = paths[import_hostPlatform.hostPlatform] || paths[""]; if (!downloadPathTemplate) return []; let downloadPath; let mirrors; if (typeof downloadPathTemplate === "function") { const result = downloadPathTemplate(descriptor); downloadPath = result.path; mirrors = result.mirrors; } else { downloadPath = util.format(downloadPathTemplate, descriptor.revision); mirrors = PLAYWRIGHT_CDN_MIRRORS; } let downloadHostEnv; if (descriptor.name.startsWith("chromium")) downloadHostEnv = "PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST"; else if (descriptor.name.startsWith("firefox")) downloadHostEnv = "PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST"; else if (descriptor.name.startsWith("webkit")) downloadHostEnv = "PLAYWRIGHT_WEBKIT_DOWNLOAD_HOST"; const customHostOverride = downloadHostEnv && (0, import_utils.getFromENV)(downloadHostEnv) || (0, import_utils.getFromENV)("PLAYWRIGHT_DOWNLOAD_HOST"); if (customHostOverride) mirrors = [customHostOverride]; return mirrors.map((mirror) => `${mirror}/${downloadPath}`); } async _downloadExecutable(descriptor, force, executablePath) { const downloadURLs = this._downloadURLs(descriptor); if (!downloadURLs.length) throw new Error(`ERROR: Playwright does not support ${descriptor.name} on ${import_hostPlatform.hostPlatform}`); if (!import_hostPlatform.isOfficiallySupportedPlatform) (0, import_browserFetcher.logPolitely)(`BEWARE: your OS is not officially supported by Playwright; downloading fallback build for ${import_hostPlatform.hostPlatform}.`); if (descriptor.hasRevisionOverride) { const message = `You are using a frozen ${descriptor.name} browser which does not receive updates anymore on ${import_hostPlatform.hostPlatform}. Please update to the latest version of your operating system to test up-to-date browsers.`; if (process.env.GITHUB_ACTIONS) console.log(`::warning title=Playwright::${message}`); else (0, import_browserFetcher.logPolitely)(message); } const title = this.calculateDownloadTitle(descriptor); const downloadFileName = `playwright-download-${descriptor.name}-${import_hostPlatform.hostPlatform}-${descriptor.revision}.zip`; const downloadSocketTimeoutEnv = (0, import_utils.getFromENV)("PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT"); const downloadSocketTimeout = +(downloadSocketTimeoutEnv || "0") || import_network.NET_DEFAULT_TIMEOUT; await (0, import_browserFetcher.downloadBrowserWithProgressBar)(title, descriptor.dir, executablePath, downloadURLs, downloadFileName, downloadSocketTimeout, force).catch((e) => { throw new Error(`Failed to download ${title}, caused by ${e.stack}`); }); } calculateDownloadTitle(descriptor) { const title = descriptor.title ?? descriptor.name.split("-").map((word) => { return word === "ffmpeg" ? "FFmpeg" : word.charAt(0).toUpperCase() + word.slice(1); }).join(" "); const version = descriptor.browserVersion ? " " + descriptor.browserVersion : ""; return `${title}${version} (playwright ${descriptor.name} v${descriptor.revision})`; } async _installMSEdgeChannel(channel, scripts) { const scriptArgs = []; if (process.platform !== "linux") { const products = lowercaseAllKeys(JSON.parse(await (0, import_network.fetchData)(void 0, { url: "https://edgeupdates.microsoft.com/api/products" }))); const productName = { "msedge": "Stable", "msedge-beta": "Beta", "msedge-dev": "Dev" }[channel]; const product = products.find((product2) => product2.product === productName); const searchConfig = { darwin: { platform: "MacOS", arch: "universal", artifact: "pkg" }, win32: { platform: "Windows", arch: "x64", artifact: "msi" } }[process.platform]; const release = searchConfig ? product.releases.find((release2) => release2.platform === searchConfig.platform && release2.architecture === searchConfig.arch && release2.artifacts.length > 0) : null; const artifact = release ? release.artifacts.find((artifact2) => artifact2.artifactname === searchConfig.artifact) : null; if (artifact) scriptArgs.push( artifact.location /* url */ ); else throw new Error(`Cannot install ${channel} on ${process.platform}`); } await this._installChromiumChannel(channel, scripts, scriptArgs); } async _installChromiumChannel(channel, scripts, scriptArgs = []) { const scriptName = scripts[process.platform]; if (!scriptName) throw new Error(`Cannot install ${channel} on ${process.platform}`); const cwd = BIN_PATH; const isPowerShell = scriptName.endsWith(".ps1"); if (isPowerShell) { const args = [ "-ExecutionPolicy", "Bypass", "-File", import_path.default.join(BIN_PATH, scriptName), ...scriptArgs ]; const { code } = await (0, import_spawnAsync.spawnAsync)("powershell.exe", args, { cwd, stdio: "inherit" }); if (code !== 0) throw new Error(`Failed to install ${channel}`); } else { const { command, args, elevatedPermissions } = await (0, import_dependencies.transformCommandsForRoot)([`bash "${import_path.default.join(BIN_PATH, scriptName)}" ${scriptArgs.join("")}`]); if (elevatedPermissions) console.log("Switching to root user to install dependencies..."); const { code } = await (0, import_spawnAsync.spawnAsync)(command, args, { cwd, stdio: "inherit" }); if (code !== 0) throw new Error(`Failed to install ${channel}`); } } async listInstalledBrowsers() { const linksDir = import_path.default.join(registryDirectory, ".links"); const { browsers } = await this._traverseBrowserInstallations(linksDir); return browsers.filter((browser) => import_fs.default.existsSync(browser.browserPath)); } async _validateInstallationCache(linksDir) { const { browsers, brokenLinks } = await this._traverseBrowserInstallations(linksDir); await this._deleteStaleBrowsers(browsers); await this._deleteBrokenInstallations(brokenLinks); } async _traverseBrowserInstallations(linksDir) { const browserList = []; const brokenLinks = []; for (const fileName of await import_fs.default.promises.readdir(linksDir)) { const linkPath = import_path.default.join(linksDir, fileName); let linkTarget = ""; try { linkTarget = (await import_fs.default.promises.readFile(linkPath)).toString(); const browsersJSON = require(import_path.default.join(linkTarget, "browsers.json")); const descriptors = readDescriptors(browsersJSON); for (const browserName of allDownloadableDirectoriesThatEverExisted) { const descriptor = descriptors.find((d) => d.name === browserName); if (!descriptor) continue; const browserPath = descriptor.dir; const browserVersion = parseInt(descriptor.revision, 10); browserList.push({ browserName, browserVersion, browserPath, referenceDir: linkTarget }); } } catch (e) { brokenLinks.push(linkPath); } } return { browsers: browserList, brokenLinks }; } async _deleteStaleBrowsers(browserList) { const usedBrowserPaths = /* @__PURE__ */ new Set(); for (const browser of browserList) { const { browserName, browserVersion, browserPath } = browser; const shouldHaveMarkerFile = browserName === "chromium" && (browserVersion >= 786218 || browserVersion < 3e5) || browserName === "firefox" && browserVersion >= 1128 || browserName === "webkit" && browserVersion >= 1307 || // All new applications have a marker file right away. browserName !== "firefox" && browserName !== "chromium" && browserName !== "webkit"; if (!shouldHaveMarkerFile || await (0, import_fileUtils.existsAsync)(browserDirectoryToMarkerFilePath(browserPath))) usedBrowserPaths.add(browserPath); } let downloadedBrowsers = (await import_fs.default.promises.readdir(registryDirectory)).map((file) => import_path.default.join(registryDirectory, file)); downloadedBrowsers = downloadedBrowsers.filter((file) => isBrowserDirectory(file)); const directories = new Set(downloadedBrowsers); for (const browserDirectory of usedBrowserPaths) directories.delete(browserDirectory); for (const directory of directories) (0, import_browserFetcher.logPolitely)("Removing unused browser at " + directory); await (0, import_fileUtils.removeFolders)([...directories]); } async _deleteBrokenInstallations(brokenLinks) { for (const linkPath of brokenLinks) await import_fs.default.promises.unlink(linkPath).catch((e) => { }); } _defaultBrowsersToInstall(options) { let executables = this.defaultExecutables(); if (options.shell === "no") executables = executables.filter((e) => e.name !== "chromium-headless-shell" && e.name !== "chromium-tip-of-tree-headless-shell"); if (options.shell === "only") executables = executables.filter((e) => e.name !== "chromium" && e.name !== "chromium-tip-of-tree"); return executables; } suggestedBrowsersToInstall() { const names = this.executables().filter((e) => e.installType !== "none").map((e) => e.name); names.push(...chromiumAliases); return names.sort().join(", "); } isChromiumAlias(name) { return chromiumAliases.includes(name); } resolveBrowsers(aliases, options) { if (aliases.length === 0) return this._defaultBrowsersToInstall(options); const faultyArguments = []; const executables = []; const handleArgument = (arg) => { const executable = this.findExecutable(arg); if (!executable || executable.installType === "none") faultyArguments.push(arg); else executables.push(executable); if (executable?.browserName) executables.push(this.findExecutable("ffmpeg")); }; for (const alias of aliases) { if (alias === "chromium" || chromiumAliases.includes(alias)) { if (options.shell !== "only") handleArgument("chromium"); if (options.shell !== "no") handleArgument("chromium-headless-shell"); } else if (alias === "chromium-tip-of-tree") { if (options.shell !== "only") handleArgument("chromium-tip-of-tree"); if (options.shell !== "no") handleArgument("chromium-tip-of-tree-headless-shell"); } else { handleArgument(alias); } } if (process.platform === "win32") executables.push(this.findExecutable("winldd")); if (faultyArguments.length) throw new Error(`Invalid installation targets: ${faultyArguments.map((name) => `'${name}'`).join(", ")}. Expecting one of: ${this.suggestedBrowsersToInstall()}`); return executables; } } function browserDirectoryToMarkerFilePath(browserDirectory) { return import_path.default.join(browserDirectory, "INSTALLATION_COMPLETE"); } function buildPlaywrightCLICommand(sdkLanguage, parameters) { switch (sdkLanguage) { case "python": return `playwright ${parameters}`; case "java": return `mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="${parameters}"`; case "csharp": return `pwsh bin/Debug/netX/playwright.ps1 ${parameters}`; default: { const packageManagerCommand = (0, import_utils.getPackageManagerExecCommand)(); return `${packageManagerCommand} playwright ${parameters}`; } } } async function installBrowsersForNpmInstall(browsers) { if ((0, import_utils.getAsBooleanFromENV)("PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD")) { (0, import_browserFetcher.logPolitely)("Skipping browsers download because `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` env variable is set"); return false; } const executables = []; if (process.platform === "win32") executables.push(registry.findExecutable("winldd")); for (const browserName of browsers) { const executable = registry.findExecutable(browserName); if (!executable || executable.installType === "none") throw new Error(`Cannot install ${browserName}`); executables.push(executable); } await registry.install(executables); } function findChromiumChannelBestEffort(sdkLanguage) { let channel = null; for (const name of ["chromium", "chrome", "msedge"]) { try { registry.findExecutable(name).executablePathOrDie(sdkLanguage); channel = name === "chromium" ? void 0 : name; break; } catch (e) { } } if (channel === null) { const installCommand = buildPlaywrightCLICommand(sdkLanguage, `install chromium`); const prettyMessage = [ `No chromium-based browser found on the system.`, `Please run the following command to download one:`, ``, ` ${installCommand}`, ``, `<3 Playwright Team` ].join("\n"); throw new Error("\n" + (0, import_ascii.wrapInASCIIBox)(prettyMessage, 1)); } return channel; } function lowercaseAllKeys(json) { if (typeof json !== "object" || !json) return json; if (Array.isArray(json)) return json.map(lowercaseAllKeys); const result = {}; for (const [key, value] of Object.entries(json)) result[key.toLowerCase()] = lowercaseAllKeys(value); return result; } const registry = new Registry(require("../../../browsers.json")); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Registry, browserDirectoryToMarkerFilePath, buildPlaywrightCLICommand, defaultCacheDirectory, defaultRegistryDirectory, findChromiumChannelBestEffort, installBrowsersForNpmInstall, registry, registryDirectory, writeDockerVersion });