How to use FrameTree class of PuppeteerSharp package

Best Puppeteer-sharp code snippet using PuppeteerSharp.FrameTree

Page.cs

Source:Page.cs Github

copy

Full Screen

...45            {"in", 96},46            {"cm", 37.8m},47            {"mm", 3.78m}48        };49        private Page(CDPSession client, Target target, FrameTree frameTree, bool ignoreHTTPSErrors, TaskQueue screenshotTaskQueue)50        {51            Client = client;52            Target = target;53            Keyboard = new Keyboard(client);54            Mouse = new Mouse(client, Keyboard);55            Touchscreen = new Touchscreen(client, Keyboard);56            Tracing = new Tracing(client);57            Coverage = new Coverage(client);58            _frameManager = new FrameManager(client, frameTree, this);59            _networkManager = new NetworkManager(client, _frameManager);60            _emulationManager = new EmulationManager(client);61            _pageBindings = new Dictionary<string, Delegate>();62            _logger = Client.Connection.LoggerFactory.CreateLogger<Page>();63            _ignoreHTTPSErrors = ignoreHTTPSErrors;64            _screenshotTaskQueue = screenshotTaskQueue;65            _frameManager.FrameAttached += (sender, e) => FrameAttached?.Invoke(this, e);66            _frameManager.FrameDetached += (sender, e) => FrameDetached?.Invoke(this, e);67            _frameManager.FrameNavigated += (sender, e) => FrameNavigated?.Invoke(this, e);68            _networkManager.Request += (sender, e) => Request?.Invoke(this, e);69            _networkManager.RequestFailed += (sender, e) => RequestFailed?.Invoke(this, e);70            _networkManager.Response += (sender, e) => Response?.Invoke(this, e);71            _networkManager.RequestFinished += (sender, e) => RequestFinished?.Invoke(this, e);72            Client.MessageReceived += client_MessageReceived;73        }74        internal CDPSession Client { get; }75        #region Public Properties76        /// <summary>77        /// Raised when the JavaScript <c>load</c> <see href="https://developer.mozilla.org/en-US/docs/Web/Events/load"/> event is dispatched.78        /// </summary>79        public event EventHandler<EventArgs> Load;80        /// <summary>81        /// Raised when the page crashes82        /// </summary>83        public event EventHandler<ErrorEventArgs> Error;84        /// <summary>85        /// Raised when the JavaScript code makes a call to <c>console.timeStamp</c>. For the list of metrics see <see cref="Page.MetricsAsync"/>.86        /// </summary>87        public event EventHandler<MetricEventArgs> Metrics;88        /// <summary>89        /// Raised when a JavaScript dialog appears, such as <c>alert</c>, <c>prompt</c>, <c>confirm</c> or <c>beforeunload</c>. Puppeteer can respond to the dialog via <see cref="Dialog"/>'s <see cref="Dialog.Accept(string)"/> or <see cref="Dialog.Dismiss"/> methods.90        /// </summary>91        public event EventHandler<DialogEventArgs> Dialog;92        /// <summary>93        /// Raised when JavaScript within the page calls one of console API methods, e.g. <c>console.log</c> or <c>console.dir</c>. Also emitted if the page throws an error or a warning.94        /// The arguments passed into <c>console.log</c> appear as arguments on the event handler.95        /// </summary>96        /// <example>97        /// An example of handling <see cref="Console"/> event:98        /// <code>99        /// <![CDATA[100        /// page.Console += (sender, e) => 101        /// {102        ///     for (var i = 0; i < e.Message.Args.Count; ++i)103        ///     {104        ///         System.Console.WriteLine($"{i}: {e.Message.Args[i]}");105        ///     }106        /// }107        /// ]]>108        /// </code>109        /// </example>110        public event EventHandler<ConsoleEventArgs> Console;111        /// <summary>112        /// Raised when a frame is attached.113        /// </summary>114        public event EventHandler<FrameEventArgs> FrameAttached;115        /// <summary>116        /// Raised when a frame is detached.117        /// </summary>118        public event EventHandler<FrameEventArgs> FrameDetached;119        /// <summary>120        /// Raised when a frame is navigated to a new url.121        /// </summary>122        public event EventHandler<FrameEventArgs> FrameNavigated;123        /// <summary>124        /// Raised when a <see cref="Response"/> is received.125        /// </summary>126        public event EventHandler<ResponseCreatedEventArgs> Response;127        /// <summary>128        /// Raised when a page issues a request. The <see cref="Request"/> object is read-only.129        /// In order to intercept and mutate requests, see <see cref="SetRequestInterceptionAsync(bool)"/>130        /// </summary>131        public event EventHandler<RequestEventArgs> Request;132        /// <summary>133        /// Raised when a request finishes successfully.134        /// </summary>135        public event EventHandler<RequestEventArgs> RequestFinished;136        /// <summary>137        /// Raised when a request fails, for example by timing out.138        /// </summary>139        public event EventHandler<RequestEventArgs> RequestFailed;140        /// <summary>141        /// Raised when an uncaught exception happens within the page.142        /// </summary>143        public event EventHandler<PageErrorEventArgs> PageError;144        /// <summary>145        /// This setting will change the default maximum navigation time of 30 seconds for the following methods:146        /// - <see cref="GoToAsync(string, NavigationOptions)"/>147        /// - <see cref="GoBackAsync(NavigationOptions)"/>148        /// - <see cref="GoForwardAsync(NavigationOptions)"/>149        /// - <see cref="ReloadAsync(NavigationOptions)"/>150        /// - <see cref="WaitForNavigationAsync(NavigationOptions)"/>151        /// </summary>152        public int DefaultNavigationTimeout { get; set; } = 30000;153        /// <summary>154        /// Gets page's main frame155        /// </summary>156        /// <remarks>157        /// Page is guaranteed to have a main frame which persists during navigations.158        /// </remarks>159        public Frame MainFrame => _frameManager.MainFrame;160        /// <summary>161        /// Gets all frames attached to the page.162        /// </summary>163        /// <value>An array of all frames attached to the page.</value>164        public Frame[] Frames => _frameManager.Frames.Values.ToArray();165        /// <summary>166        /// Shortcut for <c>page.MainFrame.Url</c>167        /// </summary>168        public string Url => MainFrame.Url;169        /// <summary>170        /// Gets that target this page was created from.171        /// </summary>172        public Target Target { get; }173        /// <summary>174        /// Gets this page's keyboard175        /// </summary>176        public Keyboard Keyboard { get; }177        /// <summary>178        /// Gets this page's touchscreen179        /// </summary>180        public Touchscreen Touchscreen { get; }181        /// <summary>182        /// Gets this page's coverage183        /// </summary>184        public Coverage Coverage { get; }185        /// <summary>186        /// Gets this page's tracing187        /// </summary>188        public Tracing Tracing { get; }189        /// <summary>190        /// Gets this page's mouse191        /// </summary>192        public Mouse Mouse { get; }193        /// <summary>194        /// Gets this page's viewport195        /// </summary>196        public ViewPortOptions Viewport { get; private set; }197        /// <summary>198        /// List of suported metrics provided by the <see cref="Metrics"/> event.199        /// </summary>200        public static readonly IEnumerable<string> SupportedMetrics = new List<string>201        {202            "Timestamp",203            "Documents",204            "Frames",205            "JSEventListeners",206            "Nodes",207            "LayoutCount",208            "RecalcStyleCount",209            "LayoutDuration",210            "RecalcStyleDuration",211            "ScriptDuration",212            "TaskDuration",213            "JSHeapUsedSize",214            "JSHeapTotalSize"215        };216        #endregion217        #region Public Methods218        /// <summary>219        /// Returns metrics220        /// </summary>221        /// <returns>Task which resolves into a list of metrics</returns>222        /// <remarks>223        /// All timestamps are in monotonic time: monotonically increasing time in seconds since an arbitrary point in the past.224        /// </remarks>225        public async Task<Dictionary<string, decimal>> MetricsAsync()226        {227            var response = await Client.SendAsync<PerformanceGetMetricsResponse>("Performance.getMetrics");228            return BuildMetricsObject(response.Metrics);229        }230        /// <summary>231        /// Fetches an element with <paramref name="selector"/>, scrolls it into view if needed, and then uses <see cref="Touchscreen"/> to tap in the center of the element.232        /// </summary>233        /// <param name="selector">A selector to search for element to tap. If there are multiple elements satisfying the selector, the first will be clicked.</param>234        /// <exception cref="SelectorException">If there's no element matching <paramref name="selector"/></exception>235        /// <returns>Task which resolves when the element matching <paramref name="selector"/> is successfully tapped</returns>236        public async Task TapAsync(string selector)237        {238            var handle = await QuerySelectorAsync(selector);239            if (handle == null)240            {241                throw new SelectorException($"No node found for selector: {selector}", selector);242            }243            await handle.TapAsync();244            await handle.DisposeAsync();245        }246        /// <summary>247        /// The method runs <c>document.querySelector</c> within the page. If no element matches the selector, the return value resolve to <c>null</c>.248        /// </summary>249        /// <param name="selector">A selector to query page for</param>250        /// <returns>Task which resolves to <see cref="ElementHandle"/> pointing to the frame element</returns>251        /// <remarks>252        /// Shortcut for <c>page.MainFrame.QuerySelectorAsync(selector)</c>253        /// </remarks>254        /// <seealso cref="Frame.QuerySelectorAsync(string)"/>255        public Task<ElementHandle> QuerySelectorAsync(string selector)256            => MainFrame.QuerySelectorAsync(selector);257        /// <summary>258        /// Runs <c>document.querySelectorAll</c> within the page. If no elements match the selector, the return value resolve to <see cref="Array.Empty{T}"/>.259        /// </summary>260        /// <param name="selector">A selector to query page for</param>261        /// <returns>Task which resolves to ElementHandles pointing to the frame elements</returns>262        /// <seealso cref="Frame.QuerySelectorAllAsync(string)"/>263        public Task<ElementHandle[]> QuerySelectorAllAsync(string selector)264            => MainFrame.QuerySelectorAllAsync(selector);265        /// <summary>266        /// A utility function to be used with <see cref="Extensions.EvaluateFunctionAsync{T}(Task{JSHandle}, string, object[])"/>267        /// </summary>268        /// <param name="selector">A selector to query page for</param>269        /// <returns>Task which resolves to a <see cref="JSHandle"/> of <c>document.querySelectorAll</c> result</returns>270        public Task<JSHandle> QuerySelectorAllHandleAsync(string selector)271            => EvaluateFunctionHandleAsync("selector => Array.from(document.querySelectorAll(selector))", selector);272        /// <summary>273        /// Evaluates the XPath expression274        /// </summary>275        /// <param name="expression">Expression to evaluate <see href="https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate"/></param>276        /// <returns>Task which resolves to an array of <see cref="ElementHandle"/></returns>277        /// <remarks>278        /// Shortcut for <c>page.MainFrame.XPathAsync(expression)</c>279        /// </remarks>280        /// <seealso cref="Frame.XPathAsync(string)"/>281        public Task<ElementHandle[]> XPathAsync(string expression) => MainFrame.XPathAsync(expression);282        /// <summary>283        /// Executes a script in browser context284        /// </summary>285        /// <param name="script">Script to be evaluated in browser context</param>286        /// <remarks>287        /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.288        /// </remarks>289        /// <returns>Task which resolves to script return value</returns>290        public async Task<JSHandle> EvaluateExpressionHandleAsync(string script)291        {292            var context = await MainFrame.GetExecutionContextAsync();293            return await context.EvaluateExpressionHandleAsync(script);294        }295        /// <summary>296        /// Executes a script in browser context297        /// </summary>298        /// <param name="pageFunction">Script to be evaluated in browser context</param>299        /// <param name="args">Function arguments</param>300        /// <remarks>301        /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.302        /// <see cref="JSHandle"/> instances can be passed as arguments303        /// </remarks>304        /// <returns>Task which resolves to script return value</returns>305        public async Task<JSHandle> EvaluateFunctionHandleAsync(string pageFunction, params object[] args)306        {307            var context = await MainFrame.GetExecutionContextAsync();308            return await context.EvaluateFunctionHandleAsync(pageFunction, args);309        }310        /// <summary>311        /// Adds a function which would be invoked in one of the following scenarios:312        /// - whenever the page is navigated313        /// - whenever the child frame is attached or navigated. In this case, the function is invoked in the context of the newly attached frame314        /// </summary>315        /// <param name="pageFunction">Function to be evaluated in browser context</param>316        /// <param name="args">Arguments to pass to <c>pageFunction</c></param>317        /// <remarks>318        /// The function is invoked after the document was created but before any of its scripts were run. This is useful to amend JavaScript environment, e.g. to seed <c>Math.random</c>.319        /// </remarks>320        /// <example>321        /// An example of overriding the navigator.languages property before the page loads:322        /// <code>323        /// var overrideNavigatorLanguages = @"Object.defineProperty(navigator, 'languages', {324        ///   get: function() {325        ///     return ['en-US', 'en', 'bn'];326        ///   };327        /// });";328        /// await page.EvaluateOnNewDocumentAsync(overrideNavigatorLanguages);329        /// </code>330        /// </example>331        /// <returns>Task</returns>332        public Task EvaluateOnNewDocumentAsync(string pageFunction, params object[] args)333        {334            var source = EvaluationString(pageFunction, args);335            return Client.SendAsync("Page.addScriptToEvaluateOnNewDocument", new { source });336        }337        /// <summary>338        /// The method iterates JavaScript heap and finds all the objects with the given prototype.339        /// Shortcut for <c>page.MainFrame.GetExecutionContextAsync().QueryObjectsAsync(prototypeHandle)</c>.340        /// </summary>341        /// <returns>A task which resolves to a handle to an array of objects with this prototype.</returns>342        /// <param name="prototypeHandle">A handle to the object prototype.</param>343        public async Task<JSHandle> QueryObjectsAsync(JSHandle prototypeHandle)344        {345            var context = await MainFrame.GetExecutionContextAsync();346            return await context.QueryObjectsAsync(prototypeHandle);347        }348        /// <summary>349        /// Activating request interception enables <see cref="Request.AbortAsync(RequestAbortErrorCode)">request.AbortAsync</see>, 350        /// <see cref="Request.ContinueAsync(Payload)">request.ContinueAsync</see> and <see cref="Request.RespondAsync(ResponseData)">request.RespondAsync</see> methods.351        /// </summary>352        /// <returns>The request interception task.</returns>353        /// <param name="value">Whether to enable request interception..</param>354        public Task SetRequestInterceptionAsync(bool value)355            => _networkManager.SetRequestInterceptionAsync(value);356        /// <summary>357        /// Set offline mode for the page.358        /// </summary>359        /// <returns>Result task</returns>360        /// <param name="value">When <c>true</c> enables offline mode for the page.</param>361        public Task SetOfflineModeAsync(bool value) => _networkManager.SetOfflineModeAsync(value);362        /// <summary>363        /// Returns the page's cookies364        /// </summary>365        /// <param name="urls">Url's to return cookies for</param>366        /// <returns>Array of cookies</returns>367        /// <remarks>368        /// If no URLs are specified, this method returns cookies for the current page URL.369        /// If URLs are specified, only cookies for those URLs are returned.370        /// </remarks>371        public async Task<CookieParam[]> GetCookiesAsync(params string[] urls)372        {373            var response = await Client.SendAsync("Network.getCookies", new Dictionary<string, object>374            {375                { "urls", urls.Length > 0 ? urls : new string[] { Url } }376            });377            return response.cookies.ToObject<CookieParam[]>();378        }379        /// <summary>380        /// Clears all of the current cookies and then sets the cookies for the page381        /// </summary>382        /// <param name="cookies">Cookies to set</param>383        /// <returns>Task</returns>384        public async Task SetCookieAsync(params CookieParam[] cookies)385        {386            foreach (var cookie in cookies)387            {388                if (string.IsNullOrEmpty(cookie.Url) && Url.StartsWith("http", StringComparison.Ordinal))389                {390                    cookie.Url = Url;391                }392                if (cookie.Url == "about:blank")393                {394                    throw new PuppeteerException($"Blank page can not have cookie \"{cookie.Name}\"");395                }396            }397            await DeleteCookieAsync(cookies);398            if (cookies.Length > 0)399            {400                await Client.SendAsync("Network.setCookies", new Dictionary<string, object>401                {402                    { "cookies", cookies}403                });404            }405        }406        /// <summary>407        /// Deletes cookies from the page408        /// </summary>409        /// <param name="cookies">Cookies to delete</param>410        /// <returns>Task</returns>411        public async Task DeleteCookieAsync(params CookieParam[] cookies)412        {413            var pageURL = Url;414            foreach (var cookie in cookies)415            {416                if (string.IsNullOrEmpty(cookie.Url) && pageURL.StartsWith("http", StringComparison.Ordinal))417                {418                    cookie.Url = pageURL;419                }420                await Client.SendAsync("Network.deleteCookies", cookie);421            }422        }423        /// <summary>424        /// Adds a <c><![CDATA[<script>]]></c> tag into the page with the desired url or content425        /// </summary>426        /// <param name="options">add script tag options</param>427        /// <remarks>428        /// Shortcut for <c>page.MainFrame.AddScriptTagAsync(options)</c>429        /// </remarks>430        /// <returns>Task which resolves to the added tag when the script's onload fires or when the script content was injected into frame</returns>431        /// <seealso cref="Frame.AddScriptTag(AddTagOptions)"/>432        public Task<ElementHandle> AddScriptTagAsync(AddTagOptions options) => MainFrame.AddScriptTag(options);433        /// <summary>434        /// Adds a <c><![CDATA[<script>]]></c> tag into the page with the desired url or content435        /// </summary>436        /// <param name="url">script url</param>437        /// <remarks>438        /// Shortcut for <c>page.MainFrame.AddScriptTagAsync(new AddTagOptions { Url = url })</c>439        /// </remarks>440        /// <returns>Task which resolves to the added tag when the script's onload fires or when the script content was injected into frame</returns>441        public Task<ElementHandle> AddScriptTagAsync(string url) => AddScriptTagAsync(new AddTagOptions { Url = url });442        /// <summary>443        /// Adds a <c><![CDATA[<link rel="stylesheet">]]></c> tag into the page with the desired url or a <c><![CDATA[<link rel="stylesheet">]]></c> tag with the content444        /// </summary>445        /// <param name="options">add style tag options</param>446        /// <remarks>447        /// Shortcut for <c>page.MainFrame.AddStyleTagAsync(options)</c>448        /// </remarks>449        /// <returns>Task which resolves to the added tag when the stylesheet's onload fires or when the CSS content was injected into frame</returns>450        /// <seealso cref="Frame.AddStyleTag(AddTagOptions)"/>451        public Task<ElementHandle> AddStyleTagAsync(AddTagOptions options) => MainFrame.AddStyleTag(options);452        /// <summary>453        /// Adds a <c><![CDATA[<link rel="stylesheet">]]></c> tag into the page with the desired url or a <c><![CDATA[<link rel="stylesheet">]]></c> tag with the content454        /// </summary>455        /// <param name="url">stylesheel url</param>456        /// <remarks>457        /// Shortcut for <c>page.MainFrame.AddStyleTagAsync(new AddTagOptions { Url = url })</c>458        /// </remarks>459        /// <returns>Task which resolves to the added tag when the stylesheet's onload fires or when the CSS content was injected into frame</returns>460        public Task<ElementHandle> AddStyleTagAsync(string url) => AddStyleTagAsync(new AddTagOptions { Url = url });461        /// <summary>462        /// Adds a function called <c>name</c> on the page's <c>window</c> object.463        /// When called, the function executes <paramref name="puppeteerFunction"/> in C# and returns a <see cref="Task"/> which resolves when <paramref name="puppeteerFunction"/> completes.464        /// </summary>465        /// <param name="name">Name of the function on the window object</param>466        /// <param name="puppeteerFunction">Callback function which will be called in Puppeteer's context.</param>467        /// <remarks>468        /// If the <paramref name="puppeteerFunction"/> returns a <see cref="Task"/>, it will be awaited.469        /// Functions installed via <see cref="ExposeFunctionAsync(string, Action)"/> survive navigations470        /// </remarks>471        /// <returns>Task</returns>472        public Task ExposeFunctionAsync(string name, Action puppeteerFunction)473            => ExposeFunctionAsync(name, (Delegate)puppeteerFunction);474        /// <summary>475        /// Adds a function called <c>name</c> on the page's <c>window</c> object.476        /// When called, the function executes <paramref name="puppeteerFunction"/> in C# and returns a <see cref="Task"/> which resolves to the return value of <paramref name="puppeteerFunction"/>.477        /// </summary>478        /// <typeparam name="TResult">The result of <paramref name="puppeteerFunction"/></typeparam>479        /// <param name="name">Name of the function on the window object</param>480        /// <param name="puppeteerFunction">Callback function which will be called in Puppeteer's context.</param>481        /// <remarks>482        /// If the <paramref name="puppeteerFunction"/> returns a <see cref="Task"/>, it will be awaited.483        /// Functions installed via <see cref="ExposeFunctionAsync{TResult}(string, Func{TResult})"/> survive navigations484        /// </remarks>485        /// <returns>Task</returns>486        public Task ExposeFunctionAsync<TResult>(string name, Func<TResult> puppeteerFunction)487            => ExposeFunctionAsync(name, (Delegate)puppeteerFunction);488        /// <summary>489        /// Adds a function called <c>name</c> on the page's <c>window</c> object.490        /// When called, the function executes <paramref name="puppeteerFunction"/> in C# and returns a <see cref="Task"/> which resolves to the return value of <paramref name="puppeteerFunction"/>.491        /// </summary>492        /// <typeparam name="TResult">The result of <paramref name="puppeteerFunction"/></typeparam>493        /// <typeparam name="T">The parameter of <paramref name="puppeteerFunction"/></typeparam>494        /// <param name="name">Name of the function on the window object</param>495        /// <param name="puppeteerFunction">Callback function which will be called in Puppeteer's context.</param>496        /// <remarks>497        /// If the <paramref name="puppeteerFunction"/> returns a <see cref="Task"/>, it will be awaited.498        /// Functions installed via <see cref="ExposeFunctionAsync{T, TResult}(string, Func{T, TResult})"/> survive navigations499        /// </remarks>500        /// <returns>Task</returns>501        public Task ExposeFunctionAsync<T, TResult>(string name, Func<T, TResult> puppeteerFunction)502            => ExposeFunctionAsync(name, (Delegate)puppeteerFunction);503        /// <summary>504        /// Adds a function called <c>name</c> on the page's <c>window</c> object.505        /// When called, the function executes <paramref name="puppeteerFunction"/> in C# and returns a <see cref="Task"/> which resolves to the return value of <paramref name="puppeteerFunction"/>.506        /// </summary>507        /// <typeparam name="TResult">The result of <paramref name="puppeteerFunction"/></typeparam>508        /// <typeparam name="T1">The first parameter of <paramref name="puppeteerFunction"/></typeparam>509        /// <typeparam name="T2">The second parameter of <paramref name="puppeteerFunction"/></typeparam>510        /// <param name="name">Name of the function on the window object</param>511        /// <param name="puppeteerFunction">Callback function which will be called in Puppeteer's context.</param>512        /// <remarks>513        /// If the <paramref name="puppeteerFunction"/> returns a <see cref="Task"/>, it will be awaited.514        /// Functions installed via <see cref="ExposeFunctionAsync{T1, T2, TResult}(string, Func{T1, T2, TResult})"/> survive navigations515        /// </remarks>516        /// <returns>Task</returns>517        public Task ExposeFunctionAsync<T1, T2, TResult>(string name, Func<T1, T2, TResult> puppeteerFunction)518            => ExposeFunctionAsync(name, (Delegate)puppeteerFunction);519        /// <summary>520        /// Adds a function called <c>name</c> on the page's <c>window</c> object.521        /// When called, the function executes <paramref name="puppeteerFunction"/> in C# and returns a <see cref="Task"/> which resolves to the return value of <paramref name="puppeteerFunction"/>.522        /// </summary>523        /// <typeparam name="TResult">The result of <paramref name="puppeteerFunction"/></typeparam>524        /// <typeparam name="T1">The first parameter of <paramref name="puppeteerFunction"/></typeparam>525        /// <typeparam name="T2">The second parameter of <paramref name="puppeteerFunction"/></typeparam>526        /// <typeparam name="T3">The third parameter of <paramref name="puppeteerFunction"/></typeparam>527        /// <param name="name">Name of the function on the window object</param>528        /// <param name="puppeteerFunction">Callback function which will be called in Puppeteer's context.</param>529        /// <remarks>530        /// If the <paramref name="puppeteerFunction"/> returns a <see cref="Task"/>, it will be awaited.531        /// Functions installed via <see cref="ExposeFunctionAsync{T1, T2, T3, TResult}(string, Func{TResult})"/> survive navigations532        /// </remarks>533        /// <returns>Task</returns>534        public Task ExposeFunctionAsync<T1, T2, T3, TResult>(string name, Func<TResult> puppeteerFunction)535            => ExposeFunctionAsync(name, (Delegate)puppeteerFunction);536        /// <summary>537        /// Adds a function called <c>name</c> on the page's <c>window</c> object.538        /// When called, the function executes <paramref name="puppeteerFunction"/> in C# and returns a <see cref="Task"/> which resolves to the return value of <paramref name="puppeteerFunction"/>.539        /// </summary>540        /// <typeparam name="TResult">The result of <paramref name="puppeteerFunction"/></typeparam>541        /// <typeparam name="T1">The first parameter of <paramref name="puppeteerFunction"/></typeparam>542        /// <typeparam name="T2">The second parameter of <paramref name="puppeteerFunction"/></typeparam>543        /// <typeparam name="T3">The third parameter of <paramref name="puppeteerFunction"/></typeparam>544        /// <typeparam name="T4">The fourth parameter of <paramref name="puppeteerFunction"/></typeparam>545        /// <param name="name">Name of the function on the window object</param>546        /// <param name="puppeteerFunction">Callback function which will be called in Puppeteer's context.</param>547        /// <remarks>548        /// If the <paramref name="puppeteerFunction"/> returns a <see cref="Task"/>, it will be awaited.549        /// Functions installed via <see cref="ExposeFunctionAsync{T1, T2, T3, T4, TResult}(string, Func{T1, T2, T3, T4, TResult})"/> survive navigations550        /// </remarks>551        /// <returns>Task</returns>552        public Task ExposeFunctionAsync<T1, T2, T3, T4, TResult>(string name, Func<T1, T2, T3, T4, TResult> puppeteerFunction)553            => ExposeFunctionAsync(name, (Delegate)puppeteerFunction);554        /// <summary>555        /// Gets the full HTML contents of the page, including the doctype.556        /// </summary>557        /// <returns>Task which resolves to the HTML content.</returns>558        /// <seealso cref="Frame.GetContentAsync"/>559        public Task<string> GetContentAsync() => _frameManager.MainFrame.GetContentAsync();560        /// <summary>561        /// Sets the HTML markup to the page562        /// </summary>563        /// <param name="html">HTML markup to assign to the page.</param>564        /// <returns>Task.</returns>565        /// <seealso cref="Frame.SetContentAsync(string)"/>566        public Task SetContentAsync(string html) => _frameManager.MainFrame.SetContentAsync(html);567        /// <summary>568        /// Navigates to an url569        /// </summary>570        /// <returns>Task which resolves to the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect.</returns>571        /// <param name="url">URL to navigate page to. The url should include scheme, e.g. https://.</param>572        /// <param name="options">Navigation parameters.</param>573        public async Task<Response> GoToAsync(string url, NavigationOptions options = null)574        {575            var referrer = _networkManager.ExtraHTTPHeaders?.GetValueOrDefault("referer");576            var requests = new Dictionary<string, Request>();577            EventHandler<RequestEventArgs> createRequestEventListener = (object sender, RequestEventArgs e) =>578            {579                if (!requests.ContainsKey(e.Request.Url))580                {581                    requests.Add(e.Request.Url, e.Request);582                }583            };584            _networkManager.Request += createRequestEventListener;585            var mainFrame = _frameManager.MainFrame;586            var timeout = options?.Timeout ?? DefaultNavigationTimeout;587            var watcher = new NavigatorWatcher(_frameManager, mainFrame, timeout, options);588            var navigateTask = Navigate(Client, url, referrer);589            await Task.WhenAny(590                watcher.NavigationTask,591                navigateTask);592            AggregateException exception = null;593            if (navigateTask.IsFaulted)594            {595                exception = navigateTask.Exception;596            }597            else if (watcher.NavigationTask.IsCompleted &&598                watcher.NavigationTask.Result.IsFaulted)599            {600                exception = watcher.NavigationTask.Result?.Exception;601            }602            if (exception == null)603            {604                await Task.WhenAll(605                    watcher.NavigationTask,606                    navigateTask);607                exception = navigateTask.Exception ?? watcher.NavigationTask.Result.Exception;608            }609            watcher.Cancel();610            _networkManager.Request -= createRequestEventListener;611            if (exception != null)612            {613                throw new NavigationException(exception.InnerException.Message, exception.InnerException);614            }615            requests.TryGetValue(MainFrame.Url, out var request);616            return request?.Response;617        }618        /// <summary>619        /// generates a pdf of the page with <see cref="MediaType.Print"/> css media. To generate a pdf with <see cref="MediaType.Screen"/> media call <see cref="EmulateMediaAsync(MediaType)"/> with <see cref="MediaType.Screen"/>620        /// </summary>621        /// <param name="file">The file path to save the PDF to. paths are resolved using <see cref="Path.GetFullPath(string)"/></param>622        /// <returns></returns>623        /// <remarks>624        /// Generating a pdf is currently only supported in Chrome headless625        /// </remarks>626        public Task PdfAsync(string file) => PdfAsync(file, new PdfOptions());627        /// <summary>628        ///  generates a pdf of the page with <see cref="MediaType.Print"/> css media. To generate a pdf with <see cref="MediaType.Screen"/> media call <see cref="EmulateMediaAsync(MediaType)"/> with <see cref="MediaType.Screen"/>629        /// </summary>630        /// <param name="file">The file path to save the PDF to. paths are resolved using <see cref="Path.GetFullPath(string)"/></param>631        /// <param name="options">pdf options</param>632        /// <returns></returns>633        /// <remarks>634        /// Generating a pdf is currently only supported in Chrome headless635        /// </remarks>636        public async Task PdfAsync(string file, PdfOptions options)637        {638            var data = await PdfDataAsync(options);639            using (var fs = File.OpenWrite(file))640            {641                await fs.WriteAsync(data, 0, data.Length);642            }643        }644        /// <summary>645        /// generates a pdf of the page with <see cref="MediaType.Print"/> css media. To generate a pdf with <see cref="MediaType.Screen"/> media call <see cref="EmulateMediaAsync(MediaType)"/> with <see cref="MediaType.Screen"/>646        /// </summary>647        /// <returns>Task which resolves to a <see cref="Stream"/> containing the PDF data.</returns>648        /// <remarks>649        /// Generating a pdf is currently only supported in Chrome headless650        /// </remarks>651        public Task<Stream> PdfStreamAsync() => PdfStreamAsync(new PdfOptions());652        /// <summary>653        /// Generates a pdf of the page with <see cref="MediaType.Print"/> css media. To generate a pdf with <see cref="MediaType.Screen"/> media call <see cref="EmulateMediaAsync(MediaType)"/> with <see cref="MediaType.Screen"/>654        /// </summary>655        /// <param name="options">pdf options</param>656        /// <returns>Task which resolves to a <see cref="Stream"/> containing the PDF data.</returns>657        /// <remarks>658        /// Generating a pdf is currently only supported in Chrome headless659        /// </remarks>660        public async Task<Stream> PdfStreamAsync(PdfOptions options)661            => new MemoryStream(await PdfDataAsync(options));662        /// <summary>663        /// Generates a pdf of the page with <see cref="MediaType.Print"/> css media. To generate a pdf with <see cref="MediaType.Screen"/> media call <see cref="EmulateMediaAsync(MediaType)"/> with <see cref="MediaType.Screen"/>664        /// </summary>665        /// <returns>Task which resolves to a <see cref="byte"/>[] containing the PDF data.</returns>666        /// <remarks>667        /// Generating a pdf is currently only supported in Chrome headless668        /// </remarks>669        public Task<byte[]> PdfDataAsync() => PdfDataAsync(new PdfOptions());670        /// <summary>671        /// Generates a pdf of the page with <see cref="MediaType.Print"/> css media. To generate a pdf with <see cref="MediaType.Screen"/> media call <see cref="EmulateMediaAsync(MediaType)"/> with <see cref="MediaType.Screen"/>672        /// </summary>673        /// <param name="options">pdf options</param>674        /// <returns>Task which resolves to a <see cref="byte"/>[] containing the PDF data.</returns>675        /// <remarks>676        /// Generating a pdf is currently only supported in Chrome headless677        /// </remarks>678        public async Task<byte[]> PdfDataAsync(PdfOptions options)679        {680            var paperWidth = PaperFormat.Letter.Width;681            var paperHeight = PaperFormat.Letter.Height;682            if (options.Format != null)683            {684                paperWidth = options.Format.Width;685                paperHeight = options.Format.Height;686            }687            else688            {689                if (options.Width != null)690                {691                    paperWidth = ConvertPrintParameterToInches(options.Width);692                }693                if (options.Height != null)694                {695                    paperHeight = ConvertPrintParameterToInches(options.Height);696                }697            }698            var marginTop = ConvertPrintParameterToInches(options.MarginOptions.Top);699            var marginLeft = ConvertPrintParameterToInches(options.MarginOptions.Left);700            var marginBottom = ConvertPrintParameterToInches(options.MarginOptions.Bottom);701            var marginRight = ConvertPrintParameterToInches(options.MarginOptions.Right);702            JObject result = await Client.SendAsync("Page.printToPDF", new703            {704                landscape = options.Landscape,705                displayHeaderFooter = options.DisplayHeaderFooter,706                headerTemplate = options.HeaderTemplate,707                footerTemplate = options.FooterTemplate,708                printBackground = options.PrintBackground,709                scale = options.Scale,710                paperWidth,711                paperHeight,712                marginTop,713                marginBottom,714                marginLeft,715                marginRight,716                pageRanges = options.PageRanges717            });718            var buffer = Convert.FromBase64String(result.GetValue("data").Value<string>());719            return buffer;720        }721        /// <summary>722        /// Enables/Disables Javascript on the page723        /// </summary>724        /// <returns>Task.</returns>725        /// <param name="enabled">Whether or not to enable JavaScript on the page.</param>726        public Task SetJavaScriptEnabledAsync(bool enabled)727            => Client.SendAsync("Emulation.setScriptExecutionDisabled", new { value = !enabled });728        /// <summary>729        /// Emulates a media such as screen or print.730        /// </summary>731        /// <returns>Task.</returns>732        /// <param name="media">Media to set.</param>733        public Task EmulateMediaAsync(MediaType media)734            => Client.SendAsync("Emulation.setEmulatedMedia", new { media });735        /// <summary>736        /// Sets the viewport.737        /// In the case of multiple pages in a single browser, each page can have its own viewport size.738        /// NOTE in certain cases, setting viewport will reload the page in order to set the isMobile or hasTouch properties.739        /// </summary>740        /// <returns>The viewport task.</returns>741        /// <param name="viewport">Viewport options.</param>742        public async Task SetViewportAsync(ViewPortOptions viewport)743        {744            var needsReload = await _emulationManager.EmulateViewport(Client, viewport);745            Viewport = viewport;746            if (needsReload)747            {748                await ReloadAsync();749            }750        }751        /// <summary>752        /// Emulates given device metrics and user agent. 753        /// </summary>754        /// <remarks>755        /// This method is a shortcut for calling two methods:756        /// page.SetViewportAsync(userAgent)757        /// page.SetUserAgentAsync(viewport)758        /// </remarks>759        /// <returns>Task.</returns>760        /// <param name="options">Emulation options.</param>761        public Task EmulateAsync(DeviceDescriptor options) => Task.WhenAll(762            SetViewportAsync(options.ViewPort),763            SetUserAgentAsync(options.UserAgent)764        );765        /// <summary>766        /// Takes a screenshot of the page767        /// </summary>768        /// <returns>The screenshot task.</returns>769        /// <param name="file">The file path to save the image to. The screenshot type will be inferred from file extension. 770        /// If path is a relative path, then it is resolved relative to current working directory. If no path is provided, 771        /// the image won't be saved to the disk.</param>772        public Task ScreenshotAsync(string file) => ScreenshotAsync(file, new ScreenshotOptions());773        /// <summary>774        /// Takes a screenshot of the page775        /// </summary>776        /// <returns>The screenshot task.</returns>777        /// <param name="file">The file path to save the image to. The screenshot type will be inferred from file extension. 778        /// If path is a relative path, then it is resolved relative to current working directory. If no path is provided, 779        /// the image won't be saved to the disk.</param>780        /// <param name="options">Screenshot options.</param>781        public async Task ScreenshotAsync(string file, ScreenshotOptions options)782        {783            var fileInfo = new FileInfo(file);784            options.Type = fileInfo.Extension.Replace(".", string.Empty);785            var data = await ScreenshotDataAsync(options);786            using (var fs = new FileStream(file, FileMode.Create, FileAccess.Write))787            {788                await fs.WriteAsync(data, 0, data.Length);789            }790        }791        /// <summary>792        /// Takes a screenshot of the page793        /// </summary>794        /// <returns>Task which resolves to a <see cref="Stream"/> containing the image data.</returns>795        public Task<Stream> ScreenshotStreamAsync() => ScreenshotStreamAsync(new ScreenshotOptions());796        /// <summary>797        /// Takes a screenshot of the page798        /// </summary>799        /// <returns>Task which resolves to a <see cref="Stream"/> containing the image data.</returns>800        /// <param name="options">Screenshot options.</param>801        public async Task<Stream> ScreenshotStreamAsync(ScreenshotOptions options)802            => new MemoryStream(await ScreenshotDataAsync(options));803        /// <summary>804        /// Takes a screenshot of the page805        /// </summary>806        /// <returns>Task which resolves to a <see cref="byte"/>[] containing the image data.</returns>807        public Task<byte[]> ScreenshotDataAsync() => ScreenshotDataAsync(new ScreenshotOptions());808        /// <summary>809        /// Takes a screenshot of the page810        /// </summary>811        /// <returns>Task which resolves to a <see cref="byte"/>[] containing the image data.</returns>812        /// <param name="options">Screenshot options.</param>813        public async Task<byte[]> ScreenshotDataAsync(ScreenshotOptions options)814        {815            string screenshotType = null;816            if (!string.IsNullOrEmpty(options.Type))817            {818                if (options.Type != "png" && options.Type != "jpeg")819                {820                    throw new ArgumentException($"Unknown options.type {options.Type}");821                }822                screenshotType = options.Type;823            }824            if (string.IsNullOrEmpty(screenshotType))825            {826                screenshotType = "png";827            }828            if (options.Quality.HasValue)829            {830                if (screenshotType == "jpeg")831                {832                    throw new ArgumentException($"options.Quality is unsupported for the {screenshotType} screenshots");833                }834                if (options.Quality < 0 || options.Quality > 100)835                {836                    throw new ArgumentException($"Expected options.quality to be between 0 and 100 (inclusive), got {options.Quality}");837                }838            }839            if (options.Clip != null && options.FullPage)840            {841                throw new ArgumentException("options.clip and options.fullPage are exclusive");842            }843            return await _screenshotTaskQueue.Enqueue(() => PerformScreenshot(screenshotType, options));844        }845        /// <summary>846        /// Returns page's title847        /// </summary>848        /// <returns>page's title</returns>849        /// <see cref="Frame.GetTitleAsync"/>850        public Task<string> GetTitleAsync() => MainFrame.GetTitleAsync();851        /// <summary>852        /// Closes the page.853        /// </summary>854        /// <returns>Task.</returns>855        public Task CloseAsync()856        {857            if (!(Client?.Connection?.IsClosed ?? true))858            {859                return Client.Connection.SendAsync("Target.closeTarget", new860                {861                    targetId = Target.TargetId862                });863            }864            return Task.CompletedTask;865        }866        /// <summary>867        /// Fetches an element with <paramref name="selector"/>, scrolls it into view if needed, and then uses <see cref="Page.Mouse"/> to click in the center of the element.868        /// </summary>869        /// <param name="selector">A selector to search for element to click. If there are multiple elements satisfying the selector, the first will be clicked.</param>870        /// <param name="options">click options</param>871        /// <exception cref="SelectorException">If there's no element matching <paramref name="selector"/></exception>872        /// <returns>Task which resolves when the element matching <paramref name="selector"/> is successfully clicked</returns>873        public async Task ClickAsync(string selector, ClickOptions options = null)874        {875            var handle = await QuerySelectorAsync(selector);876            if (handle == null)877            {878                throw new SelectorException($"No node found for selector: {selector}", selector);879            }880            await handle.ClickAsync(options);881            await handle.DisposeAsync();882        }883        /// <summary>884        /// Fetches an element with <paramref name="selector"/>, scrolls it into view if needed, and then uses <see cref="Page.Mouse"/> to hover over the center of the element.885        /// </summary>886        /// <param name="selector">A selector to search for element to hover. If there are multiple elements satisfying the selector, the first will be hovered.</param>887        /// <exception cref="SelectorException">If there's no element matching <paramref name="selector"/></exception>888        /// <returns>Task which resolves when the element matching <paramref name="selector"/> is successfully hovered</returns>889        public async Task HoverAsync(string selector)890        {891            var handle = await QuerySelectorAsync(selector);892            if (handle == null)893            {894                throw new SelectorException($"No node found for selector: {selector}", selector);895            }896            await handle.HoverAsync();897            await handle.DisposeAsync();898        }899        /// <summary>900        /// Fetches an element with <paramref name="selector"/> and focuses it901        /// </summary>902        /// <param name="selector">A selector to search for element to focus. If there are multiple elements satisfying the selector, the first will be focused.</param>903        /// <exception cref="SelectorException">If there's no element matching <paramref name="selector"/></exception>904        /// <returns>Task which resolves when the element matching <paramref name="selector"/> is successfully focused</returns>905        public async Task FocusAsync(string selector)906        {907            var handle = await QuerySelectorAsync(selector);908            if (handle == null)909            {910                throw new SelectorException($"No node found for selector: {selector}", selector);911            }912            await handle.FocusAsync();913            await handle.DisposeAsync();914        }915        /// <summary>916        /// Executes a script in browser context917        /// </summary>918        /// <param name="script">Script to be evaluated in browser context</param>919        /// <remarks>920        /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.921        /// </remarks>922        /// <seealso cref="EvaluateFunctionAsync(string, object[])"/>923        /// <returns>Task which resolves to script return value</returns>924        public Task<dynamic> EvaluateExpressionAsync(string script)925            => _frameManager.MainFrame.EvaluateExpressionAsync(script);926        /// <summary>927        /// Executes a script in browser context928        /// </summary>929        /// <typeparam name="T">The type to deserialize the result to</typeparam>930        /// <param name="script">Script to be evaluated in browser context</param>931        /// <remarks>932        /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.933        /// </remarks>934        /// <seealso cref="EvaluateFunctionAsync{T}(string, object[])"/>935        /// <returns>Task which resolves to script return value</returns>936        public Task<T> EvaluateExpressionAsync<T>(string script)937            => _frameManager.MainFrame.EvaluateExpressionAsync<T>(script);938        /// <summary>939        /// Executes a function in browser context940        /// </summary>941        /// <param name="script">Script to be evaluated in browser context</param>942        /// <param name="args">Arguments to pass to script</param>943        /// <remarks>944        /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.945        /// <see cref="JSHandle"/> instances can be passed as arguments946        /// </remarks>947        /// <seealso cref="EvaluateExpressionAsync(string)"/>948        /// <returns>Task which resolves to script return value</returns>949        public Task<dynamic> EvaluateFunctionAsync(string script, params object[] args)950            => _frameManager.MainFrame.EvaluateFunctionAsync(script, args);951        /// <summary>952        /// Executes a function in browser context953        /// </summary>954        /// <typeparam name="T">The type to deserialize the result to</typeparam>955        /// <param name="script">Script to be evaluated in browser context</param>956        /// <param name="args">Arguments to pass to script</param>957        /// <remarks>958        /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.959        /// <see cref="JSHandle"/> instances can be passed as arguments960        /// </remarks>961        /// <seealso cref="EvaluateExpressionAsync{T}(string)"/>962        /// <returns>Task which resolves to script return value</returns>963        public Task<T> EvaluateFunctionAsync<T>(string script, params object[] args)964            => _frameManager.MainFrame.EvaluateFunctionAsync<T>(script, args);965        /// <summary>966        /// Sets the user agent to be used in this page967        /// </summary>968        /// <param name="userAgent">Specific user agent to use in this page</param>969        /// <returns>Task</returns>970        public Task SetUserAgentAsync(string userAgent)971            => _networkManager.SetUserAgentAsync(userAgent);972        /// <summary>973        /// Sets extra HTTP headers that will be sent with every request the page initiates974        /// </summary>975        /// <param name="headers">Additional http headers to be sent with every request</param>976        /// <returns>Task</returns>977        public Task SetExtraHttpHeadersAsync(Dictionary<string, string> headers)978            => _networkManager.SetExtraHTTPHeadersAsync(headers);979        /// <summary>980        /// Provide credentials for http authentication <see href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication"/>981        /// </summary>982        /// <param name="credentials">The credentials</param>983        /// <returns></returns>984        /// <remarks>985        /// To disable authentication, pass <c>null</c>986        /// </remarks>987        public Task AuthenticateAsync(Credentials credentials) => _networkManager.AuthenticateAsync(credentials);988        /// <summary>989        /// Reloads the page990        /// </summary>991        /// <param name="options">Navigation options</param>992        /// <returns>Task which resolves to the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect</returns>993        public async Task<Response> ReloadAsync(NavigationOptions options = null)994        {995            var navigationTask = WaitForNavigationAsync(options);996            await Task.WhenAll(997              navigationTask,998              Client.SendAsync("Page.reload")999            );1000            return navigationTask.Result;1001        }1002        /// <summary>1003        /// Triggers a change and input event once all the provided options have been selected. 1004        /// If there's no <![CDATA[<select>]]> element matching selector, the method throws an error.1005        /// </summary>1006        /// <exception cref="SelectorException">If there's no element matching <paramref name="selector"/></exception>1007        /// <param name="selector">A selector to query page for</param>1008        /// <param name="values">Values of options to select. If the <![CDATA[<select>]]> has the multiple attribute, 1009        /// all values are considered, otherwise only the first one is taken into account.</param>1010        /// <returns>Returns an array of option values that have been successfully selected.</returns>1011        /// <seealso cref="Frame.SelectAsync(string, string[])"/>1012        public Task<string[]> SelectAsync(string selector, params string[] values)1013            => MainFrame.SelectAsync(selector, values);1014        /// <summary>1015        /// Sends a <c>keydown</c>, <c>keypress</c>/<c>input</c>, and <c>keyup</c> event for each character in the text.1016        /// </summary>1017        /// <param name="selector">A selector of an element to type into. If there are multiple elements satisfying the selector, the first will be used.</param>1018        /// <param name="text">A text to type into a focused element</param>1019        /// <param name="options"></param>1020        /// <exception cref="SelectorException">If there's no element matching <paramref name="selector"/></exception>1021        /// <remarks>1022        /// To press a special key, like <c>Control</c> or <c>ArrowDown</c> use <see cref="Keyboard.PressAsync(string, PressOptions)"/>1023        /// </remarks>1024        /// <example>1025        /// <code>1026        /// page.TypeAsync("#mytextarea", "Hello"); // Types instantly1027        /// page.TypeAsync("#mytextarea", "World", new TypeOptions { Delay = 100 }); // Types slower, like a user1028        /// </code>1029        /// </example>1030        /// <returns>Task</returns>1031        public async Task TypeAsync(string selector, string text, TypeOptions options = null)1032        {1033            var handle = await QuerySelectorAsync(selector);1034            if (handle == null)1035            {1036                throw new SelectorException($"No node found for selector: {selector}", selector);1037            }1038            await handle.TypeAsync(text, options);1039            await handle.DisposeAsync();1040        }1041        /// <summary>1042        /// Waits for a timeout1043        /// </summary>1044        /// <param name="milliseconds"></param>1045        /// <returns>A task that resolves when after the timeout</returns>1046        /// <seealso cref="Frame.WaitForTimeoutAsync(int)"/>1047        public Task WaitForTimeoutAsync(int milliseconds)1048            => MainFrame.WaitForTimeoutAsync(milliseconds);1049        /// <summary>1050        /// Waits for a script to be evaluated to a truthy value1051        /// </summary>1052        /// <param name="script">Function to be evaluated in browser context</param>1053        /// <param name="options">Optional waiting parameters</param>1054        /// <param name="args">Arguments to pass to <c>script</c></param>1055        /// <returns>A task that resolves when the <c>script</c> returns a truthy value</returns>1056        /// <seealso cref="Frame.WaitForFunctionAsync(string, WaitForFunctionOptions, object[])"/>1057        public Task<JSHandle> WaitForFunctionAsync(string script, WaitForFunctionOptions options = null, params object[] args)1058            => MainFrame.WaitForFunctionAsync(script, options ?? new WaitForFunctionOptions(), args);1059        /// <summary>1060        /// Waits for a script to be evaluated to a truthy value1061        /// </summary>1062        /// <param name="script">Function to be evaluated in browser context</param>1063        /// <param name="args">Arguments to pass to <c>script</c></param>1064        /// <returns>A task that resolves when the <c>script</c> returns a truthy value</returns>1065        public Task<JSHandle> WaitForFunctionAsync(string script, params object[] args) => WaitForFunctionAsync(script, null, args);1066        /// <summary>1067        /// Waits for a selector to be added to the DOM1068        /// </summary>1069        /// <param name="selector">A selector of an element to wait for</param>1070        /// <param name="options">Optional waiting parameters</param>1071        /// <returns>A task that resolves when element specified by selector string is added to DOM</returns>1072        public Task<ElementHandle> WaitForSelectorAsync(string selector, WaitForSelectorOptions options = null)1073            => MainFrame.WaitForSelectorAsync(selector, options ?? new WaitForSelectorOptions());1074        /// <summary>1075        /// Waits for navigation1076        /// </summary>1077        /// <param name="options">navigation options</param>1078        /// <returns>Task which resolves to the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect</returns>1079        public async Task<Response> WaitForNavigationAsync(NavigationOptions options = null)1080        {1081            var mainFrame = _frameManager.MainFrame;1082            var timeout = options?.Timeout ?? DefaultNavigationTimeout;1083            var watcher = new NavigatorWatcher(_frameManager, mainFrame, timeout, options);1084            var responses = new Dictionary<string, Response>();1085            EventHandler<ResponseCreatedEventArgs> createResponseEventListener = (object sender, ResponseCreatedEventArgs e) =>1086                responses.Add(e.Response.Url, e.Response);1087            _networkManager.Response += createResponseEventListener;1088            await watcher.NavigationTask;1089            _networkManager.Response -= createResponseEventListener;1090            var exception = watcher.NavigationTask.Exception;1091            if (exception != null)1092            {1093                throw new NavigationException(exception.Message, exception);1094            }1095            return responses.GetValueOrDefault(_frameManager.MainFrame.Url);1096        }1097        /// <summary>1098        /// Navigate to the previous page in history.1099        /// </summary>1100        /// <returns>Task which which resolves to the main resource response. In case of multiple redirects, 1101        /// the navigation will resolve with the response of the last redirect. If can not go back, resolves to null.</returns>1102        /// <param name="options">Navigation parameters.</param>1103        public Task<Response> GoBackAsync(NavigationOptions options = null) => GoAsync(-1, null);1104        /// <summary>1105        /// Navigate to the next page in history.1106        /// </summary>1107        /// <returns>Task which which resolves to the main resource response. In case of multiple redirects, 1108        /// the navigation will resolve with the response of the last redirect. If can not go forward, resolves to null.</returns>1109        /// <param name="options">Navigation parameters.</param>1110        public Task<Response> GoForwardAsync(NavigationOptions options = null) => GoAsync(1, null);1111        #endregion1112        #region Private Method1113        internal static async Task<Page> CreateAsync(CDPSession client, Target target, bool ignoreHTTPSErrors, bool appMode,1114                                                   TaskQueue screenshotTaskQueue)1115        {1116            await client.SendAsync("Page.enable", null);1117            dynamic result = await client.SendAsync("Page.getFrameTree");1118            var page = new Page(client, target, new FrameTree(result.frameTree), ignoreHTTPSErrors, screenshotTaskQueue);1119            await Task.WhenAll(1120                client.SendAsync("Page.setLifecycleEventsEnabled", new Dictionary<string, object>1121                {1122                    {"enabled", true }1123                }),1124                client.SendAsync("Network.enable", null),1125                client.SendAsync("Runtime.enable", null),1126                client.SendAsync("Security.enable", null),1127                client.SendAsync("Performance.enable", null)1128            );1129            if (ignoreHTTPSErrors)1130            {1131                await client.SendAsync("Security.setOverrideCertificateErrors", new Dictionary<string, object>1132                {...

