11import { execSync , spawn } from 'child_process'
2+ import * as fs from 'node:fs'
3+ import * as path from 'node:path'
4+ import * as os from 'node:os'
25
36const BOOT_TIMEOUT_MS = 300_000
47const BOOT_POLL_INTERVAL_MS = 2_000
@@ -24,6 +27,7 @@ export default async function globalSetup() {
2427
2528 await waitForBoot ( )
2629 setupAdbReverse ( )
30+ await installChromium ( )
2731
2832 process . env . ANDROID_E2E = 'true'
2933}
@@ -60,3 +64,68 @@ function setupAdbReverse() {
6064
6165 console . log ( `Forwarded ports: ${ DEV_SERVER_PORT } , ${ PORT_RANGE_START } -${ PORT_RANGE_END } ` )
6266}
67+
68+ async function installChromium ( ) {
69+ // The system Chrome on the emulator is v113, which is too old for many web APIs
70+ // (LoAf, modern resource timing, etc.). Install a recent Chromium from snapshots.
71+ console . log ( 'Installing Chromium on emulator...' )
72+
73+ try {
74+ // Get the latest Chromium snapshot revision for Android ARM64
75+ const revisionResponse = await fetch (
76+ 'https://storage.googleapis.com/chromium-browser-snapshots/Android_Arm64/LAST_CHANGE'
77+ )
78+ const revision = ( await revisionResponse . text ( ) ) . trim ( )
79+ console . log ( `Latest Chromium ARM64 snapshot revision: ${ revision } ` )
80+
81+ // Download the Chromium Android ARM64 build
82+ const downloadUrl = `https://storage.googleapis.com/chromium-browser-snapshots/Android_Arm64/${ revision } /chrome-android.zip`
83+ console . log ( `Downloading from ${ downloadUrl } ` )
84+
85+ const tmpDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'chromium-android-' ) )
86+ const zipPath = path . join ( tmpDir , 'chrome-android.zip' )
87+
88+ const downloadResponse = await fetch ( downloadUrl )
89+ if ( ! downloadResponse . ok ) {
90+ console . log ( `Download failed: ${ downloadResponse . status } ` )
91+ return
92+ }
93+
94+ const buffer = Buffer . from ( await downloadResponse . arrayBuffer ( ) )
95+ fs . writeFileSync ( zipPath , buffer )
96+ console . log ( `Downloaded ${ ( buffer . length / 1024 / 1024 ) . toFixed ( 1 ) } MB` )
97+
98+ // Extract the zip
99+ execSync ( `unzip -o "${ zipPath } " -d "${ tmpDir } "` , { timeout : 60_000 } )
100+
101+ // Find APKs
102+ const apks = execSync ( `find "${ tmpDir } " -name "*.apk"` , { encoding : 'utf-8' , timeout : 5_000 } )
103+ . trim ( )
104+ . split ( '\n' )
105+ . filter ( Boolean )
106+
107+ console . log ( `Found APKs: ${ apks . map ( ( a ) => path . basename ( a ) ) . join ( ', ' ) } ` )
108+
109+ // Install ChromePublic.apk (the main Chromium browser)
110+ const chromeApk = apks . find ( ( a ) => path . basename ( a ) === 'ChromePublic.apk' )
111+ if ( ! chromeApk ) {
112+ console . log ( 'ChromePublic.apk not found in download' )
113+ return
114+ }
115+
116+ const result = execSync ( `adb install -r -d "${ chromeApk } "` , { encoding : 'utf-8' , timeout : 120_000 } )
117+ console . log ( `Install result: ${ result . trim ( ) } ` )
118+
119+ // Log the installed Chromium version
120+ const versionInfo = execSync ( 'adb shell dumpsys package org.chromium.chrome | grep versionName' , {
121+ encoding : 'utf-8' ,
122+ timeout : 5_000 ,
123+ } ) . trim ( )
124+ console . log ( `Chromium installed: ${ versionInfo } ` )
125+
126+ // Cleanup
127+ fs . rmSync ( tmpDir , { recursive : true , force : true } )
128+ } catch ( error ) {
129+ console . log ( 'Chromium install failed (non-fatal):' , error )
130+ }
131+ }
0 commit comments