@@ -2688,6 +2688,9 @@ class Playwright extends Helper {
26882688 if ( ( this . context && this . context . constructor . name === 'FrameLocator' ) || this . context ) {
26892689 return this . context
26902690 }
2691+ if ( this . frame ) {
2692+ return this . frame
2693+ }
26912694 return this . page
26922695 }
26932696
@@ -2752,26 +2755,21 @@ class Playwright extends Helper {
27522755 async waitForText ( text , sec = null , context = null ) {
27532756 const waitTimeout = sec ? sec * 1000 : this . options . waitForTimeout
27542757 const errorMessage = `Text "${ text } " was not found on page after ${ waitTimeout / 1000 } sec.`
2755- let waiter
27562758
27572759 const contextObject = await this . _getContext ( )
27582760
27592761 if ( context ) {
27602762 const locator = new Locator ( context , 'css' )
2761- if ( ! locator . isXPath ( ) ) {
2762- try {
2763- await contextObject
2763+ try {
2764+ if ( ! locator . isXPath ( ) ) {
2765+ return contextObject
27642766 . locator ( `${ locator . isCustom ( ) ? `${ locator . type } =${ locator . value } ` : locator . simplify ( ) } >> text=${ text } ` )
27652767 . first ( )
27662768 . waitFor ( { timeout : waitTimeout , state : 'visible' } )
2767- } catch ( e ) {
2768- throw new Error ( `${ errorMessage } \n${ e . message } ` )
27692769 }
2770- }
27712770
2772- if ( locator . isXPath ( ) ) {
2773- try {
2774- await contextObject . waitForFunction (
2771+ if ( locator . isXPath ( ) ) {
2772+ return contextObject . waitForFunction (
27752773 ( [ locator , text , $XPath ] ) => {
27762774 eval ( $XPath ) // eslint-disable-line no-eval
27772775 const el = $XPath ( null , locator )
@@ -2781,27 +2779,34 @@ class Playwright extends Helper {
27812779 [ locator . value , text , $XPath . toString ( ) ] ,
27822780 { timeout : waitTimeout } ,
27832781 )
2784- } catch ( e ) {
2785- throw new Error ( `${ errorMessage } \n${ e . message } ` )
27862782 }
2783+ } catch ( e ) {
2784+ throw new Error ( `${ errorMessage } \n${ e . message } ` )
27872785 }
2788- } else {
2789- // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented
2790-
2791- const _contextObject = this . frame ? this . frame : contextObject
2792- let count = 0
2793- do {
2794- waiter = await _contextObject
2795- . locator ( `:has-text(${ JSON . stringify ( text ) } )` )
2796- . first ( )
2797- . isVisible ( )
2798- if ( waiter ) break
2799- await this . wait ( 1 )
2800- count += 1000
2801- } while ( count <= waitTimeout )
2802-
2803- if ( ! waiter ) throw new Error ( `${ errorMessage } ` )
28042786 }
2787+
2788+ const timeoutGap = waitTimeout + 1000
2789+
2790+ // We add basic timeout to make sure we don't wait forever
2791+ // We apply 2 strategies here: wait for text as innert text on page (wide strategy) - older
2792+ // or we use native Playwright matcher to wait for text in element (narrow strategy) - newer
2793+ // 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
2794+ return Promise . race ( [
2795+ new Promise ( ( _ , reject ) => {
2796+ setTimeout ( ( ) => reject ( errorMessage ) , waitTimeout )
2797+ } ) ,
2798+ this . page . waitForFunction ( text => document . body && document . body . innerText . indexOf ( text ) > - 1 , text , { timeout : timeoutGap } ) ,
2799+ promiseRetry (
2800+ async retry => {
2801+ const textPresent = await contextObject
2802+ . locator ( `:has-text(${ JSON . stringify ( text ) } )` )
2803+ . first ( )
2804+ . isVisible ( )
2805+ if ( ! textPresent ) retry ( errorMessage )
2806+ } ,
2807+ { retries : 1000 , minTimeout : 500 , maxTimeout : 500 , factor : 1 } ,
2808+ ) ,
2809+ ] )
28052810 }
28062811
28072812 /**
0 commit comments