@@ -20,12 +20,13 @@ const test = base.extend<{
2020 args : [ "--headless=new" , ...chromeArgs ] ,
2121 } ) ;
2222 let [ bg ] = ctx1 . serviceWorkers ( ) ;
23- if ( ! bg ) bg = await ctx1 . waitForEvent ( "serviceworker" ) ;
23+ if ( ! bg ) bg = await ctx1 . waitForEvent ( "serviceworker" , { timeout : 30_000 } ) ;
2424 const extensionId = bg . url ( ) . split ( "/" ) [ 2 ] ;
2525 const extPage = await ctx1 . newPage ( ) ;
2626 await extPage . goto ( "chrome://extensions/" ) ;
2727 await extPage . waitForLoadState ( "domcontentloaded" ) ;
28- await extPage . waitForTimeout ( 1_000 ) ;
28+ // Wait for developerPrivate API to be available instead of a fixed delay
29+ await extPage . waitForFunction ( ( ) => ! ! ( chrome as any ) . developerPrivate , { timeout : 10_000 } ) ;
2930 await extPage . evaluate ( async ( id ) => {
3031 await ( chrome as any ) . developerPrivate . updateExtensionConfiguration ( {
3132 extensionId : id ,
@@ -40,6 +41,10 @@ const test = base.extend<{
4041 headless : false ,
4142 args : [ "--headless=new" , ...chromeArgs ] ,
4243 } ) ;
44+ // Ensure service worker is registered before handing context to fixtures,
45+ // preventing extensionId fixture from timing out with the global 10s timeout.
46+ let [ sw ] = context . serviceWorkers ( ) ;
47+ if ( ! sw ) await context . waitForEvent ( "serviceworker" , { timeout : 30_000 } ) ;
4348 await use ( context ) ;
4449 await context . close ( ) ;
4550 fs . rmSync ( userDataDir , { recursive : true , force : true } ) ;
@@ -117,24 +122,25 @@ async function runTestScript(
117122
118123 const page = await context . newPage ( ) ;
119124 const logs : string [ ] = [ ] ;
120- page . on ( "console" , ( msg ) => logs . push ( msg . text ( ) ) ) ;
121-
122- await page . goto ( targetUrl , { waitUntil : "domcontentloaded" } ) ;
123-
124- // Wait for test results to appear in console
125- const deadline = Date . now ( ) + timeoutMs ;
126125 let passed = - 1 ;
127126 let failed = - 1 ;
128- while ( Date . now ( ) < deadline ) {
129- for ( const log of logs ) {
130- const passMatch = log . match ( / 通 过 [: : ] \s * ( \d + ) / ) ;
131- const failMatch = log . match ( / 失 败 [: : ] \s * ( \d + ) / ) ;
127+
128+ // Resolve as soon as both pass and fail counts appear in console output
129+ const resultReady = new Promise < void > ( ( resolve ) => {
130+ page . on ( "console" , ( msg ) => {
131+ const text = msg . text ( ) ;
132+ logs . push ( text ) ;
133+ const passMatch = text . match ( / 通 过 [: : ] \s * ( \d + ) / ) ;
134+ const failMatch = text . match ( / 失 败 [: : ] \s * ( \d + ) / ) ;
132135 if ( passMatch ) passed = parseInt ( passMatch [ 1 ] , 10 ) ;
133136 if ( failMatch ) failed = parseInt ( failMatch [ 1 ] , 10 ) ;
134- }
135- if ( passed >= 0 && failed >= 0 ) break ;
136- await page . waitForTimeout ( 500 ) ;
137- }
137+ if ( passed >= 0 && failed >= 0 ) resolve ( ) ;
138+ } ) ;
139+ } ) ;
140+
141+ await page . goto ( targetUrl , { waitUntil : "domcontentloaded" } ) ;
142+ // Race: resolve immediately when results arrive, or fall through after timeout
143+ await Promise . race ( [ resultReady , page . waitForTimeout ( timeoutMs ) ] ) ;
138144
139145 await page . close ( ) ;
140146 return { passed, failed, logs } ;
0 commit comments