Full Screen

Full Screen

FrameManager.cs

Source:FrameManager.cs Github

copy

Full Screen

...13        private Dictionary<int, ExecutionContext> _contextIdToContext;14        private bool _ensureNewDocumentNavigation;15        private readonly ILogger _logger;16        private readonly NetworkManager _networkManager;17        internal FrameManager(CDPSession client, FrameTree frameTree, Page page, NetworkManager networkManager)18        {19            _client = client;20            Page = page;21            Frames = new Dictionary<string, Frame>();22            _contextIdToContext = new Dictionary<int, ExecutionContext>();23            _logger = _client.Connection.LoggerFactory.CreateLogger<FrameManager>();24            _networkManager = networkManager;25            _client.MessageReceived += _client_MessageReceived;26            HandleFrameTree(frameTree);27        }28        #region Properties29        internal event EventHandler<FrameEventArgs> FrameAttached;30        internal event EventHandler<FrameEventArgs> FrameDetached;31        internal event EventHandler<FrameEventArgs> FrameNavigated;32        internal event EventHandler<FrameEventArgs> FrameNavigatedWithinDocument;33        internal event EventHandler<FrameEventArgs> LifecycleEvent;34        internal Dictionary<string, Frame> Frames { get; set; }35        internal Frame MainFrame { get; set; }36        internal Page Page { get; }37        internal int DefaultNavigationTimeout { get; set; } = 30000;38        #endregion39        #region Public Methods40        internal ExecutionContext ExecutionContextById(int contextId)41        {42            _contextIdToContext.TryGetValue(contextId, out var context);43            if (context == null)44            {45                _logger.LogError("INTERNAL ERROR: missing context with id = {ContextId}", contextId);46            }47            return context;48        }49        public async Task<Response> NavigateFrameAsync(Frame frame, string url, NavigationOptions options)50        {51            var referrer = string.IsNullOrEmpty(options.Referer)52               ? _networkManager.ExtraHTTPHeaders?.GetValueOrDefault(MessageKeys.Referer)53               : options.Referer;54            var requests = new Dictionary<string, Request>();55            var timeout = options?.Timeout ?? DefaultNavigationTimeout;56            var watcher = new NavigatorWatcher(_client, this, frame, _networkManager, timeout, options);57            var navigateTask = NavigateAsync(_client, url, referrer, frame.Id);58            await Task.WhenAny(59                watcher.TimeoutOrTerminationTask,60                navigateTask).ConfigureAwait(false);61            AggregateException exception = null;62            if (navigateTask.IsFaulted)63            {64                exception = navigateTask.Exception;65            }66            else67            {68                await Task.WhenAny(69                    watcher.TimeoutOrTerminationTask,70                    _ensureNewDocumentNavigation ? watcher.NewDocumentNavigationTask : watcher.SameDocumentNavigationTask71                ).ConfigureAwait(false);72                if (watcher.TimeoutOrTerminationTask.IsCompleted && watcher.TimeoutOrTerminationTask.Result.IsFaulted)73                {74                    exception = watcher.TimeoutOrTerminationTask.Result.Exception;75                }76            }77            if (exception != null)78            {79                throw new NavigationException(exception.InnerException.Message, exception.InnerException);80            }81            return watcher.NavigationResponse;82        }83        private async Task NavigateAsync(CDPSession client, string url, string referrer, string frameId)84        {85            var response = await client.SendAsync<PageNavigateResponse>("Page.navigate", new86            {87                url,88                referrer = referrer ?? string.Empty,89                frameId90            }).ConfigureAwait(false);91            _ensureNewDocumentNavigation = !string.IsNullOrEmpty(response.LoaderId);92            if (!string.IsNullOrEmpty(response.ErrorText))93            {94                throw new NavigationException(response.ErrorText, url);95            }96        }97        public async Task<Response> WaitForFrameNavigationAsync(Frame frame, NavigationOptions options = null)98        {99            var timeout = options?.Timeout ?? DefaultNavigationTimeout;100            var watcher = new NavigatorWatcher(_client, this, frame, _networkManager, timeout, options);101            var raceTask = await Task.WhenAny(102                watcher.NewDocumentNavigationTask,103                watcher.SameDocumentNavigationTask,104                watcher.TimeoutOrTerminationTask105            ).ConfigureAwait(false);106            var exception = raceTask.Exception;107            if (exception == null &&108                watcher.TimeoutOrTerminationTask.IsCompleted &&109                watcher.TimeoutOrTerminationTask.Result.IsFaulted)110            {111                exception = watcher.TimeoutOrTerminationTask.Result.Exception;112            }113            if (exception != null)114            {115                throw new NavigationException(exception.Message, exception);116            }117            return watcher.NavigationResponse;118        }119        #endregion120        #region Private Methods121        private void _client_MessageReceived(object sender, MessageEventArgs e)122        {123            switch (e.MessageID)124            {125                case "Page.frameAttached":126                    OnFrameAttached(127                        e.MessageData.SelectToken(MessageKeys.FrameId).ToObject<string>(),128                        e.MessageData.SelectToken("parentFrameId").ToObject<string>());129                    break;130                case "Page.frameNavigated":131                    OnFrameNavigated(e.MessageData.SelectToken(MessageKeys.Frame).ToObject<FramePayload>());132                    break;133                case "Page.navigatedWithinDocument":134                    OnFrameNavigatedWithinDocument(e.MessageData.ToObject<NavigatedWithinDocumentResponse>());135                    break;136                case "Page.frameDetached":137                    OnFrameDetached(e.MessageData.ToObject<BasicFrameResponse>());138                    break;139                case "Page.frameStoppedLoading":140                    OnFrameStoppedLoading(e.MessageData.ToObject<BasicFrameResponse>());141                    break;142                case "Runtime.executionContextCreated":143                    OnExecutionContextCreated(e.MessageData.SelectToken(MessageKeys.Context).ToObject<ContextPayload>());144                    break;145                case "Runtime.executionContextDestroyed":146                    OnExecutionContextDestroyed(e.MessageData.SelectToken(MessageKeys.ExecutionContextId).ToObject<int>());147                    break;148                case "Runtime.executionContextsCleared":149                    OnExecutionContextsCleared();150                    break;151                case "Page.lifecycleEvent":152                    OnLifeCycleEvent(e.MessageData.ToObject<LifecycleEventResponse>());153                    break;154                default:155                    break;156            }157        }158        private void OnFrameStoppedLoading(BasicFrameResponse e)159        {160            if (Frames.TryGetValue(e.FrameId, out var frame))161            {162                frame.OnLoadingStopped();163                LifecycleEvent?.Invoke(this, new FrameEventArgs(frame));164            }165        }166        private void OnLifeCycleEvent(LifecycleEventResponse e)167        {168            if (Frames.TryGetValue(e.FrameId, out var frame))169            {170                frame.OnLifecycleEvent(e.LoaderId, e.Name);171                LifecycleEvent?.Invoke(this, new FrameEventArgs(frame));172            }173        }174        private void OnExecutionContextsCleared()175        {176            foreach (var context in _contextIdToContext.Values)177            {178                RemoveContext(context);179            }180            _contextIdToContext.Clear();181        }182        private void OnExecutionContextDestroyed(int executionContextId)183        {184            _contextIdToContext.TryGetValue(executionContextId, out var context);185            if (context != null)186            {187                _contextIdToContext.Remove(executionContextId);188                RemoveContext(context);189            }190        }191        private void OnExecutionContextCreated(ContextPayload contextPayload)192        {193            var frameId = contextPayload.AuxData.IsDefault ? contextPayload.AuxData.FrameId : null;194            var frame = !string.IsNullOrEmpty(frameId) ? Frames[frameId] : null;195            var context = new ExecutionContext(196                _client,197                contextPayload,198                frame);199            _contextIdToContext[contextPayload.Id] = context;200            if (frame != null)201            {202                frame.SetDefaultContext(context);203            }204        }205        private void OnFrameDetached(BasicFrameResponse e)206        {207            if (Frames.TryGetValue(e.FrameId, out var frame))208            {209                RemoveFramesRecursively(frame);210            }211        }212        private void OnFrameNavigated(FramePayload framePayload)213        {214            var isMainFrame = string.IsNullOrEmpty(framePayload.ParentId);215            var frame = isMainFrame ? MainFrame : Frames[framePayload.Id];216            Contract.Assert(isMainFrame || frame != null, "We either navigate top level or have old version of the navigated frame");217            // Detach all child frames first.218            if (frame != null)219            {220                while (frame.ChildFrames.Count > 0)221                {222                    RemoveFramesRecursively(frame.ChildFrames[0]);223                }224            }225            // Update or create main frame.226            if (isMainFrame)227            {228                if (frame != null)229                {230                    // Update frame id to retain frame identity on cross-process navigation.231                    if (frame.Id != null)232                    {233                        Frames.Remove(frame.Id);234                    }235                    frame.Id = framePayload.Id;236                }237                else238                {239                    // Initial main frame navigation.240                    frame = new Frame(this, _client, null, framePayload.Id);241                }242                Frames[framePayload.Id] = frame;243                MainFrame = frame;244            }245            // Update frame payload.246            frame.Navigated(framePayload);247            FrameNavigated?.Invoke(this, new FrameEventArgs(frame));248        }249        private void OnFrameNavigatedWithinDocument(NavigatedWithinDocumentResponse e)250        {251            if (Frames.TryGetValue(e.FrameId, out var frame))252            {253                frame.NavigatedWithinDocument(e.Url);254                var eventArgs = new FrameEventArgs(frame);255                FrameNavigatedWithinDocument?.Invoke(this, eventArgs);256                FrameNavigated?.Invoke(this, eventArgs);257            }258        }259        private void RemoveContext(ExecutionContext context)260        {261            if (context.Frame != null)262            {263                context.Frame.SetDefaultContext(null);264            }265        }266        private void RemoveFramesRecursively(Frame frame)267        {268            while (frame.ChildFrames.Count > 0)269            {270                RemoveFramesRecursively(frame.ChildFrames[0]);271            }272            frame.Detach();273            Frames.Remove(frame.Id);274            FrameDetached?.Invoke(this, new FrameEventArgs(frame));275        }276        private void OnFrameAttached(string frameId, string parentFrameId)277        {278            if (!Frames.ContainsKey(frameId) && Frames.ContainsKey(parentFrameId))279            {280                var parentFrame = Frames[parentFrameId];281                var frame = new Frame(this, _client, parentFrame, frameId);282                Frames[frame.Id] = frame;283                FrameAttached?.Invoke(this, new FrameEventArgs(frame));284            }285        }286        private void HandleFrameTree(FrameTree frameTree)287        {288            if (!string.IsNullOrEmpty(frameTree.Frame.ParentId))289            {290                OnFrameAttached(frameTree.Frame.Id, frameTree.Frame.ParentId);291            }292            OnFrameNavigated(frameTree.Frame);293            if (frameTree.Childs != null)294            {295                foreach (var child in frameTree.Childs)296                {297                    HandleFrameTree(child);298                }299            }300        }301        #endregion302    }303}...

