Some checks failed
Main Confidence / confidence (push) Failing after 45s
## Summary - introduce surface-aware compressed governance outcomes and reuse the shared truth/explanation seams for operator-first summaries - apply the compressed outcome hierarchy across baseline, evidence, review, review-pack, canonical review/evidence, and artifact-oriented operation-run surfaces - expand spec 214 fixtures and Pest coverage, and fix tenant-panel route assertions by generating explicit tenant-panel URLs in the affected Filament tests ## Validation - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - focused governance compression suite from `specs/214-governance-outcome-compression/quickstart.md` passed (`68` tests, `445` assertions) - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/InventoryItemResourceTest.php tests/Feature/Filament/BackupSetUiEnforcementTest.php tests/Feature/Filament/RestoreRunUiEnforcementTest.php` passed (`18` tests, `81` assertions) Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #253
1396 lines
67 KiB
Plaintext
1396 lines
67 KiB
Plaintext
"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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": void 0,
|
|
"linux-x64": ["ffmpeg-linux"],
|
|
"linux-arm64": ["ffmpeg-linux"],
|
|
"mac-x64": ["ffmpeg-mac"],
|
|
"mac-arm64": ["ffmpeg-mac"],
|
|
"win-x64": ["ffmpeg-win64.exe"]
|
|
},
|
|
"winldd": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": 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": {
|
|
"<unknown>": "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["<unknown>"];
|
|
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
|
|
});
|