11import { errors , Page } from '@playwright/test' ;
2+ import { WaitForMetaMaskLoadOptions } from '../template/types' ;
23import { waitUntilStable } from '../template/waitUntilStable' ;
34
45const DEFAULT_TIMEOUT = 10_000 ;
5- const DEFAULT_POST_DELAY_MS = 300 ;
6+ const DEFAULT_CONCURRENCY = 3 ;
67
7- // Core loading indicators commonly found in MetaMask screens
88const BASE_LOADING_SELECTORS : readonly string [ ] = [
99 '.loading-logo' ,
1010 '.loading-spinner' ,
@@ -20,71 +20,73 @@ const BASE_LOADING_SELECTORS: readonly string[] = [
2020 '.spinner'
2121] ;
2222
23- type WaitForMetaMaskLoadOptions = {
24- // Per-selector timeout while waiting to become hidden (defaults to 10s).
25- selectorTimeoutMs ?: number ;
26- // Additional page selectors that should also be hidden before continuing.
27- extraLoadingSelectors ?: string [ ] ;
28- // Milliseconds to sleep after the page looks ready (defaults to 300ms).
29- postDelayMs ?: number ;
30- // Skip the initial stable wait if you’ve already done it.
31- skipInitialStabilityWait ?: boolean ;
32- } ;
33-
34- // Waits for MetaMask UI to become usable:
35- // 1) (optionally) waits for DOM/network to settle
36- // 2) waits for known loading indicators to disappear (best-effort)
37- // 3) small post-delay to avoid flakiness on slow CI
23+ /**
24+ * Waits for MetaMask UI to be usable:
25+ * 1) (optional) wait for page stability
26+ * 2) wait for known loading indicators to hide (best-effort)
27+ * 3) brief post delay (conditional)
28+ */
3829export async function waitForMetaMaskLoad (
3930 page : Page ,
40- options : WaitForMetaMaskLoadOptions = { }
41- ) : Promise < Page > {
31+ options : WaitForMetaMaskLoadOptions
32+ ) : Promise < void > {
4233 const {
4334 selectorTimeoutMs = DEFAULT_TIMEOUT ,
4435 extraLoadingSelectors = [ ] ,
45- postDelayMs = DEFAULT_POST_DELAY_MS ,
46- skipInitialStabilityWait = false
36+ skipInitialStabilityWait = false ,
37+ concurrency = DEFAULT_CONCURRENCY // how many selectors to wait on in parallel
4738 } = options ;
4839
4940 try {
5041 if ( ! skipInitialStabilityWait ) {
5142 await waitUntilStable ( page ) ;
5243 }
5344
54- const selectors = [ ...BASE_LOADING_SELECTORS , ...extraLoadingSelectors ] ;
45+ const selectors = Array . from (
46+ new Set ( [ ...BASE_LOADING_SELECTORS , ...extraLoadingSelectors ] )
47+ ) ;
5548
56- await waitForSelectorsHidden ( page , selectors , selectorTimeoutMs ) ;
49+ await waitSelectorsHiddenWithConcurrency (
50+ page ,
51+ selectors ,
52+ selectorTimeoutMs ,
53+ concurrency
54+ ) ;
5755 } catch ( err ) {
58- // Don’t fail the test — UI might still be interactive
5956 const msg = err instanceof Error ? err . message : String ( err ) ;
6057 console . warn ( `[waitForMetaMaskLoad] Non-fatal warning: ${ msg } ` ) ;
6158 }
62-
63- await page . waitForTimeout ( postDelayMs ) ;
64- return page ;
6559}
6660
67- // Wait until each selector is hidden; ignore timeouts (selector may not exist on this screen).
68- async function waitForSelectorsHidden (
61+ async function waitSelectorsHiddenWithConcurrency (
6962 page : Page ,
7063 selectors : string [ ] ,
71- perSelectorTimeoutMs : number
72- ) : Promise < void > {
73- await Promise . all (
74- selectors . map ( async ( selector ) => {
75- try {
76- await waitUntilStable ( page ) ;
77- await page . waitForSelector ( selector , {
78- state : 'hidden' ,
79- timeout : perSelectorTimeoutMs
80- } ) ;
81- } catch ( err ) {
82- if ( err instanceof errors . TimeoutError ) {
83- // OK: selector may never appear on this view; continue
84- return ;
64+ perSelectorTimeoutMs : number ,
65+ concurrency : number
66+ ) {
67+ // One stability wait per batch, not per selector
68+ await waitUntilStable ( page ) ;
69+
70+ // Process selectors with a small concurrency to reduce polling in CI/CD
71+ let i = 0 ;
72+ while ( i < selectors . length ) {
73+ const batch = selectors . slice ( i , i + Math . max ( 1 , concurrency ) ) ;
74+ await Promise . all (
75+ batch . map ( async ( selector ) => {
76+ try {
77+ await page . waitForSelector ( selector , {
78+ state : 'hidden' ,
79+ timeout : perSelectorTimeoutMs
80+ } ) ;
81+ } catch ( err ) {
82+ if ( err instanceof errors . TimeoutError ) {
83+ // OK if a selector never appears on this screen
84+ return ;
85+ }
86+ throw err ;
8587 }
86- throw err ;
87- }
88- } )
89- ) ;
88+ } )
89+ ) ;
90+ i += batch . length ;
91+ }
9092}
0 commit comments