mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-25 00:59:35 +00:00
fix(qa): recover Playwright Chromium on Ubuntu 26
This commit is contained in:
@@ -179,7 +179,7 @@ describe("qa test file scenario runner", () => {
|
||||
|
||||
expect(result.executionKind).toBe("playwright");
|
||||
expect(commands.map((command) => command.args)).toEqual([
|
||||
["scripts/ensure-playwright-chromium.mjs"],
|
||||
["scripts/ensure-playwright-chromium.mjs", "--skip-ffmpeg"],
|
||||
[
|
||||
"scripts/run-vitest.mjs",
|
||||
"run",
|
||||
|
||||
@@ -121,7 +121,7 @@ function playwrightSteps(scenario: QaTestFileScenario): QaScenarioCommandStep[]
|
||||
return [
|
||||
{
|
||||
command: process.execPath,
|
||||
args: ["scripts/ensure-playwright-chromium.mjs"],
|
||||
args: ["scripts/ensure-playwright-chromium.mjs", "--skip-ffmpeg"],
|
||||
},
|
||||
{
|
||||
command: process.execPath,
|
||||
|
||||
@@ -10,6 +10,7 @@ import { resolvePnpmRunner } from "./pnpm-runner.mjs";
|
||||
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const playwrightInstallBaseArgs = ["--dir", "ui", "exec", "playwright", "install"];
|
||||
const executableOverrideEnvKey = "PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH";
|
||||
const chromiumPackageNames = ["chromium-browser", "chromium"];
|
||||
/**
|
||||
* System Chromium executable paths used before downloading Playwright browsers.
|
||||
*/
|
||||
@@ -89,6 +90,68 @@ export function shouldInstallPlaywrightSystemDependencies(options = {}) {
|
||||
);
|
||||
}
|
||||
|
||||
function resolveLinuxPrivilegePrefix(options = {}) {
|
||||
const getuid = options.getuid ?? process.getuid;
|
||||
const spawnSync = options.spawnSync ?? spawnSyncImpl;
|
||||
if (typeof getuid === "function" && getuid() === 0) {
|
||||
return [];
|
||||
}
|
||||
const result = spawnSync("sudo", ["-n", "true"], { stdio: "ignore" });
|
||||
if (result.status === 0) {
|
||||
return ["sudo", "-n"];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a distro Chromium package for CI images newer than Playwright's
|
||||
* bundled browser support matrix.
|
||||
*/
|
||||
export function installLinuxSystemChromiumPackage(options = {}) {
|
||||
const platform = options.platform ?? process.platform;
|
||||
if (platform !== "linux") {
|
||||
return 1;
|
||||
}
|
||||
const spawnSync = options.spawnSync ?? spawnSyncImpl;
|
||||
const privilegePrefix = resolveLinuxPrivilegePrefix({
|
||||
getuid: options.getuid,
|
||||
spawnSync,
|
||||
});
|
||||
if (!privilegePrefix) {
|
||||
return 1;
|
||||
}
|
||||
const env = {
|
||||
...(options.env ?? process.env),
|
||||
DEBIAN_FRONTEND: "noninteractive",
|
||||
};
|
||||
const cwd = options.cwd ?? repoRoot;
|
||||
const stdio = options.stdio ?? "inherit";
|
||||
const runAptGet = (args) => {
|
||||
const command = privilegePrefix[0] ?? "apt-get";
|
||||
const commandArgs =
|
||||
privilegePrefix.length === 0 ? args : [...privilegePrefix.slice(1), "apt-get", ...args];
|
||||
return (
|
||||
spawnSync(command, commandArgs, {
|
||||
cwd,
|
||||
env,
|
||||
stdio,
|
||||
}).status ?? 1
|
||||
);
|
||||
};
|
||||
|
||||
const updateStatus = runAptGet(["update", "-qq"]);
|
||||
if (updateStatus !== 0) {
|
||||
return updateStatus;
|
||||
}
|
||||
for (const packageName of chromiumPackageNames) {
|
||||
const installStatus = runAptGet(["install", "-y", packageName]);
|
||||
if (installStatus === 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this module is the direct script entrypoint.
|
||||
*/
|
||||
@@ -135,6 +198,31 @@ export function ensurePlaywrightChromium(options = {}) {
|
||||
});
|
||||
return result.status ?? 1;
|
||||
};
|
||||
const useLinuxSystemChromiumPackage = () => {
|
||||
log(`[ui-e2e] Playwright install is unavailable; installing a system Chromium package.`);
|
||||
const installStatus = installLinuxSystemChromiumPackage({
|
||||
cwd: options.cwd,
|
||||
env,
|
||||
getuid: options.getuid,
|
||||
platform: options.platform,
|
||||
spawnSync,
|
||||
stdio: options.stdio,
|
||||
});
|
||||
if (installStatus !== 0) {
|
||||
log(`[ui-e2e] System Chromium package install failed with status ${installStatus}.`);
|
||||
return installStatus;
|
||||
}
|
||||
const installedSystemExecutablePath = resolveSystemChromiumExecutablePath(
|
||||
existsSync,
|
||||
spawnSync,
|
||||
);
|
||||
if (installedSystemExecutablePath) {
|
||||
log(`[ui-e2e] Using system Chromium at ${installedSystemExecutablePath}.`);
|
||||
return ensureFfmpeg();
|
||||
}
|
||||
log(`[ui-e2e] System Chromium package install completed but no runnable Chromium was found.`);
|
||||
return 1;
|
||||
};
|
||||
const ensureFfmpeg = () => {
|
||||
if (!options.ensureFfmpeg) {
|
||||
return 0;
|
||||
@@ -188,7 +276,7 @@ export function ensurePlaywrightChromium(options = {}) {
|
||||
);
|
||||
const depsStatus = runPlaywrightInstall(["chromium"], true);
|
||||
if (depsStatus !== 0) {
|
||||
return depsStatus;
|
||||
return useLinuxSystemChromiumPackage();
|
||||
}
|
||||
if (existsSync(executablePath) && canRunChromiumExecutable(executablePath, spawnSync)) {
|
||||
return ensureFfmpeg();
|
||||
@@ -208,11 +296,12 @@ export function ensurePlaywrightChromium(options = {}) {
|
||||
);
|
||||
const depsStatus = runPlaywrightInstall(["chromium"], true);
|
||||
if (depsStatus !== 0) {
|
||||
return depsStatus;
|
||||
return useLinuxSystemChromiumPackage();
|
||||
}
|
||||
if (existsSync(executablePath) && canRunChromiumExecutable(executablePath, spawnSync)) {
|
||||
return ensureFfmpeg();
|
||||
}
|
||||
return useLinuxSystemChromiumPackage();
|
||||
}
|
||||
log(
|
||||
`[ui-e2e] Playwright install completed but Chromium is still not runnable at ${executablePath}.`,
|
||||
@@ -222,6 +311,12 @@ export function ensurePlaywrightChromium(options = {}) {
|
||||
return ensureFfmpeg();
|
||||
}
|
||||
|
||||
if (isDirectScriptExecution()) {
|
||||
process.exitCode = ensurePlaywrightChromium({ ensureFfmpeg: true });
|
||||
export function shouldEnsureFfmpegFromArgv(argv = process.argv) {
|
||||
return !argv.includes("--skip-ffmpeg");
|
||||
}
|
||||
|
||||
if (isDirectScriptExecution()) {
|
||||
process.exitCode = ensurePlaywrightChromium({
|
||||
ensureFfmpeg: shouldEnsureFfmpegFromArgv(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
ensurePlaywrightChromium,
|
||||
installLinuxSystemChromiumPackage,
|
||||
resolvePlaywrightInstallRunner,
|
||||
shouldEnsureFfmpegFromArgv,
|
||||
shouldInstallPlaywrightSystemDependencies,
|
||||
} from "../../scripts/ensure-playwright-chromium.mjs";
|
||||
|
||||
@@ -276,6 +278,55 @@ describe("ensurePlaywrightChromium", () => {
|
||||
expect(logs.join("\n")).toContain("installing Linux system dependencies");
|
||||
});
|
||||
|
||||
it("falls back to distro Chromium when Playwright does not support the Linux runner image", () => {
|
||||
const logs: string[] = [];
|
||||
let installedSystemChromium = false;
|
||||
const spawnSync = vi.fn((command: string, args: string[]) => {
|
||||
if (command === "pnpm" && args.includes("chromium")) {
|
||||
return { status: 1 };
|
||||
}
|
||||
if (command === "apt-get" && args.includes("update")) {
|
||||
return { status: 0 };
|
||||
}
|
||||
if (command === "apt-get" && args.includes("chromium-browser")) {
|
||||
installedSystemChromium = true;
|
||||
return { status: 0 };
|
||||
}
|
||||
if (command === "/usr/bin/chromium-browser") {
|
||||
return { status: installedSystemChromium ? 0 : 127 };
|
||||
}
|
||||
return { status: 1 };
|
||||
});
|
||||
|
||||
expect(
|
||||
ensurePlaywrightChromium({
|
||||
cwd: "/repo",
|
||||
env: { CI: "1", PATH: "/bin" },
|
||||
executablePath: "/cache/chromium/chrome",
|
||||
existsSync: (path: string) =>
|
||||
installedSystemChromium && path === "/usr/bin/chromium-browser",
|
||||
getuid: () => 0,
|
||||
log: (line: string) => logs.push(line),
|
||||
platform: "linux",
|
||||
spawnSync,
|
||||
stdio: "pipe",
|
||||
systemExecutablePath: "",
|
||||
}),
|
||||
).toBe(0);
|
||||
expect(spawnSync).toHaveBeenCalledWith(
|
||||
"apt-get",
|
||||
["update", "-qq"],
|
||||
expect.objectContaining({ cwd: "/repo", stdio: "pipe" }),
|
||||
);
|
||||
expect(spawnSync).toHaveBeenCalledWith(
|
||||
"apt-get",
|
||||
["install", "-y", "chromium-browser"],
|
||||
expect.objectContaining({ cwd: "/repo", stdio: "pipe" }),
|
||||
);
|
||||
expect(logs.join("\n")).toContain("installing a system Chromium package");
|
||||
expect(logs.join("\n")).toContain("Using system Chromium at /usr/bin/chromium-browser");
|
||||
});
|
||||
|
||||
it("does not install Linux system dependencies for an unprivileged local lane", () => {
|
||||
const spawnSync = vi
|
||||
.fn()
|
||||
@@ -343,6 +394,7 @@ describe("ensurePlaywrightChromium", () => {
|
||||
ensurePlaywrightChromium({
|
||||
executablePath: "/cache/chromium/chrome",
|
||||
existsSync: () => false,
|
||||
platform: "darwin",
|
||||
spawnSync: vi.fn(() => ({ status: 23 })),
|
||||
stdio: "pipe",
|
||||
systemExecutablePath: "",
|
||||
@@ -404,4 +456,45 @@ describe("ensurePlaywrightChromium", () => {
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("installs Linux system Chromium packages with sudo for non-root lanes", () => {
|
||||
const spawnSync = vi.fn(() => ({ status: 0 }));
|
||||
|
||||
expect(
|
||||
installLinuxSystemChromiumPackage({
|
||||
cwd: "/repo",
|
||||
env: { PATH: "/bin" },
|
||||
getuid: () => 501,
|
||||
platform: "linux",
|
||||
spawnSync,
|
||||
stdio: "pipe",
|
||||
}),
|
||||
).toBe(0);
|
||||
expect(spawnSync).toHaveBeenNthCalledWith(1, "sudo", ["-n", "true"], { stdio: "ignore" });
|
||||
expect(spawnSync).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
"sudo",
|
||||
["-n", "apt-get", "update", "-qq"],
|
||||
expect.objectContaining({ cwd: "/repo", stdio: "pipe" }),
|
||||
);
|
||||
expect(spawnSync).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
"sudo",
|
||||
["-n", "apt-get", "install", "-y", "chromium-browser"],
|
||||
expect.objectContaining({ cwd: "/repo", stdio: "pipe" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("allows QA scenario runners to skip optional Playwright ffmpeg", () => {
|
||||
expect(shouldEnsureFfmpegFromArgv(["node", "scripts/ensure-playwright-chromium.mjs"])).toBe(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
shouldEnsureFfmpegFromArgv([
|
||||
"node",
|
||||
"scripts/ensure-playwright-chromium.mjs",
|
||||
"--skip-ffmpeg",
|
||||
]),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user