Spaces:
Running
Running
File size: 3,472 Bytes
8e9d829 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | // Which Chromium the browser-level tests should drive.
//
// `chromium.launch()` with no executablePath demands the EXACT build the
// installed Playwright expects, and fails with "Looks like Playwright was just
// installed or updated / npx playwright install" if the machine has any other
// revision. That is a real failure mode here rather than a hypothetical: this
// workspace ships a shared browser under PLAYWRIGHT_BROWSERS_PATH (rev 1208 at
// the time of writing) while `playwright@^1.62` asks for 1234, so every browser
// suite died before running a line of app code — and the message blames a missing
// install rather than a mismatch, which sends you off to download 115MB you
// already have.
//
// Order of preference:
// 1. PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH — an explicit answer always wins.
// 2. the newest chromium under PLAYWRIGHT_BROWSERS_PATH, whatever its revision.
// 3. undefined — let Playwright resolve its own download, which is what CI and
// an ordinary dev machine want. The error, if any, stays Playwright's.
//
// Driving a revision Playwright wasn't built against is a deliberate trade: these
// suites use long-stable APIs (newPage, setContent, addScriptTag, keyboard,
// screenshots), and a browser that is one build off is worth far more than a
// suite nobody can run.
import fs from 'node:fs';
import path from 'node:path';
// Full chromium first: it can run headed as well as headless, where
// chrome-headless-shell cannot. Both are accepted — the shell alone is enough for
// the headless suites, and on some images it is all that was fetched.
const FAMILIES = [
{ dir: /^chromium-(\d+)$/, exe: ['chrome-linux64/chrome', 'chrome-linux/chrome', 'chrome-mac/Chromium.app/Contents/MacOS/Chromium'] },
{ dir: /^chromium_headless_shell-(\d+)$/, exe: ['chrome-headless-shell-linux64/chrome-headless-shell', 'chrome-headless-shell-linux/chrome-headless-shell'] },
];
export function chromiumExecutablePath() {
const explicit = process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH;
if (explicit) return fs.existsSync(explicit) ? explicit : undefined;
const root = process.env.PLAYWRIGHT_BROWSERS_PATH;
if (!root || !fs.existsSync(root)) return undefined;
let entries;
try { entries = fs.readdirSync(root); } catch { return undefined; }
for (const family of FAMILIES) {
const found = entries
.map((name) => ({ name, rev: Number((family.dir.exec(name) || [])[1]) }))
.filter((e) => Number.isFinite(e.rev))
.sort((a, b) => b.rev - a.rev); // newest revision present
for (const { name } of found) {
for (const rel of family.exe) {
const p = path.join(root, name, rel);
if (fs.existsSync(p)) return p;
}
}
}
return undefined;
}
/**
* Launch options for a headless run. Spread into `chromium.launch({...})`.
*
* `--no-sandbox` because these suites run inside a container as a non-root user
* with no user namespaces, where Chromium's sandbox cannot initialise and the
* browser exits immediately. It is scoped to tests driving content this repo
* generated itself.
*/
export function chromiumLaunchOptions(extra = {}) {
const executablePath = chromiumExecutablePath();
return {
headless: true,
...(executablePath ? { executablePath } : {}),
args: ['--no-sandbox', '--disable-dev-shm-usage', ...(extra.args || [])],
...Object.fromEntries(Object.entries(extra).filter(([k]) => k !== 'args')),
};
}
|