@@ -2779,61 +2779,62 @@ class Playwright extends Helper {
27792779            . locator ( `${ locator . isCustom ( )  ? `${ locator . type } ${ locator . value }   : locator . simplify ( ) } ${ text }  ) 
27802780            . first ( ) 
27812781            . waitFor ( {  timeout : waitTimeout ,  state : 'visible'  } ) 
2782+             . catch ( e  =>  { 
2783+               throw  new  Error ( errorMessage ) 
2784+             } ) 
27822785        } 
27832786
27842787        if  ( locator . isXPath ( ) )  { 
2785-           return  contextObject . waitForFunction ( 
2786-             ( [ locator ,  text ,  $XPath ] )  =>  { 
2787-               eval ( $XPath ) 
2788-               const  el  =  $XPath ( null ,  locator ) 
2789-               if  ( ! el . length )  return  false 
2790-               return  el [ 0 ] . innerText . indexOf ( text )  >  - 1 
2791-             } , 
2792-             [ locator . value ,  text ,  $XPath . toString ( ) ] , 
2793-             {  timeout : waitTimeout  } , 
2794-           ) 
2788+           return  contextObject 
2789+             . waitForFunction ( 
2790+               ( [ locator ,  text ,  $XPath ] )  =>  { 
2791+                 eval ( $XPath ) 
2792+                 const  el  =  $XPath ( null ,  locator ) 
2793+                 if  ( ! el . length )  return  false 
2794+                 return  el [ 0 ] . innerText . indexOf ( text )  >  - 1 
2795+               } , 
2796+               [ locator . value ,  text ,  $XPath . toString ( ) ] , 
2797+               {  timeout : waitTimeout  } , 
2798+             ) 
2799+             . catch ( e  =>  { 
2800+               throw  new  Error ( errorMessage ) 
2801+             } ) 
27952802        } 
27962803      }  catch  ( e )  { 
27972804        throw  new  Error ( `${ errorMessage } ${ e . message }  ) 
27982805      } 
27992806    } 
28002807
2808+     // Based on original implementation but fixed to check title text and remove problematic promiseRetry 
2809+     // Original used timeoutGap for waitForFunction to give it slightly more time than the locator 
28012810    const  timeoutGap  =  waitTimeout  +  1000 
28022811
2803-     // We add basic timeout to make sure we don't wait forever 
2804-     // We apply 2 strategies here: wait for text as innert text on page (wide strategy) - older 
2805-     // or we use native Playwright matcher to wait for text in element (narrow strategy) - newer 
2806-     // If a user waits for text on a page they are mostly expect it to be there, so wide strategy can be helpful even PW strategy is available 
2807- 
2808-     // Use a flag to stop retries when race resolves 
2809-     let  shouldStop  =  false 
2810-     let  timeoutId 
2811- 
2812-     const  racePromise  =  Promise . race ( [ 
2813-       new  Promise ( ( _ ,  reject )  =>  { 
2814-         timeoutId  =  setTimeout ( ( )  =>  reject ( errorMessage ) ,  waitTimeout ) 
2815-       } ) , 
2816-       this . page . waitForFunction ( text  =>  document . body  &&  document . body . innerText . indexOf ( text )  >  - 1 ,  text ,  {  timeout : timeoutGap  } ) , 
2817-       promiseRetry ( 
2818-         async  ( retry ,  number )  =>  { 
2819-           // Stop retrying if race has resolved 
2820-           if  ( shouldStop )  { 
2821-             throw  new  Error ( 'Operation cancelled' ) 
2812+     return  Promise . race ( [ 
2813+       // Strategy 1: waitForFunction that checks both body AND title text 
2814+       // Use this.page instead of contextObject because FrameLocator doesn't have waitForFunction 
2815+       // Original only checked document.body.innerText, missing title text like "TestEd" 
2816+       this . page . waitForFunction ( 
2817+         function  ( text )  { 
2818+           // Check body text (original behavior) 
2819+           if  ( document . body  &&  document . body . innerText  &&  document . body . innerText . indexOf ( text )  >  - 1 )  { 
2820+             return  true 
28222821          } 
2823-           const   textPresent   =   await   contextObject 
2824-              . locator ( `:has-text( ${ JSON . stringify ( text ) } )` ) 
2825-             . first ( ) 
2826-              . isVisible ( ) 
2827-           if   ( ! textPresent )   retry ( errorMessage ) 
2822+           // Check document title (fixes the TestEd in title issue) 
2823+           if   ( document . title   &&   document . title . indexOf ( text )   >   - 1 )   { 
2824+             return   true 
2825+           } 
2826+           return   false 
28282827        } , 
2829-         {  retries : 10 ,  minTimeout : 100 ,  maxTimeout : 500 ,  factor : 1.5  } , 
2828+         text , 
2829+         {  timeout : timeoutGap  } , 
28302830      ) , 
2831-     ] ) 
2832- 
2833-     // Clean up when race resolves/rejects 
2834-     return  racePromise . finally ( ( )  =>  { 
2835-       if  ( timeoutId )  clearTimeout ( timeoutId ) 
2836-       shouldStop  =  true 
2831+       // Strategy 2: Native Playwright text locator (replaces problematic promiseRetry) 
2832+       contextObject 
2833+         . locator ( `:has-text(${ JSON . stringify ( text ) }  ) 
2834+         . first ( ) 
2835+         . waitFor ( {  timeout : waitTimeout  } ) , 
2836+     ] ) . catch ( err  =>  { 
2837+       throw  new  Error ( errorMessage ) 
28372838    } ) 
28382839  } 
28392840
0 commit comments