@@ -13,10 +13,11 @@ public class Frame
1313 private string _defaultContextId = "<not-initialized>" ;
1414 private object _context = null ;
1515 private string _url = string . Empty ;
16- private List < WaitTask > _waitTasks ;
1716 private bool _detached ;
1817 private TaskCompletionSource < ElementHandle > _documentCompletionSource ;
1918
19+ internal List < WaitTask > WaitTasks { get ; }
20+
2021 public Frame ( Session client , Page page , Frame parentFrame , string frameId )
2122 {
2223 _client = client ;
@@ -31,7 +32,7 @@ public Frame(Session client, Page page, Frame parentFrame, string frameId)
3132
3233 SetDefaultContext ( null ) ;
3334
34- _waitTasks = new List < WaitTask > ( ) ;
35+ WaitTasks = new List < WaitTask > ( ) ;
3536 LifecycleEvents = new List < string > ( ) ;
3637 }
3738
@@ -163,7 +164,7 @@ internal void SetDefaultContext(ExecutionContext context)
163164 {
164165 ContextResolveTaskWrapper . SetResult ( context ) ;
165166
166- foreach ( var waitTask in _waitTasks )
167+ foreach ( var waitTask in WaitTasks )
167168 {
168169 waitTask . Rerun ( ) ;
169170 }
@@ -176,7 +177,7 @@ internal void SetDefaultContext(ExecutionContext context)
176177
177178 internal void Detach ( )
178179 {
179- foreach ( var waitTask in _waitTasks )
180+ foreach ( var waitTask in WaitTasks )
180181 {
181182 waitTask . Termiante ( new Exception ( "waitForSelector failed: frame got detached." ) ) ;
182183 }
@@ -188,10 +189,43 @@ internal void Detach()
188189 _parentFrame = null ;
189190 }
190191
192+ internal Task WaitForTimeoutAsync ( int milliseconds ) => Task . Delay ( milliseconds ) ;
193+
194+ internal Task < JSHandle > WaitForFunctionAsync ( string script , WaitForFunctionOptions options , params object [ ] args )
195+ => new WaitTask ( this , script , options . Polling , options . Timeout , args ) . Task ;
196+
197+ internal async Task < ElementHandle > WaitForSelectorAsync ( string selector , WaitForSelectorOptions options )
198+ {
199+ const string predicate = @"
200+ function predicate(selector, waitForVisible, waitForHidden) {
201+ const node = document.querySelector(selector);
202+ if (!node)
203+ return waitForHidden;
204+ if (!waitForVisible && !waitForHidden)
205+ return node;
206+ const style = window.getComputedStyle(node);
207+ const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox();
208+ const success = (waitForVisible === isVisible || waitForHidden === !isVisible);
209+ return success ? node : null;
210+
211+ function hasVisibleBoundingBox() {
212+ const rect = node.getBoundingClientRect();
213+ return !!(rect.top || rect.bottom || rect.width || rect.height);
214+ }
215+ }" ;
216+ var polling = options . Visible || options . Hidden ? WaitForFunctionPollingOption . Raf : WaitForFunctionPollingOption . Mutation ;
217+ var handle = await WaitForFunctionAsync ( predicate , new WaitForFunctionOptions
218+ {
219+ Timeout = options . Timeout ,
220+ Polling = polling
221+ } , selector , options . Visible , options . Hidden ) ;
222+ return handle . AsElement ( ) ;
223+ }
224+
191225 #endregion
192226
193227 #region Private Methods
194-
228+
195229 private async Task < ElementHandle > GetDocument ( )
196230 {
197231 if ( _documentCompletionSource == null )
0 commit comments