@@ -10,6 +10,7 @@ import { resolvePnpmRunner } from "./pnpm-runner.mjs";
1010const repoRoot = resolve ( dirname ( fileURLToPath ( import . meta. url ) ) , ".." ) ;
1111const playwrightInstallBaseArgs = [ "--dir" , "ui" , "exec" , "playwright" , "install" ] ;
1212const executableOverrideEnvKey = "PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH" ;
13+ const chromiumPackageNames = [ "chromium-browser" , "chromium" ] ;
1314/**
1415 * System Chromium executable paths used before downloading Playwright browsers.
1516 */
@@ -89,6 +90,68 @@ export function shouldInstallPlaywrightSystemDependencies(options = {}) {
8990 ) ;
9091}
9192
93+ function resolveLinuxPrivilegePrefix ( options = { } ) {
94+ const getuid = options . getuid ?? process . getuid ;
95+ const spawnSync = options . spawnSync ?? spawnSyncImpl ;
96+ if ( typeof getuid === "function" && getuid ( ) === 0 ) {
97+ return [ ] ;
98+ }
99+ const result = spawnSync ( "sudo" , [ "-n" , "true" ] , { stdio : "ignore" } ) ;
100+ if ( result . status === 0 ) {
101+ return [ "sudo" , "-n" ] ;
102+ }
103+ return undefined ;
104+ }
105+
106+ /**
107+ * Installs a distro Chromium package for CI images newer than Playwright's
108+ * bundled browser support matrix.
109+ */
110+ export function installLinuxSystemChromiumPackage ( options = { } ) {
111+ const platform = options . platform ?? process . platform ;
112+ if ( platform !== "linux" ) {
113+ return 1 ;
114+ }
115+ const spawnSync = options . spawnSync ?? spawnSyncImpl ;
116+ const privilegePrefix = resolveLinuxPrivilegePrefix ( {
117+ getuid : options . getuid ,
118+ spawnSync,
119+ } ) ;
120+ if ( ! privilegePrefix ) {
121+ return 1 ;
122+ }
123+ const env = {
124+ ...( options . env ?? process . env ) ,
125+ DEBIAN_FRONTEND : "noninteractive" ,
126+ } ;
127+ const cwd = options . cwd ?? repoRoot ;
128+ const stdio = options . stdio ?? "inherit" ;
129+ const runAptGet = ( args ) => {
130+ const command = privilegePrefix [ 0 ] ?? "apt-get" ;
131+ const commandArgs =
132+ privilegePrefix . length === 0 ? args : [ ...privilegePrefix . slice ( 1 ) , "apt-get" , ...args ] ;
133+ return (
134+ spawnSync ( command , commandArgs , {
135+ cwd,
136+ env,
137+ stdio,
138+ } ) . status ?? 1
139+ ) ;
140+ } ;
141+
142+ const updateStatus = runAptGet ( [ "update" , "-qq" ] ) ;
143+ if ( updateStatus !== 0 ) {
144+ return updateStatus ;
145+ }
146+ for ( const packageName of chromiumPackageNames ) {
147+ const installStatus = runAptGet ( [ "install" , "-y" , packageName ] ) ;
148+ if ( installStatus === 0 ) {
149+ return 0 ;
150+ }
151+ }
152+ return 1 ;
153+ }
154+
92155/**
93156 * Checks whether this module is the direct script entrypoint.
94157 */
@@ -135,6 +198,31 @@ export function ensurePlaywrightChromium(options = {}) {
135198 } ) ;
136199 return result . status ?? 1 ;
137200 } ;
201+ const useLinuxSystemChromiumPackage = ( ) => {
202+ log ( `[ui-e2e] Playwright install is unavailable; installing a system Chromium package.` ) ;
203+ const installStatus = installLinuxSystemChromiumPackage ( {
204+ cwd : options . cwd ,
205+ env,
206+ getuid : options . getuid ,
207+ platform : options . platform ,
208+ spawnSync,
209+ stdio : options . stdio ,
210+ } ) ;
211+ if ( installStatus !== 0 ) {
212+ log ( `[ui-e2e] System Chromium package install failed with status ${ installStatus } .` ) ;
213+ return installStatus ;
214+ }
215+ const installedSystemExecutablePath = resolveSystemChromiumExecutablePath (
216+ existsSync ,
217+ spawnSync ,
218+ ) ;
219+ if ( installedSystemExecutablePath ) {
220+ log ( `[ui-e2e] Using system Chromium at ${ installedSystemExecutablePath } .` ) ;
221+ return ensureFfmpeg ( ) ;
222+ }
223+ log ( `[ui-e2e] System Chromium package install completed but no runnable Chromium was found.` ) ;
224+ return 1 ;
225+ } ;
138226 const ensureFfmpeg = ( ) => {
139227 if ( ! options . ensureFfmpeg ) {
140228 return 0 ;
@@ -188,7 +276,7 @@ export function ensurePlaywrightChromium(options = {}) {
188276 ) ;
189277 const depsStatus = runPlaywrightInstall ( [ "chromium" ] , true ) ;
190278 if ( depsStatus !== 0 ) {
191- return depsStatus ;
279+ return useLinuxSystemChromiumPackage ( ) ;
192280 }
193281 if ( existsSync ( executablePath ) && canRunChromiumExecutable ( executablePath , spawnSync ) ) {
194282 return ensureFfmpeg ( ) ;
@@ -208,11 +296,12 @@ export function ensurePlaywrightChromium(options = {}) {
208296 ) ;
209297 const depsStatus = runPlaywrightInstall ( [ "chromium" ] , true ) ;
210298 if ( depsStatus !== 0 ) {
211- return depsStatus ;
299+ return useLinuxSystemChromiumPackage ( ) ;
212300 }
213301 if ( existsSync ( executablePath ) && canRunChromiumExecutable ( executablePath , spawnSync ) ) {
214302 return ensureFfmpeg ( ) ;
215303 }
304+ return useLinuxSystemChromiumPackage ( ) ;
216305 }
217306 log (
218307 `[ui-e2e] Playwright install completed but Chromium is still not runnable at ${ executablePath } .` ,
@@ -222,6 +311,12 @@ export function ensurePlaywrightChromium(options = {}) {
222311 return ensureFfmpeg ( ) ;
223312}
224313
314+ export function shouldEnsureFfmpegFromArgv ( argv = process . argv ) {
315+ return ! argv . includes ( "--skip-ffmpeg" ) ;
316+ }
317+
225318if ( isDirectScriptExecution ( ) ) {
226- process . exitCode = ensurePlaywrightChromium ( { ensureFfmpeg : true } ) ;
319+ process . exitCode = ensurePlaywrightChromium ( {
320+ ensureFfmpeg : shouldEnsureFfmpegFromArgv ( ) ,
321+ } ) ;
227322}
0 commit comments