@@ -38,6 +38,7 @@ let playwright
3838let  perfTiming 
3939let  defaultSelectorEnginesInitialized  =  false 
4040let  registeredCustomLocatorStrategies  =  new  Set ( ) 
41+ let  globalCustomLocatorStrategies  =  new  Map ( ) 
4142
4243const  popupStore  =  new  Popup ( ) 
4344const  consoleLogStore  =  new  Console ( ) 
@@ -348,8 +349,18 @@ class Playwright extends Helper {
348349    this . customLocatorStrategies  =  typeof  config . customLocatorStrategies  ===  'object'  &&  config . customLocatorStrategies  !==  null  ? config . customLocatorStrategies  : null 
349350    this . _customLocatorsRegistered  =  false 
350351
352+     // Add custom locator strategies to global registry for early registration 
353+     if  ( this . customLocatorStrategies )  { 
354+       for  ( const  [ strategyName ,  strategyFunction ]  of  Object . entries ( this . customLocatorStrategies ) )  { 
355+         globalCustomLocatorStrategies . set ( strategyName ,  strategyFunction ) 
356+       } 
357+     } 
358+ 
351359    // override defaults with config 
352360    this . _setConfig ( config ) 
361+     
362+     // Ensure _init() is called early to register custom selectors 
363+     this . _init ( ) . catch ( console . warn ) 
353364  } 
354365
355366  _validateConfig ( config )  { 
@@ -472,6 +483,49 @@ class Playwright extends Helper {
472483      await  playwright . selectors . register ( '__value' ,  createValueEngine ) 
473484      await  playwright . selectors . register ( '__disabled' ,  createDisabledEngine ) 
474485      if  ( process . env . testIdAttribute )  await  playwright . selectors . setTestIdAttribute ( process . env . testIdAttribute ) 
486+       
487+       // Register all custom locator strategies from the global registry 
488+       for  ( const  [ strategyName ,  strategyFunction ]  of  globalCustomLocatorStrategies . entries ( ) )  { 
489+         if  ( ! registeredCustomLocatorStrategies . has ( strategyName ) )  { 
490+           try  { 
491+             // Create a selector engine as JavaScript code string 
492+             const  selectorEngineCode  =  ` 
493+               (() => ({ 
494+                 create(root, target) { 
495+                   return null; 
496+                 }, 
497+                 query(root, selector) { 
498+                   try { 
499+                     const strategyFunction = ${ strategyFunction . toString ( ) }  
500+                     const result = strategyFunction(selector, root); 
501+                     return Array.isArray(result) ? result[0] : result; 
502+                   } catch (error) { 
503+                     console.warn('Error in custom locator "${ strategyName }  
504+                     return null; 
505+                   } 
506+                 }, 
507+                 queryAll(root, selector) { 
508+                   try { 
509+                     const strategyFunction = ${ strategyFunction . toString ( ) }  
510+                     const result = strategyFunction(selector, root); 
511+                     return Array.isArray(result) ? result : result ? [result] : []; 
512+                   } catch (error) { 
513+                     console.warn('Error in custom locator "${ strategyName }  
514+                     return []; 
515+                   } 
516+                 } 
517+               }))() 
518+             ` ; 
519+ 
520+             await  playwright . selectors . register ( strategyName ,  {  content : selectorEngineCode  } ) 
521+             registeredCustomLocatorStrategies . add ( strategyName ) 
522+           }  catch  ( error )  { 
523+             if  ( ! error . message . includes ( 'already registered' ) )  { 
524+               console . warn ( `Failed to register global custom locator strategy '${ strategyName }  ,  error ) 
525+             } 
526+           } 
527+         } 
528+       } 
475529    }  catch  ( e )  { 
476530      console . warn ( e ) 
477531    } 
@@ -861,10 +915,6 @@ class Playwright extends Helper {
861915      this . debugSection ( 'Url' ,  target . url ( ) ) 
862916    } ) 
863917
864-     // Register custom locator strategies for this helper instance 
865-     await  this . _registerCustomLocatorStrategies ( ) 
866-     this . _customLocatorsRegistered  =  true 
867- 
868918    this . isRunning  =  true 
869919    return  this . browser 
870920  } 
@@ -893,47 +943,6 @@ class Playwright extends Helper {
893943    return  ! ! ( this . customLocatorStrategies  &&  Object . keys ( this . customLocatorStrategies ) . length  >  0 ) 
894944  } 
895945
896-   async  _registerCustomLocatorStrategies ( )  { 
897-     if  ( this . _isCustomLocatorStrategyDefined ( ) )  { 
898-       for  ( const  [ strategyName ,  strategyFunction ]  of  Object . entries ( this . customLocatorStrategies ) )  { 
899-         try  { 
900-           this . debugSection ( 'Playwright' ,  `registering custom locator strategy: ${ strategyName }  ) 
901- 
902-           // Create a selector engine object similar to the default engines 
903-           const  selectorEngine  =  { 
904-             query ( root ,  selector )  { 
905-               try  { 
906-                 const  result  =  strategyFunction ( selector ,  root ) ; 
907-                 return  Array . isArray ( result )  ? result [ 0 ]  : result ; 
908-               }  catch  ( error )  { 
909-                 console . warn ( `Error in custom locator "${ strategyName }  ,  error ) ; 
910-                 return  null ; 
911-               } 
912-             } , 
913-             
914-             queryAll ( root ,  selector )  { 
915-               try  { 
916-                 const  result  =  strategyFunction ( selector ,  root ) ; 
917-                 return  Array . isArray ( result )  ? result  : result  ? [ result ]  : [ ] ; 
918-               }  catch  ( error )  { 
919-                 console . warn ( `Error in custom locator "${ strategyName }  ,  error ) ; 
920-                 return  [ ] ; 
921-               } 
922-             } 
923-           } 
924- 
925-           await  playwright . selectors . register ( strategyName ,  selectorEngine ) 
926-           registeredCustomLocatorStrategies . add ( strategyName ) 
927-         }  catch  ( error )  { 
928-           // Ignore "already registered" errors, warn about others 
929-           if  ( ! error . message . includes ( 'already registered' ) )  { 
930-             console . warn ( `Failed to register custom locator strategy '${ strategyName }  ,  error ) 
931-           } 
932-         } 
933-       } 
934-     } 
935-   } 
936- 
937946  /** 
938947   * Create a new browser context with a page. \ 
939948   * Usually it should be run from a custom helper after call of `_startBrowser()` 
@@ -1166,9 +1175,6 @@ class Playwright extends Helper {
11661175    const  src  =  new  Locator ( srcElement ) 
11671176    const  dst  =  new  Locator ( destElement ) 
11681177
1169-     // Ensure custom locators are registered 
1170-     await  this . _ensureCustomLocatorsRegistered ( ) 
1171- 
11721178    if  ( options )  { 
11731179      return  this . page . dragAndDrop ( buildLocatorString ( src ) ,  buildLocatorString ( dst ) ,  options ) 
11741180    } 
@@ -1330,27 +1336,6 @@ class Playwright extends Helper {
13301336    return  this . page . title ( ) 
13311337  } 
13321338
1333-   async  _ensureCustomLocatorsRegistered ( )  { 
1334-     // Only register once, and only if we have strategies defined 
1335-     if  ( this . _customLocatorsRegistered  ||  ! this . _isCustomLocatorStrategyDefined ( ) )  { 
1336-       return 
1337-     } 
1338- 
1339-     try  { 
1340-       // If browser isn't running yet, start it to register selectors 
1341-       if  ( ! this . isRunning  &&  ! this . options . manualStart )  { 
1342-         await  this . _startBrowser ( ) 
1343-       }  else  { 
1344-         // If browser is running but custom locators not registered, register them now 
1345-         await  this . _registerCustomLocatorStrategies ( ) 
1346-       } 
1347-       this . _customLocatorsRegistered  =  true 
1348-     }  catch  ( error )  { 
1349-       console . warn ( 'Failed to register custom locators:' ,  error . message ) 
1350-       // Continue execution - the error will surface when the locator is actually used 
1351-     } 
1352-   } 
1353- 
13541339  /** 
13551340   * Get elements by different locator types, including strict locator 
13561341   * Should be used in custom helpers: 
@@ -1360,9 +1345,6 @@ class Playwright extends Helper {
13601345   * ``` 
13611346   */ 
13621347  async  _locate ( locator )  { 
1363-     // Ensure custom locators are registered before any locator operations 
1364-     await  this . _ensureCustomLocatorsRegistered ( ) 
1365- 
13661348    const  context  =  await  this . _getContext ( ) 
13671349
13681350    if  ( this . frame )  return  findElements ( this . frame ,  locator ) 
@@ -1394,9 +1376,6 @@ class Playwright extends Helper {
13941376   * ``` 
13951377   */ 
13961378  async  _locateElement ( locator )  { 
1397-     // Ensure custom locators are registered before any locator operations 
1398-     await  this . _ensureCustomLocatorsRegistered ( ) 
1399- 
14001379    const  context  =  await  this . _getContext ( ) 
14011380    return  findElement ( context ,  locator ) 
14021381  } 
@@ -2678,9 +2657,6 @@ class Playwright extends Helper {
26782657    const  waitTimeout  =  sec  ? sec  *  1000  : this . options . waitForTimeout 
26792658    locator  =  new  Locator ( locator ,  'css' ) 
26802659
2681-     // Ensure custom locators are registered 
2682-     await  this . _ensureCustomLocatorsRegistered ( ) 
2683- 
26842660    const  context  =  await  this . _getContext ( ) 
26852661    try  { 
26862662      await  context . locator ( buildLocatorString ( locator ) ) . first ( ) . waitFor ( {  timeout : waitTimeout ,  state : 'attached'  } ) 
@@ -2698,9 +2674,6 @@ class Playwright extends Helper {
26982674    const  waitTimeout  =  sec  ? sec  *  1000  : this . options . waitForTimeout 
26992675    locator  =  new  Locator ( locator ,  'css' ) 
27002676
2701-     // Ensure custom locators are registered 
2702-     await  this . _ensureCustomLocatorsRegistered ( ) 
2703- 
27042677    const  context  =  await  this . _getContext ( ) 
27052678    let  count  =  0 
27062679
@@ -2731,9 +2704,6 @@ class Playwright extends Helper {
27312704    const  waitTimeout  =  sec  ? sec  *  1000  : this . options . waitForTimeout 
27322705    locator  =  new  Locator ( locator ,  'css' ) 
27332706
2734-     // Ensure custom locators are registered 
2735-     await  this . _ensureCustomLocatorsRegistered ( ) 
2736- 
27372707    const  context  =  await  this . _getContext ( ) 
27382708    let  waiter 
27392709    let  count  =  0 
@@ -2765,9 +2735,6 @@ class Playwright extends Helper {
27652735    const  waitTimeout  =  sec  ? sec  *  1000  : this . options . waitForTimeout 
27662736    locator  =  new  Locator ( locator ,  'css' ) 
27672737
2768-     // Ensure custom locators are registered 
2769-     await  this . _ensureCustomLocatorsRegistered ( ) 
2770- 
27712738    const  context  =  await  this . _getContext ( ) 
27722739    let  waiter 
27732740    let  count  =  0 
@@ -2884,9 +2851,6 @@ class Playwright extends Helper {
28842851    const  waitTimeout  =  sec  ? sec  *  1000  : this . options . waitForTimeout 
28852852    const  errorMessage  =  `Text "${ text } ${ waitTimeout  /  1000 }  
28862853
2887-     // Ensure custom locators are registered 
2888-     await  this . _ensureCustomLocatorsRegistered ( ) 
2889- 
28902854    const  contextObject  =  await  this . _getContext ( ) 
28912855
28922856    if  ( context )  { 
@@ -3108,9 +3072,6 @@ class Playwright extends Helper {
31083072    const  waitTimeout  =  sec  ? sec  *  1000  : this . options . waitForTimeout 
31093073    locator  =  new  Locator ( locator ,  'css' ) 
31103074
3111-     // Ensure custom locators are registered 
3112-     await  this . _ensureCustomLocatorsRegistered ( ) 
3113- 
31143075    let  waiter 
31153076    const  context  =  await  this . _getContext ( ) 
31163077    if  ( ! locator . isXPath ( ) )  { 
0 commit comments