Full Screen

Full Screen

MessageKeys.cs

Source:MessageKeys.cs Github

copy

Full Screen

...37        public const string ParentId = "parentId";38        public const string Url = "url";39        public const string Urls = "urls";40        public const string ChildFrames = "childFrames";41        public const string FrameTree = "frameTree";42        public const string ContentSize = "contentSize";43        public const string Width = "width";44        public const string Height = "height";45        public const string FrameId = "frameId";46        public const string ExecutionContextId = "executionContextId";47        public const string Args = "args";48        public const string EventId = "eventId";49        public const string BrowserContextId = "browserContextId";50        public const string RequestId = "requestId";51        public const string InterceptionId = "interceptionId";52        public const string Headers = "headers";53        public const string TargetInfo = "targetInfo";54        public const string PostData = "postData";55        public const string Modifiers = "modifiers";...

Full Screen

Full Screen

FrameTree.cs

Source:FrameTree.cs Github

copy

Full Screen

...3using PuppeteerSharp.Helpers;4using PuppeteerSharp.Messaging;5namespace PuppeteerSharp6{7    internal class FrameTree8    {9        internal FrameTree()10        {11            Childs = new List<FrameTree>();12        }13        internal FrameTree(JToken frameTree)14        {15            var frame = frameTree[MessageKeys.Frame];16            Frame = new FramePayload17            {18                Id = frame[MessageKeys.Id].AsString(),19                ParentId = frame[MessageKeys.ParentId].AsString(),20                Name = frame[MessageKeys.Name].AsString(),21                Url = frame[MessageKeys.Url].AsString()22            };23            Childs = new List<FrameTree>();24            LoadChilds(this, frameTree);25        }26        #region Properties27        internal FramePayload Frame { get; set; }28        internal List<FrameTree> Childs { get; set; }29        #endregion30        #region Private Functions31        private void LoadChilds(FrameTree frame, JToken frameTree)32        {33            var childFrames = frameTree[MessageKeys.ChildFrames];34            if (childFrames != null)35            {36                foreach (var item in childFrames)37                {38                    var childFrame = item[MessageKeys.Frame];39                    var newFrame = new FrameTree40                    {41                        Frame = new FramePayload42                        {43                            Id = childFrame[MessageKeys.Id].AsString(),44                            ParentId = childFrame[MessageKeys.ParentId].AsString(),45                            Url = childFrame[MessageKeys.Url].AsString()46                        }47                    };48                    if ((item as JObject)[MessageKeys.ChildFrames] != null)49                    {50                        LoadChilds(newFrame, item);51                    }52                    frame.Childs.Add(newFrame);53                }...

Full Screen

Full Screen

PageGetFrameTreeResponse.cs

Source:PageGetFrameTreeResponse.cs Github

copy

Full Screen

1using System.Collections.Generic;2using Newtonsoft.Json.Linq;3namespace PuppeteerSharp.Messaging4{5    internal class PageGetFrameTreeResponse6    {7        public PageGetFrameTreeItem FrameTree { get; set; }8    }9}...

Full Screen

Full Screen

FrameTree

Using AI Code Generation

copy

Full Screen

1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4{5    {6        public static async Task Main(string[] args)7        {8            await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);9            using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = false }))10            using (var page = await browser.NewPageAsync())11            {12                var frame = await page.QuerySelectorAsync("iframe");13                var frameTree = await page.GetFrameTreeAsync();14                var frameId = frameTree.Frame.Id;15                var childFrame = page.Frames[1];16                var childFrameId = childFrame.Id;17                var childFrameTree = await childFrame.GetFrameTreeAsync();18                Console.WriteLine("Frame tree: {0}", frameTree);19            }20        }21    }22}23   at PuppeteerSharp.FrameTree.get_Frame()24   at PuppeteerSharpTest.FrameTree.Main(String[] args) in C:\Users\user\source\repos\PuppeteerSharpTest\PuppeteerSharpTest\FrameTree.cs:line 25

Full Screen

Full Screen

FrameTree

Using AI Code Generation

copy

Full Screen

1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4{5    {6        static void Main(string[] args)7        {8            MainAsync(args).GetAwaiter().GetResult();9        }10        static async Task MainAsync(string[] args)11        {12            var browser = await Puppeteer.LaunchAsync(new LaunchOptions13            {14                Args = new string[] { "--start-maximized" }15            });16            var page = await browser.NewPageAsync();17            var frameTree = await page.MainFrame.GetFrameTreeAsync();18            Console.WriteLine(frameTree.ToString());19            await browser.CloseAsync();20        }21    }22}23FrameTree {24    FrameTree {

Full Screen

Full Screen

FrameTree

Using AI Code Generation

copy

Full Screen

1var frameTree = await page.GetFrameTreeAsync();2var frame = frameTree.ChildFrames[0];3await frame.ClickAsync("button");4await frame.ClickAsync("button");5await frame.ClickAsync("button");6await frame.ClickAsync("button");7await frame.ClickAsync("button");8var frameTree = await page.GetFrameTreeAsync();9var frame = frameTree.ChildFrames[0];10var frameTree2 = await frame.GetFrameTreeAsync();11var frame2 = frameTree2.ChildFrames[0];12await frame2.ClickAsync("button");13await frame2.ClickAsync("button");14await frame2.ClickAsync("button");15await frame2.ClickAsync("button");16await frame2.ClickAsync("button");17var frameTree = await page.GetFrameTreeAsync();18var frame = frameTree.ChildFrames[0];19var frameTree2 = await frame.GetFrameTreeAsync();20var frame2 = frameTree2.ChildFrames[0];21var frameTree3 = await frame2.GetFrameTreeAsync();22var frame3 = frameTree3.ChildFrames[0];23await frame3.ClickAsync("button");24await frame3.ClickAsync("button");25await frame3.ClickAsync("button");26await frame3.ClickAsync("button");27await frame3.ClickAsync("button");28var frameTree = await page.GetFrameTreeAsync();29var frame = frameTree.ChildFrames[0];30var frameTree2 = await frame.GetFrameTreeAsync();31var frame2 = frameTree2.ChildFrames[0];32var frameTree3 = await frame2.GetFrameTreeAsync();33var frame3 = frameTree3.ChildFrames[0];34var frameTree4 = await frame3.GetFrameTreeAsync();35var frame4 = frameTree4.ChildFrames[0];36await frame4.ClickAsync("button");37await frame4.ClickAsync("button");38await frame4.ClickAsync("button");39await frame4.ClickAsync("button");40await frame4.ClickAsync("button");41var frameTree = await page.GetFrameTreeAsync();42var frame = frameTree.ChildFrames[0];

Full Screen

Full Screen

FrameTree

Using AI Code Generation

copy

Full Screen

1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4{5    {6        static async Task Main(string[] args)7        {8            var browser = await Puppeteer.LaunchAsync(new LaunchOptions9            {10            });11            var page = await browser.NewPageAsync();12            var frameTree = page.MainFrame.GetFrameTree();13            Console.WriteLine(frameTree);14            Console.ReadLine();15            await browser.CloseAsync();16        }17    }18}19FrameTree {20  Frame = Frame {21  }22    FrameTree {23      Frame = Frame {24        ParentFrame = Frame {25        }26      }27    }28}

Full Screen

Full Screen

FrameTree

Using AI Code Generation

copy

Full Screen

1using System;2using System.IO;3using System.Threading.Tasks;4using PuppeteerSharp;5{6    {7        static async Task Main(string[] args)8        {9            string fileName = "FrameTree.txt";10            await GetFrameTree(url, fileName);11        }12        static async Task GetFrameTree(string url, string fileName)13        {14            await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);15            using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true }))16            using (var page = await browser.NewPageAsync())17            {18                await page.GoToAsync(url);19                FrameTree frameTree = page.MainFrame.GetFrameTree();20                using (StreamWriter sw = new StreamWriter(fileName))21                {22                    await sw.WriteLineAsync(frameTree.ToString());23                }24            }25        }26    }27}

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Puppeteer-sharp automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Most used methods in FrameTree

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful