Best Puppeteer-sharp code snippet using PuppeteerSharp.WaitTask.Dispose
Page.cs
Source:Page.cs
...419 {420 throw new SelectorException($"No node found for selector: {selector}", selector);421 }422 await handle.TapAsync().ConfigureAwait(false);423 await handle.DisposeAsync().ConfigureAwait(false);424 }425 /// <summary>426 /// The method runs <c>document.querySelector</c> within the page. If no element matches the selector, the return value resolve to <c>null</c>.427 /// </summary>428 /// <param name="selector">A selector to query page for</param>429 /// <returns>Task which resolves to <see cref="ElementHandle"/> pointing to the frame element</returns>430 /// <remarks>431 /// Shortcut for <c>page.MainFrame.QuerySelectorAsync(selector)</c>432 /// </remarks>433 /// <seealso cref="Frame.QuerySelectorAsync(string)"/>434 public Task<ElementHandle> QuerySelectorAsync(string selector)435 => MainFrame.QuerySelectorAsync(selector);436 /// <summary>437 /// Runs <c>document.querySelectorAll</c> within the page. If no elements match the selector, the return value resolve to <see cref="Array.Empty{T}"/>.438 /// </summary>439 /// <param name="selector">A selector to query page for</param>440 /// <returns>Task which resolves to ElementHandles pointing to the frame elements</returns>441 /// <seealso cref="Frame.QuerySelectorAllAsync(string)"/>442 public Task<ElementHandle[]> QuerySelectorAllAsync(string selector)443 => MainFrame.QuerySelectorAllAsync(selector);444 /// <summary>445 /// A utility function to be used with <see cref="PuppeteerHandleExtensions.EvaluateFunctionAsync{T}(Task{JSHandle}, string, object[])"/>446 /// </summary>447 /// <param name="selector">A selector to query page for</param>448 /// <returns>Task which resolves to a <see cref="JSHandle"/> of <c>document.querySelectorAll</c> result</returns>449 public Task<JSHandle> QuerySelectorAllHandleAsync(string selector)450 => EvaluateFunctionHandleAsync("selector => Array.from(document.querySelectorAll(selector))", selector);451 /// <summary>452 /// Evaluates the XPath expression453 /// </summary>454 /// <param name="expression">Expression to evaluate <see href="https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate"/></param>455 /// <returns>Task which resolves to an array of <see cref="ElementHandle"/></returns>456 /// <remarks>457 /// Shortcut for <c>page.MainFrame.XPathAsync(expression)</c>458 /// </remarks>459 /// <seealso cref="Frame.XPathAsync(string)"/>460 public Task<ElementHandle[]> XPathAsync(string expression) => MainFrame.XPathAsync(expression);461 /// <summary>462 /// Executes a script in browser context463 /// </summary>464 /// <param name="script">Script to be evaluated in browser context</param>465 /// <remarks>466 /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.467 /// </remarks>468 /// <returns>Task which resolves to script return value</returns>469 public async Task<JSHandle> EvaluateExpressionHandleAsync(string script)470 {471 var context = await MainFrame.GetExecutionContextAsync().ConfigureAwait(false);472 return await context.EvaluateExpressionHandleAsync(script).ConfigureAwait(false);473 }474 /// <summary>475 /// Executes a script in browser context476 /// </summary>477 /// <param name="pageFunction">Script to be evaluated in browser context</param>478 /// <param name="args">Function arguments</param>479 /// <remarks>480 /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.481 /// <see cref="JSHandle"/> instances can be passed as arguments482 /// </remarks>483 /// <returns>Task which resolves to script return value</returns>484 public async Task<JSHandle> EvaluateFunctionHandleAsync(string pageFunction, params object[] args)485 {486 var context = await MainFrame.GetExecutionContextAsync().ConfigureAwait(false);487 return await context.EvaluateFunctionHandleAsync(pageFunction, args).ConfigureAwait(false);488 }489 /// <summary>490 /// Adds a function which would be invoked in one of the following scenarios:491 /// - whenever the page is navigated492 /// - whenever the child frame is attached or navigated. In this case, the function is invoked in the context of the newly attached frame493 /// </summary>494 /// <param name="pageFunction">Function to be evaluated in browser context</param>495 /// <param name="args">Arguments to pass to <c>pageFunction</c></param>496 /// <remarks>497 /// 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>.498 /// </remarks>499 /// <example>500 /// An example of overriding the navigator.languages property before the page loads:501 /// <code>502 /// await page.EvaluateOnNewDocumentAsync("() => window.__example = true");503 /// </code>504 /// </example>505 /// <returns>Task</returns>506 [Obsolete("User EvaluateFunctionOnNewDocumentAsync instead")]507 public Task EvaluateOnNewDocumentAsync(string pageFunction, params object[] args)508 => EvaluateFunctionOnNewDocumentAsync(pageFunction, args);509 /// <summary>510 /// Adds a function which would be invoked in one of the following scenarios:511 /// - whenever the page is navigated512 /// - whenever the child frame is attached or navigated. In this case, the function is invoked in the context of the newly attached frame513 /// </summary>514 /// <param name="pageFunction">Function to be evaluated in browser context</param>515 /// <param name="args">Arguments to pass to <c>pageFunction</c></param>516 /// <remarks>517 /// 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>.518 /// </remarks>519 /// <example>520 /// An example of overriding the navigator.languages property before the page loads:521 /// <code>522 /// await page.EvaluateFunctionOnNewDocumentAsync("() => window.__example = true");523 /// </code>524 /// </example>525 /// <returns>Task</returns>526 public Task EvaluateFunctionOnNewDocumentAsync(string pageFunction, params object[] args)527 {528 var source = EvaluationString(pageFunction, args);529 return Client.SendAsync("Page.addScriptToEvaluateOnNewDocument", new PageAddScriptToEvaluateOnNewDocumentRequest530 {531 Source = source532 });533 }534 /// <summary>535 /// Adds a function which would be invoked in one of the following scenarios:536 /// - whenever the page is navigated537 /// - whenever the child frame is attached or navigated. In this case, the function is invoked in the context of the newly attached frame538 /// </summary>539 /// <param name="expression">Javascript expression to be evaluated in browser context</param>540 /// <remarks>541 /// 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>.542 /// </remarks>543 /// <example>544 /// An example of overriding the navigator.languages property before the page loads:545 /// <code>546 /// await page.EvaluateExpressionOnNewDocumentAsync("window.__example = true;");547 /// </code>548 /// </example>549 /// <returns>Task</returns>550 public Task EvaluateExpressionOnNewDocumentAsync(string expression)551 => Client.SendAsync("Page.addScriptToEvaluateOnNewDocument", new PageAddScriptToEvaluateOnNewDocumentRequest552 {553 Source = expression554 });555 /// <summary>556 /// The method iterates JavaScript heap and finds all the objects with the given prototype.557 /// Shortcut for <c>page.MainFrame.GetExecutionContextAsync().QueryObjectsAsync(prototypeHandle)</c>.558 /// </summary>559 /// <returns>A task which resolves to a handle to an array of objects with this prototype.</returns>560 /// <param name="prototypeHandle">A handle to the object prototype.</param>561 public async Task<JSHandle> QueryObjectsAsync(JSHandle prototypeHandle)562 {563 var context = await MainFrame.GetExecutionContextAsync().ConfigureAwait(false);564 return await context.QueryObjectsAsync(prototypeHandle).ConfigureAwait(false);565 }566 /// <summary>567 /// Activating request interception enables <see cref="PuppeteerSharp.Request.AbortAsync(RequestAbortErrorCode)">request.AbortAsync</see>,568 /// <see cref="PuppeteerSharp.Request.ContinueAsync(Payload)">request.ContinueAsync</see> and <see cref="PuppeteerSharp.Request.RespondAsync(ResponseData)">request.RespondAsync</see> methods.569 /// </summary>570 /// <returns>The request interception task.</returns>571 /// <param name="value">Whether to enable request interception..</param>572 public Task SetRequestInterceptionAsync(bool value)573 => FrameManager.NetworkManager.SetRequestInterceptionAsync(value);574 /// <summary>575 /// Set offline mode for the page.576 /// </summary>577 /// <returns>Result task</returns>578 /// <param name="value">When <c>true</c> enables offline mode for the page.</param>579 public Task SetOfflineModeAsync(bool value) => FrameManager.NetworkManager.SetOfflineModeAsync(value);580 /// <summary>581 /// Emulates network conditions582 /// </summary>583 /// <param name="networkConditions">Passing <c>null</c> disables network condition emulation.</param>584 /// <returns>Result task</returns>585 /// <remarks>586 /// **NOTE** This does not affect WebSockets and WebRTC PeerConnections (see https://crbug.com/563644)587 /// </remarks>588 public Task EmulateNetworkConditionsAsync(NetworkConditions networkConditions) => FrameManager.NetworkManager.EmulateNetworkConditionsAsync(networkConditions);589 /// <summary>590 /// Returns the page's cookies591 /// </summary>592 /// <param name="urls">Url's to return cookies for</param>593 /// <returns>Array of cookies</returns>594 /// <remarks>595 /// If no URLs are specified, this method returns cookies for the current page URL.596 /// If URLs are specified, only cookies for those URLs are returned.597 /// </remarks>598 public async Task<CookieParam[]> GetCookiesAsync(params string[] urls)599 => (await Client.SendAsync<NetworkGetCookiesResponse>("Network.getCookies", new NetworkGetCookiesRequest600 {601 Urls = urls.Length > 0 ? urls : new string[] { Url }602 }).ConfigureAwait(false)).Cookies;603 /// <summary>604 /// Clears all of the current cookies and then sets the cookies for the page605 /// </summary>606 /// <param name="cookies">Cookies to set</param>607 /// <returns>Task</returns>608 public async Task SetCookieAsync(params CookieParam[] cookies)609 {610 foreach (var cookie in cookies)611 {612 if (string.IsNullOrEmpty(cookie.Url) && Url.StartsWith("http", StringComparison.Ordinal))613 {614 cookie.Url = Url;615 }616 if (cookie.Url == "about:blank")617 {618 throw new PuppeteerException($"Blank page can not have cookie \"{cookie.Name}\"");619 }620 }621 await DeleteCookieAsync(cookies).ConfigureAwait(false);622 if (cookies.Length > 0)623 {624 await Client.SendAsync("Network.setCookies", new NetworkSetCookiesRequest625 {626 Cookies = cookies627 }).ConfigureAwait(false);628 }629 }630 /// <summary>631 /// Deletes cookies from the page632 /// </summary>633 /// <param name="cookies">Cookies to delete</param>634 /// <returns>Task</returns>635 public async Task DeleteCookieAsync(params CookieParam[] cookies)636 {637 var pageURL = Url;638 foreach (var cookie in cookies)639 {640 if (string.IsNullOrEmpty(cookie.Url) && pageURL.StartsWith("http", StringComparison.Ordinal))641 {642 cookie.Url = pageURL;643 }644 await Client.SendAsync("Network.deleteCookies", cookie).ConfigureAwait(false);645 }646 }647 /// <summary>648 /// Adds a <c><![CDATA[<script>]]></c> tag into the page with the desired url or content649 /// </summary>650 /// <param name="options">add script tag options</param>651 /// <remarks>652 /// Shortcut for <c>page.MainFrame.AddScriptTagAsync(options)</c>653 /// </remarks>654 /// <returns>Task which resolves to the added tag when the script's onload fires or when the script content was injected into frame</returns>655 /// <seealso cref="Frame.AddScriptTagAsync(AddTagOptions)"/>656 public Task<ElementHandle> AddScriptTagAsync(AddTagOptions options) => MainFrame.AddScriptTagAsync(options);657 /// <summary>658 /// Adds a <c><![CDATA[<script>]]></c> tag into the page with the desired url or content659 /// </summary>660 /// <param name="url">script url</param>661 /// <remarks>662 /// Shortcut for <c>page.MainFrame.AddScriptTagAsync(new AddTagOptions { Url = url })</c>663 /// </remarks>664 /// <returns>Task which resolves to the added tag when the script's onload fires or when the script content was injected into frame</returns>665 public Task<ElementHandle> AddScriptTagAsync(string url) => AddScriptTagAsync(new AddTagOptions { Url = url });666 /// <summary>667 /// 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 content668 /// </summary>669 /// <param name="options">add style tag options</param>670 /// <remarks>671 /// Shortcut for <c>page.MainFrame.AddStyleTagAsync(options)</c>672 /// </remarks>673 /// <returns>Task which resolves to the added tag when the stylesheet's onload fires or when the CSS content was injected into frame</returns>674 /// <seealso cref="Frame.AddStyleTag(AddTagOptions)"/>675 public Task<ElementHandle> AddStyleTagAsync(AddTagOptions options) => MainFrame.AddStyleTagAsync(options);676 /// <summary>677 /// 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 content678 /// </summary>679 /// <param name="url">stylesheel url</param>680 /// <remarks>681 /// Shortcut for <c>page.MainFrame.AddStyleTagAsync(new AddTagOptions { Url = url })</c>682 /// </remarks>683 /// <returns>Task which resolves to the added tag when the stylesheet's onload fires or when the CSS content was injected into frame</returns>684 public Task<ElementHandle> AddStyleTagAsync(string url) => AddStyleTagAsync(new AddTagOptions { Url = url });685 /// <summary>686 /// Adds a function called <c>name</c> on the page's <c>window</c> object.687 /// When called, the function executes <paramref name="puppeteerFunction"/> in C# and returns a <see cref="Task"/> which resolves when <paramref name="puppeteerFunction"/> completes.688 /// </summary>689 /// <param name="name">Name of the function on the window object</param>690 /// <param name="puppeteerFunction">Callback function which will be called in Puppeteer's context.</param>691 /// <remarks>692 /// If the <paramref name="puppeteerFunction"/> returns a <see cref="Task"/>, it will be awaited.693 /// Functions installed via <see cref="ExposeFunctionAsync(string, Action)"/> survive navigations694 /// </remarks>695 /// <returns>Task</returns>696 public Task ExposeFunctionAsync(string name, Action puppeteerFunction)697 => ExposeFunctionAsync(name, (Delegate)puppeteerFunction);698 /// <summary>699 /// Adds a function called <c>name</c> on the page's <c>window</c> object.700 /// 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"/>.701 /// </summary>702 /// <typeparam name="TResult">The result of <paramref name="puppeteerFunction"/></typeparam>703 /// <param name="name">Name of the function on the window object</param>704 /// <param name="puppeteerFunction">Callback function which will be called in Puppeteer's context.</param>705 /// <remarks>706 /// If the <paramref name="puppeteerFunction"/> returns a <see cref="Task"/>, it will be awaited.707 /// Functions installed via <see cref="ExposeFunctionAsync{TResult}(string, Func{TResult})"/> survive navigations708 /// </remarks>709 /// <returns>Task</returns>710 public Task ExposeFunctionAsync<TResult>(string name, Func<TResult> puppeteerFunction)711 => ExposeFunctionAsync(name, (Delegate)puppeteerFunction);712 /// <summary>713 /// Adds a function called <c>name</c> on the page's <c>window</c> object.714 /// 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"/>.715 /// </summary>716 /// <typeparam name="T">The parameter of <paramref name="puppeteerFunction"/></typeparam>717 /// <typeparam name="TResult">The result of <paramref name="puppeteerFunction"/></typeparam>718 /// <param name="name">Name of the function on the window object</param>719 /// <param name="puppeteerFunction">Callback function which will be called in Puppeteer's context.</param>720 /// <remarks>721 /// If the <paramref name="puppeteerFunction"/> returns a <see cref="Task"/>, it will be awaited.722 /// Functions installed via <see cref="ExposeFunctionAsync{T, TResult}(string, Func{T, TResult})"/> survive navigations723 /// </remarks>724 /// <returns>Task</returns>725 public Task ExposeFunctionAsync<T, TResult>(string name, Func<T, TResult> puppeteerFunction)726 => ExposeFunctionAsync(name, (Delegate)puppeteerFunction);727 /// <summary>728 /// Adds a function called <c>name</c> on the page's <c>window</c> object.729 /// 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"/>.730 /// </summary>731 /// <typeparam name="T1">The first parameter of <paramref name="puppeteerFunction"/></typeparam>732 /// <typeparam name="T2">The second parameter of <paramref name="puppeteerFunction"/></typeparam>733 /// <typeparam name="TResult">The result of <paramref name="puppeteerFunction"/></typeparam>734 /// <param name="name">Name of the function on the window object</param>735 /// <param name="puppeteerFunction">Callback function which will be called in Puppeteer's context.</param>736 /// <remarks>737 /// If the <paramref name="puppeteerFunction"/> returns a <see cref="Task"/>, it will be awaited.738 /// Functions installed via <see cref="ExposeFunctionAsync{T1, T2, TResult}(string, Func{T1, T2, TResult})"/> survive navigations739 /// </remarks>740 /// <returns>Task</returns>741 public Task ExposeFunctionAsync<T1, T2, TResult>(string name, Func<T1, T2, TResult> puppeteerFunction)742 => ExposeFunctionAsync(name, (Delegate)puppeteerFunction);743 /// <summary>744 /// Adds a function called <c>name</c> on the page's <c>window</c> object.745 /// 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"/>.746 /// </summary>747 /// <typeparam name="T1">The first parameter of <paramref name="puppeteerFunction"/></typeparam>748 /// <typeparam name="T2">The second parameter of <paramref name="puppeteerFunction"/></typeparam>749 /// <typeparam name="T3">The third parameter of <paramref name="puppeteerFunction"/></typeparam>750 /// <typeparam name="TResult">The result of <paramref name="puppeteerFunction"/></typeparam>751 /// <param name="name">Name of the function on the window object</param>752 /// <param name="puppeteerFunction">Callback function which will be called in Puppeteer's context.</param>753 /// <remarks>754 /// If the <paramref name="puppeteerFunction"/> returns a <see cref="Task"/>, it will be awaited.755 /// Functions installed via <see cref="ExposeFunctionAsync{T1, T2, T3, TResult}(string, Func{T1, T2, T3, TResult})"/> survive navigations756 /// </remarks>757 /// <returns>Task</returns>758 public Task ExposeFunctionAsync<T1, T2, T3, TResult>(string name, Func<T1, T2, T3, TResult> puppeteerFunction)759 => ExposeFunctionAsync(name, (Delegate)puppeteerFunction);760 /// <summary>761 /// Adds a function called <c>name</c> on the page's <c>window</c> object.762 /// 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"/>.763 /// </summary>764 /// <typeparam name="T1">The first parameter of <paramref name="puppeteerFunction"/></typeparam>765 /// <typeparam name="T2">The second parameter of <paramref name="puppeteerFunction"/></typeparam>766 /// <typeparam name="T3">The third parameter of <paramref name="puppeteerFunction"/></typeparam>767 /// <typeparam name="T4">The fourth parameter of <paramref name="puppeteerFunction"/></typeparam>768 /// <typeparam name="TResult">The result of <paramref name="puppeteerFunction"/></typeparam>769 /// <param name="name">Name of the function on the window object</param>770 /// <param name="puppeteerFunction">Callback function which will be called in Puppeteer's context.</param>771 /// <remarks>772 /// If the <paramref name="puppeteerFunction"/> returns a <see cref="Task"/>, it will be awaited.773 /// Functions installed via <see cref="ExposeFunctionAsync{T1, T2, T3, T4, TResult}(string, Func{T1, T2, T3, T4, TResult})"/> survive navigations774 /// </remarks>775 /// <returns>Task</returns>776 public Task ExposeFunctionAsync<T1, T2, T3, T4, TResult>(string name, Func<T1, T2, T3, T4, TResult> puppeteerFunction)777 => ExposeFunctionAsync(name, (Delegate)puppeteerFunction);778 /// <summary>779 /// Gets the full HTML contents of the page, including the doctype.780 /// </summary>781 /// <returns>Task which resolves to the HTML content.</returns>782 /// <seealso cref="Frame.GetContentAsync"/>783 public Task<string> GetContentAsync() => FrameManager.MainFrame.GetContentAsync();784 /// <summary>785 /// Sets the HTML markup to the page786 /// </summary>787 /// <param name="html">HTML markup to assign to the page.</param>788 /// <param name="options">The navigations options</param>789 /// <returns>Task.</returns>790 /// <seealso cref="Frame.SetContentAsync(string, NavigationOptions)"/>791 public Task SetContentAsync(string html, NavigationOptions options = null) => FrameManager.MainFrame.SetContentAsync(html, options);792 /// <summary>793 /// Navigates to an url794 /// </summary>795 /// <remarks>796 /// <see cref="GoToAsync(string, int?, WaitUntilNavigation[])"/> will throw an error if:797 /// - there's an SSL error (e.g. in case of self-signed certificates).798 /// - target URL is invalid.799 /// - the `timeout` is exceeded during navigation.800 /// - the remote server does not respond or is unreachable.801 /// - the main resource failed to load.802 ///803 /// <see cref="GoToAsync(string, int?, WaitUntilNavigation[])"/> will not throw an error when any valid HTTP status code is returned by the remote server,804 /// including 404 "Not Found" and 500 "Internal Server Error". The status code for such responses can be retrieved by calling <see cref="PuppeteerSharp.Response.Status"/>805 ///806 /// > **NOTE** <see cref="GoToAsync(string, int?, WaitUntilNavigation[])"/> either throws an error or returns a main resource response.807 /// The only exceptions are navigation to `about:blank` or navigation to the same URL with a different hash, which would succeed and return `null`.808 ///809 /// > **NOTE** Headless mode doesn't support navigation to a PDF document. See the <see fref="https://bugs.chromium.org/p/chromium/issues/detail?id=761295">upstream issue</see>.810 ///811 /// Shortcut for <seealso cref="Frame.GoToAsync(string, int?, WaitUntilNavigation[])"/>812 /// </remarks>813 /// <param name="url">URL to navigate page to. The url should include scheme, e.g. https://.</param>814 /// <param name="options">Navigation parameters.</param>815 /// <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>816 /// <seealso cref="GoToAsync(string, int?, WaitUntilNavigation[])"/>817 public Task<Response> GoToAsync(string url, NavigationOptions options) => FrameManager.MainFrame.GoToAsync(url, options);818 /// <summary>819 /// Navigates to an url820 /// </summary>821 /// <param name="url">URL to navigate page to. The url should include scheme, e.g. https://.</param>822 /// <param name="timeout">Maximum navigation time in milliseconds, defaults to 30 seconds, pass <c>0</c> to disable timeout. </param>823 /// <param name="waitUntil">When to consider navigation succeeded, defaults to <see cref="WaitUntilNavigation.Load"/>. Given an array of <see cref="WaitUntilNavigation"/>, navigation is considered to be successful after all events have been fired</param>824 /// <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>825 /// <seealso cref="GoToAsync(string, NavigationOptions)"/>826 public Task<Response> GoToAsync(string url, int? timeout = null, WaitUntilNavigation[] waitUntil = null)827 => GoToAsync(url, new NavigationOptions { Timeout = timeout, WaitUntil = waitUntil });828 /// <summary>829 /// Navigates to an url830 /// </summary>831 /// <param name="url">URL to navigate page to. The url should include scheme, e.g. https://.</param>832 /// <param name="waitUntil">When to consider navigation succeeded.</param>833 /// <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>834 /// <seealso cref="GoToAsync(string, NavigationOptions)"/>835 public Task<Response> GoToAsync(string url, WaitUntilNavigation waitUntil)836 => GoToAsync(url, new NavigationOptions { WaitUntil = new[] { waitUntil } });837 /// <summary>838 /// 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"/>839 /// </summary>840 /// <param name="file">The file path to save the PDF to. paths are resolved using <see cref="Path.GetFullPath(string)"/></param>841 /// <returns></returns>842 /// <remarks>843 /// Generating a pdf is currently only supported in Chrome headless844 /// </remarks>845 public Task PdfAsync(string file) => PdfAsync(file, new PdfOptions());846 /// <summary>847 /// 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"/>848 /// </summary>849 /// <param name="file">The file path to save the PDF to. paths are resolved using <see cref="Path.GetFullPath(string)"/></param>850 /// <param name="options">pdf options</param>851 /// <returns></returns>852 /// <remarks>853 /// Generating a pdf is currently only supported in Chrome headless854 /// </remarks>855 public async Task PdfAsync(string file, PdfOptions options)856 {857 if (options == null)858 {859 throw new ArgumentNullException(nameof(options));860 }861 await PdfInternalAsync(file, options).ConfigureAwait(false);862 }863 /// <summary>864 /// 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"/>865 /// </summary>866 /// <returns>Task which resolves to a <see cref="Stream"/> containing the PDF data.</returns>867 /// <remarks>868 /// Generating a pdf is currently only supported in Chrome headless869 /// </remarks>870 public Task<Stream> PdfStreamAsync() => PdfStreamAsync(new PdfOptions());871 /// <summary>872 /// 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"/>873 /// </summary>874 /// <param name="options">pdf options</param>875 /// <returns>Task which resolves to a <see cref="Stream"/> containing the PDF data.</returns>876 /// <remarks>877 /// Generating a pdf is currently only supported in Chrome headless878 /// </remarks>879 public async Task<Stream> PdfStreamAsync(PdfOptions options)880 => new MemoryStream(await PdfDataAsync(options).ConfigureAwait(false));881 /// <summary>882 /// 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"/>883 /// </summary>884 /// <returns>Task which resolves to a <see cref="byte"/>[] containing the PDF data.</returns>885 /// <remarks>886 /// Generating a pdf is currently only supported in Chrome headless887 /// </remarks>888 public Task<byte[]> PdfDataAsync() => PdfDataAsync(new PdfOptions());889 /// <summary>890 /// 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"/>891 /// </summary>892 /// <param name="options">pdf options</param>893 /// <returns>Task which resolves to a <see cref="byte"/>[] containing the PDF data.</returns>894 /// <remarks>895 /// Generating a pdf is currently only supported in Chrome headless896 /// </remarks>897 public Task<byte[]> PdfDataAsync(PdfOptions options)898 {899 if (options == null)900 {901 throw new ArgumentNullException(nameof(options));902 }903 return PdfInternalAsync(null, options);904 }905 internal async Task<byte[]> PdfInternalAsync(string file, PdfOptions options)906 {907 var paperWidth = PaperFormat.Letter.Width;908 var paperHeight = PaperFormat.Letter.Height;909 if (options.Format != null)910 {911 paperWidth = options.Format.Width;912 paperHeight = options.Format.Height;913 }914 else915 {916 if (options.Width != null)917 {918 paperWidth = ConvertPrintParameterToInches(options.Width);919 }920 if (options.Height != null)921 {922 paperHeight = ConvertPrintParameterToInches(options.Height);923 }924 }925 var marginTop = ConvertPrintParameterToInches(options.MarginOptions.Top);926 var marginLeft = ConvertPrintParameterToInches(options.MarginOptions.Left);927 var marginBottom = ConvertPrintParameterToInches(options.MarginOptions.Bottom);928 var marginRight = ConvertPrintParameterToInches(options.MarginOptions.Right);929 if (options.OmitBackground)930 {931 await SetTransparentBackgroundColorAsync().ConfigureAwait(false);932 }933 var result = await Client.SendAsync<PagePrintToPDFResponse>("Page.printToPDF", new PagePrintToPDFRequest934 {935 TransferMode = "ReturnAsStream",936 Landscape = options.Landscape,937 DisplayHeaderFooter = options.DisplayHeaderFooter,938 HeaderTemplate = options.HeaderTemplate,939 FooterTemplate = options.FooterTemplate,940 PrintBackground = options.PrintBackground,941 Scale = options.Scale,942 PaperWidth = paperWidth,943 PaperHeight = paperHeight,944 MarginTop = marginTop,945 MarginBottom = marginBottom,946 MarginLeft = marginLeft,947 MarginRight = marginRight,948 PageRanges = options.PageRanges,949 PreferCSSPageSize = options.PreferCSSPageSize950 }).ConfigureAwait(false);951 if (options.OmitBackground)952 {953 await ResetDefaultBackgroundColorAsync().ConfigureAwait(false);954 }955 return await ProtocolStreamReader.ReadProtocolStreamByteAsync(Client, result.Stream, file).ConfigureAwait(false);956 }957 /// <summary>958 /// Enables/Disables Javascript on the page959 /// </summary>960 /// <returns>Task.</returns>961 /// <param name="enabled">Whether or not to enable JavaScript on the page.</param>962 public Task SetJavaScriptEnabledAsync(bool enabled)963 {964 if (enabled == JavascriptEnabled)965 {966 return Task.CompletedTask;967 }968 JavascriptEnabled = enabled;969 return Client.SendAsync("Emulation.setScriptExecutionDisabled", new EmulationSetScriptExecutionDisabledRequest970 {971 Value = !enabled972 });973 }974 /// <summary>975 /// Toggles bypassing page's Content-Security-Policy.976 /// </summary>977 /// <param name="enabled">sets bypassing of page's Content-Security-Policy.</param>978 /// <returns></returns>979 /// <remarks>980 /// CSP bypassing happens at the moment of CSP initialization rather then evaluation.981 /// Usually this means that <see cref="SetBypassCSPAsync(bool)"/> should be called before navigating to the domain.982 /// </remarks>983 public Task SetBypassCSPAsync(bool enabled) => Client.SendAsync("Page.setBypassCSP", new PageSetBypassCSPRequest984 {985 Enabled = enabled986 });987 /// <summary>988 /// Emulates a media such as screen or print.989 /// </summary>990 /// <returns>Task.</returns>991 /// <param name="media">Media to set.</param>992 [Obsolete("User EmulateMediaTypeAsync instead")]993 public Task EmulateMediaAsync(MediaType media) => EmulateMediaTypeAsync(media);994 /// <summary>995 /// Emulates a media such as screen or print.996 /// </summary>997 /// <param name="type">Media to set.</param>998 /// <example>999 /// <code>1000 /// <![CDATA[1001 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('screen').matches)");1002 /// // â true1003 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('print').matches)");1004 /// // â true1005 /// await page.EmulateMediaTypeAsync(MediaType.Print);1006 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('screen').matches)");1007 /// // â false1008 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('print').matches)");1009 /// // â true1010 /// await page.EmulateMediaTypeAsync(MediaType.None);1011 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('screen').matches)");1012 /// // â true1013 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('print').matches)");1014 /// // â true1015 /// ]]>1016 /// </code>1017 /// </example>1018 /// <returns>Emulate media type task.</returns>1019 public Task EmulateMediaTypeAsync(MediaType type)1020 => Client.SendAsync("Emulation.setEmulatedMedia", new EmulationSetEmulatedMediaTypeRequest { Media = type });1021 /// <summary>1022 /// Given an array of media feature objects, emulates CSS media features on the page.1023 /// </summary>1024 /// <param name="features">Features to apply</param>1025 /// <example>1026 /// <code>1027 /// <![CDATA[1028 /// await page.EmulateMediaFeaturesAsync(new MediaFeature[]{ new MediaFeature { MediaFeature = MediaFeature.PrefersColorScheme, Value = "dark" }});1029 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('(prefers-color-scheme: dark)').matches)");1030 /// // â true1031 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('(prefers-color-scheme: light)').matches)");1032 /// // â false1033 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('(prefers-color-scheme: no-preference)').matches)");1034 /// // â false1035 /// await page.EmulateMediaFeaturesAsync(new MediaFeature[]{ new MediaFeature { MediaFeature = MediaFeature.PrefersReducedMotion, Value = "reduce" }});1036 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('(prefers-reduced-motion: reduce)').matches)");1037 /// // â true1038 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('(prefers-color-scheme: no-preference)').matches)");1039 /// // â false1040 /// await page.EmulateMediaFeaturesAsync(new MediaFeature[]1041 /// {1042 /// new MediaFeature { MediaFeature = MediaFeature.PrefersColorScheme, Value = "dark" },1043 /// new MediaFeature { MediaFeature = MediaFeature.PrefersReducedMotion, Value = "reduce" },1044 /// });1045 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('(prefers-color-scheme: dark)').matches)");1046 /// // â true1047 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('(prefers-color-scheme: light)').matches)");1048 /// // â false1049 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('(prefers-color-scheme: no-preference)').matches)");1050 /// // â false1051 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('(prefers-reduced-motion: reduce)').matches)");1052 /// // â true1053 /// await page.EvaluateFunctionAsync<bool>("() => matchMedia('(prefers-color-scheme: no-preference)').matches)");1054 /// // â false1055 /// ]]>1056 /// </code>1057 /// </example>1058 /// <returns>Emulate features task</returns>1059 public Task EmulateMediaFeaturesAsync(IEnumerable<MediaFeatureValue> features)1060 => Client.SendAsync("Emulation.setEmulatedMedia", new EmulationSetEmulatedMediaFeatureRequest { Features = features });1061 /// <summary>1062 /// Sets the viewport.1063 /// In the case of multiple pages in a single browser, each page can have its own viewport size.1064 /// <see cref="SetViewportAsync(ViewPortOptions)"/> will resize the page. A lot of websites don't expect phones to change size, so you should set the viewport before navigating to the page.1065 /// </summary>1066 /// <example>1067 ///<![CDATA[1068 /// using(var page = await browser.NewPageAsync())1069 /// {1070 /// await page.SetViewPortAsync(new ViewPortOptions1071 /// {1072 /// Width = 640,1073 /// Height = 480,1074 /// DeviceScaleFactor = 11075 /// });1076 /// await page.goto('https://www.example.com');1077 /// }1078 /// ]]>1079 /// </example>1080 /// <returns>The viewport task.</returns>1081 /// <param name="viewport">Viewport options.</param>1082 public async Task SetViewportAsync(ViewPortOptions viewport)1083 {1084 if (viewport == null)1085 {1086 throw new ArgumentNullException(nameof(viewport));1087 }1088 var needsReload = await _emulationManager.EmulateViewport(viewport).ConfigureAwait(false);1089 Viewport = viewport;1090 if (needsReload)1091 {1092 await ReloadAsync().ConfigureAwait(false);1093 }1094 }1095 /// <summary>1096 /// Emulates given device metrics and user agent.1097 /// </summary>1098 /// <remarks>1099 /// This method is a shortcut for calling two methods:1100 /// <see cref="SetViewportAsync(ViewPortOptions)"/>1101 /// <see cref="SetUserAgentAsync(string)"/>1102 /// To aid emulation, puppeteer provides a list of device descriptors which can be obtained via the <see cref="Puppeteer.Devices"/>.1103 /// <see cref="EmulateAsync(DeviceDescriptor)"/> will resize the page. A lot of websites don't expect phones to change size, so you should emulate before navigating to the page.1104 /// </remarks>1105 /// <example>1106 ///<![CDATA[1107 /// var iPhone = Puppeteer.Devices[DeviceDescriptorName.IPhone6];1108 /// using(var page = await browser.NewPageAsync())1109 /// {1110 /// await page.EmulateAsync(iPhone);1111 /// await page.goto('https://www.google.com');1112 /// }1113 /// ]]>1114 /// </example>1115 /// <returns>Task.</returns>1116 /// <param name="options">Emulation options.</param>1117 public Task EmulateAsync(DeviceDescriptor options)1118 {1119 if (options == null)1120 {1121 throw new ArgumentNullException(nameof(options));1122 }1123 return Task.WhenAll(1124 SetViewportAsync(options.ViewPort),1125 SetUserAgentAsync(options.UserAgent));1126 }1127 /// <summary>1128 /// Takes a screenshot of the page1129 /// </summary>1130 /// <returns>The screenshot task.</returns>1131 /// <param name="file">The file path to save the image to. The screenshot type will be inferred from file extension.1132 /// If path is a relative path, then it is resolved relative to current working directory. If no path is provided,1133 /// the image won't be saved to the disk.</param>1134 public Task ScreenshotAsync(string file) => ScreenshotAsync(file, new ScreenshotOptions());1135 /// <summary>1136 /// Takes a screenshot of the page1137 /// </summary>1138 /// <returns>The screenshot task.</returns>1139 /// <param name="file">The file path to save the image to. The screenshot type will be inferred from file extension.1140 /// If path is a relative path, then it is resolved relative to current working directory. If no path is provided,1141 /// the image won't be saved to the disk.</param>1142 /// <param name="options">Screenshot options.</param>1143 public async Task ScreenshotAsync(string file, ScreenshotOptions options)1144 {1145 if (options == null)1146 {1147 throw new ArgumentNullException(nameof(options));1148 }1149 if (!options.Type.HasValue)1150 {1151 options.Type = ScreenshotOptions.GetScreenshotTypeFromFile(file);1152 if (options.Type == ScreenshotType.Jpeg && !options.Quality.HasValue)1153 {1154 options.Quality = 90;1155 }1156 }1157 var data = await ScreenshotDataAsync(options).ConfigureAwait(false);1158 using (var fs = AsyncFileHelper.CreateStream(file, FileMode.Create))1159 {1160 await fs.WriteAsync(data, 0, data.Length).ConfigureAwait(false);1161 }1162 }1163 /// <summary>1164 /// Takes a screenshot of the page1165 /// </summary>1166 /// <returns>Task which resolves to a <see cref="Stream"/> containing the image data.</returns>1167 public Task<Stream> ScreenshotStreamAsync() => ScreenshotStreamAsync(new ScreenshotOptions());1168 /// <summary>1169 /// Takes a screenshot of the page1170 /// </summary>1171 /// <returns>Task which resolves to a <see cref="Stream"/> containing the image data.</returns>1172 /// <param name="options">Screenshot options.</param>1173 public async Task<Stream> ScreenshotStreamAsync(ScreenshotOptions options)1174 => new MemoryStream(await ScreenshotDataAsync(options).ConfigureAwait(false));1175 /// <summary>1176 /// Takes a screenshot of the page1177 /// </summary>1178 /// <returns>Task which resolves to a <see cref="string"/> containing the image data as base64.</returns>1179 public Task<string> ScreenshotBase64Async() => ScreenshotBase64Async(new ScreenshotOptions());1180 /// <summary>1181 /// Takes a screenshot of the page1182 /// </summary>1183 /// <returns>Task which resolves to a <see cref="string"/> containing the image data as base64.</returns>1184 /// <param name="options">Screenshot options.</param>1185 public Task<string> ScreenshotBase64Async(ScreenshotOptions options)1186 {1187 if (options == null)1188 {1189 throw new ArgumentNullException(nameof(options));1190 }1191 var screenshotType = options.Type;1192 if (!screenshotType.HasValue)1193 {1194 screenshotType = ScreenshotType.Png;1195 }1196 if (options.Quality.HasValue)1197 {1198 if (screenshotType != ScreenshotType.Jpeg)1199 {1200 throw new ArgumentException($"options.Quality is unsupported for the {screenshotType} screenshots");1201 }1202 if (options.Quality < 0 || options.Quality > 100)1203 {1204 throw new ArgumentException($"Expected options.quality to be between 0 and 100 (inclusive), got {options.Quality}");1205 }1206 }1207 if (options?.Clip?.Width == 0)1208 {1209 throw new PuppeteerException("Expected options.Clip.Width not to be 0.");1210 }1211 if (options?.Clip?.Height == 0)1212 {1213 throw new PuppeteerException("Expected options.Clip.Height not to be 0.");1214 }1215 if (options.Clip != null && options.FullPage)1216 {1217 throw new ArgumentException("options.clip and options.fullPage are exclusive");1218 }1219 return _screenshotTaskQueue.Enqueue(() => PerformScreenshot(screenshotType.Value, options));1220 }1221 /// <summary>1222 /// Takes a screenshot of the page1223 /// </summary>1224 /// <returns>Task which resolves to a <see cref="byte"/>[] containing the image data.</returns>1225 public Task<byte[]> ScreenshotDataAsync() => ScreenshotDataAsync(new ScreenshotOptions());1226 /// <summary>1227 /// Takes a screenshot of the page1228 /// </summary>1229 /// <returns>Task which resolves to a <see cref="byte"/>[] containing the image data.</returns>1230 /// <param name="options">Screenshot options.</param>1231 public async Task<byte[]> ScreenshotDataAsync(ScreenshotOptions options)1232 => Convert.FromBase64String(await ScreenshotBase64Async(options).ConfigureAwait(false));1233 /// <summary>1234 /// Returns page's title1235 /// </summary>1236 /// <returns>page's title</returns>1237 /// <see cref="Frame.GetTitleAsync"/>1238 public Task<string> GetTitleAsync() => MainFrame.GetTitleAsync();1239 /// <summary>1240 /// Closes the page.1241 /// </summary>1242 /// <param name="options">Close options.</param>1243 /// <returns>Task.</returns>1244 public Task CloseAsync(PageCloseOptions options = null)1245 {1246 if (!(Client?.Connection?.IsClosed ?? true))1247 {1248 var runBeforeUnload = options?.RunBeforeUnload ?? false;1249 if (runBeforeUnload)1250 {1251 return Client.SendAsync("Page.close");1252 }1253 return Client.Connection.SendAsync("Target.closeTarget", new TargetCloseTargetRequest1254 {1255 TargetId = Target.TargetId1256 }).ContinueWith(task => Target.CloseTask, TaskScheduler.Default);1257 }1258 _logger.LogWarning("Protocol error: Connection closed. Most likely the page has been closed.");1259 return _closeCompletedTcs.Task;1260 }1261 /// <summary>1262 /// Toggles ignoring cache for each request based on the enabled state. By default, caching is enabled.1263 /// </summary>1264 /// <param name="enabled">sets the <c>enabled</c> state of the cache</param>1265 /// <returns>Task</returns>1266 public Task SetCacheEnabledAsync(bool enabled = true)1267 => FrameManager.NetworkManager.SetCacheEnabledAsync(enabled);1268 /// <summary>1269 /// Fetches an element with <paramref name="selector"/>, scrolls it into view if needed, and then uses <see cref="Mouse"/> to click in the center of the element.1270 /// </summary>1271 /// <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>1272 /// <param name="options">click options</param>1273 /// <exception cref="SelectorException">If there's no element matching <paramref name="selector"/></exception>1274 /// <returns>Task which resolves when the element matching <paramref name="selector"/> is successfully clicked</returns>1275 public Task ClickAsync(string selector, ClickOptions options = null) => FrameManager.MainFrame.ClickAsync(selector, options);1276 /// <summary>1277 /// Fetches an element with <paramref name="selector"/>, scrolls it into view if needed, and then uses <see cref="Mouse"/> to hover over the center of the element.1278 /// </summary>1279 /// <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>1280 /// <exception cref="SelectorException">If there's no element matching <paramref name="selector"/></exception>1281 /// <returns>Task which resolves when the element matching <paramref name="selector"/> is successfully hovered</returns>1282 public Task HoverAsync(string selector) => FrameManager.MainFrame.HoverAsync(selector);1283 /// <summary>1284 /// Fetches an element with <paramref name="selector"/> and focuses it1285 /// </summary>1286 /// <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>1287 /// <exception cref="SelectorException">If there's no element matching <paramref name="selector"/></exception>1288 /// <returns>Task which resolves when the element matching <paramref name="selector"/> is successfully focused</returns>1289 public Task FocusAsync(string selector) => FrameManager.MainFrame.FocusAsync(selector);1290 /// <summary>1291 /// Sends a <c>keydown</c>, <c>keypress</c>/<c>input</c>, and <c>keyup</c> event for each character in the text.1292 /// </summary>1293 /// <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>1294 /// <param name="text">A text to type into a focused element</param>1295 /// <param name="options">The options to apply to the type operation.</param>1296 /// <exception cref="SelectorException">If there's no element matching <paramref name="selector"/></exception>1297 /// <remarks>1298 /// To press a special key, like <c>Control</c> or <c>ArrowDown</c> use <see cref="PuppeteerSharp.Input.Keyboard.PressAsync(string, PressOptions)"/>1299 /// </remarks>1300 /// <example>1301 /// <code>1302 /// await page.TypeAsync("#mytextarea", "Hello"); // Types instantly1303 /// await page.TypeAsync("#mytextarea", "World", new TypeOptions { Delay = 100 }); // Types slower, like a user1304 /// </code>1305 /// </example>1306 /// <returns>Task</returns>1307 public Task TypeAsync(string selector, string text, TypeOptions options = null)1308 => FrameManager.MainFrame.TypeAsync(selector, text, options);1309 /// <summary>1310 /// Executes a script in browser context1311 /// </summary>1312 /// <param name="script">Script to be evaluated in browser context</param>1313 /// <remarks>1314 /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.1315 /// </remarks>1316 /// <example>1317 /// An example of scraping information from all hyperlinks on the page.1318 /// <code>1319 /// var hyperlinkInfo = await page.EvaluateExpressionAsync(@"1320 /// Array1321 /// .from(document.querySelectorAll('a'))1322 /// .map(n => ({1323 /// text: n.innerText,1324 /// href: n.getAttribute('href'),1325 /// target: n.getAttribute('target')1326 /// }))1327 /// ");1328 /// Console.WriteLine(hyperlinkInfo.ToString()); // Displays JSON array of hyperlinkInfo objects1329 /// </code>1330 /// </example>1331 /// <seealso href="https://www.newtonsoft.com/json/help/html/t_newtonsoft_json_linq_jtoken.htm"/>1332 /// <seealso cref="EvaluateFunctionAsync{T}(string, object[])"/>1333 /// <returns>Task which resolves to script return value</returns>1334 public Task<JToken> EvaluateExpressionAsync(string script)1335 => FrameManager.MainFrame.EvaluateExpressionAsync<JToken>(script);1336 /// <summary>1337 /// Executes a script in browser context1338 /// </summary>1339 /// <typeparam name="T">The type to deserialize the result to</typeparam>1340 /// <param name="script">Script to be evaluated in browser context</param>1341 /// <remarks>1342 /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.1343 /// </remarks>1344 /// <seealso cref="EvaluateFunctionAsync{T}(string, object[])"/>1345 /// <returns>Task which resolves to script return value</returns>1346 public Task<T> EvaluateExpressionAsync<T>(string script)1347 => FrameManager.MainFrame.EvaluateExpressionAsync<T>(script);1348 /// <summary>1349 /// Executes a function in browser context1350 /// </summary>1351 /// <param name="script">Script to be evaluated in browser context</param>1352 /// <param name="args">Arguments to pass to script</param>1353 /// <remarks>1354 /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.1355 /// <see cref="JSHandle"/> instances can be passed as arguments1356 /// </remarks>1357 /// <seealso cref="EvaluateExpressionAsync{T}(string)"/>1358 /// <returns>Task which resolves to script return value</returns>1359 public Task<JToken> EvaluateFunctionAsync(string script, params object[] args)1360 => FrameManager.MainFrame.EvaluateFunctionAsync<JToken>(script, args);1361 /// <summary>1362 /// Executes a function in browser context1363 /// </summary>1364 /// <typeparam name="T">The type to deserialize the result to</typeparam>1365 /// <param name="script">Script to be evaluated in browser context</param>1366 /// <param name="args">Arguments to pass to script</param>1367 /// <remarks>1368 /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.1369 /// <see cref="JSHandle"/> instances can be passed as arguments1370 /// </remarks>1371 /// <seealso cref="EvaluateExpressionAsync{T}(string)"/>1372 /// <returns>Task which resolves to script return value</returns>1373 public Task<T> EvaluateFunctionAsync<T>(string script, params object[] args)1374 => FrameManager.MainFrame.EvaluateFunctionAsync<T>(script, args);1375 /// <summary>1376 /// Sets the user agent to be used in this page1377 /// </summary>1378 /// <param name="userAgent">Specific user agent to use in this page</param>1379 /// <returns>Task</returns>1380 public Task SetUserAgentAsync(string userAgent)1381 => FrameManager.NetworkManager.SetUserAgentAsync(userAgent);1382 /// <summary>1383 /// Sets extra HTTP headers that will be sent with every request the page initiates1384 /// </summary>1385 /// <param name="headers">Additional http headers to be sent with every request</param>1386 /// <returns>Task</returns>1387 public Task SetExtraHttpHeadersAsync(Dictionary<string, string> headers)1388 {1389 if (headers == null)1390 {1391 throw new ArgumentNullException(nameof(headers));1392 }1393 return FrameManager.NetworkManager.SetExtraHTTPHeadersAsync(headers);1394 }1395 /// <summary>1396 /// Provide credentials for http authentication <see href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication"/>1397 /// </summary>1398 /// <param name="credentials">The credentials</param>1399 /// <returns></returns>1400 /// <remarks>1401 /// To disable authentication, pass <c>null</c>1402 /// </remarks>1403 public Task AuthenticateAsync(Credentials credentials) => FrameManager.NetworkManager.AuthenticateAsync(credentials);1404 /// <summary>1405 /// Reloads the page1406 /// </summary>1407 /// <param name="options">Navigation options</param>1408 /// <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>1409 /// <seealso cref="ReloadAsync(int?, WaitUntilNavigation[])"/>1410 public async Task<Response> ReloadAsync(NavigationOptions options)1411 {1412 var navigationTask = WaitForNavigationAsync(options);1413 await Task.WhenAll(1414 navigationTask,1415 Client.SendAsync("Page.reload", new PageReloadRequest { FrameId = MainFrame.Id })).ConfigureAwait(false);1416 return navigationTask.Result;1417 }1418 /// <summary>1419 /// Reloads the page1420 /// </summary>1421 /// <param name="timeout">Maximum navigation time in milliseconds, defaults to 30 seconds, pass <c>0</c> to disable timeout. </param>1422 /// <param name="waitUntil">When to consider navigation succeeded, defaults to <see cref="WaitUntilNavigation.Load"/>. Given an array of <see cref="WaitUntilNavigation"/>, navigation is considered to be successful after all events have been fired</param>1423 /// <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>1424 /// <seealso cref="ReloadAsync(NavigationOptions)"/>1425 public Task<Response> ReloadAsync(int? timeout = null, WaitUntilNavigation[] waitUntil = null)1426 => ReloadAsync(new NavigationOptions { Timeout = timeout, WaitUntil = waitUntil });1427 /// <summary>1428 /// Triggers a change and input event once all the provided options have been selected.1429 /// If there's no <![CDATA[<select>]]> element matching selector, the method throws an error.1430 /// </summary>1431 /// <exception cref="SelectorException">If there's no element matching <paramref name="selector"/></exception>1432 /// <param name="selector">A selector to query page for</param>1433 /// <param name="values">Values of options to select. If the <![CDATA[<select>]]> has the multiple attribute,1434 /// all values are considered, otherwise only the first one is taken into account.</param>1435 /// <returns>Returns an array of option values that have been successfully selected.</returns>1436 /// <seealso cref="Frame.SelectAsync(string, string[])"/>1437 public Task<string[]> SelectAsync(string selector, params string[] values)1438 => MainFrame.SelectAsync(selector, values);1439 /// <summary>1440 /// Waits for a timeout1441 /// </summary>1442 /// <param name="milliseconds">The amount of time to wait.</param>1443 /// <returns>A task that resolves when after the timeout</returns>1444 /// <seealso cref="Frame.WaitForTimeoutAsync(int)"/>1445 public Task WaitForTimeoutAsync(int milliseconds)1446 => MainFrame.WaitForTimeoutAsync(milliseconds);1447 /// <summary>1448 /// Waits for a function to be evaluated to a truthy value1449 /// </summary>1450 /// <param name="script">Function to be evaluated in browser context</param>1451 /// <param name="options">Optional waiting parameters</param>1452 /// <param name="args">Arguments to pass to <c>script</c></param>1453 /// <returns>A task that resolves when the <c>script</c> returns a truthy value</returns>1454 /// <seealso cref="Frame.WaitForFunctionAsync(string, WaitForFunctionOptions, object[])"/>1455 public Task<JSHandle> WaitForFunctionAsync(string script, WaitForFunctionOptions options = null, params object[] args)1456 => MainFrame.WaitForFunctionAsync(script, options ?? new WaitForFunctionOptions(), args);1457 /// <summary>1458 /// Waits for a function to be evaluated to a truthy value1459 /// </summary>1460 /// <param name="script">Function to be evaluated in browser context</param>1461 /// <param name="args">Arguments to pass to <c>script</c></param>1462 /// <returns>A task that resolves when the <c>script</c> returns a truthy value</returns>1463 public Task<JSHandle> WaitForFunctionAsync(string script, params object[] args) => WaitForFunctionAsync(script, null, args);1464 /// <summary>1465 /// Waits for an expression to be evaluated to a truthy value1466 /// </summary>1467 /// <param name="script">Expression to be evaluated in browser context</param>1468 /// <param name="options">Optional waiting parameters</param>1469 /// <returns>A task that resolves when the <c>script</c> returns a truthy value</returns>1470 /// <seealso cref="Frame.WaitForExpressionAsync(string, WaitForFunctionOptions)"/>1471 public Task<JSHandle> WaitForExpressionAsync(string script, WaitForFunctionOptions options = null)1472 => MainFrame.WaitForExpressionAsync(script, options ?? new WaitForFunctionOptions());1473 /// <summary>1474 /// Waits for a selector to be added to the DOM1475 /// </summary>1476 /// <param name="selector">A selector of an element to wait for</param>1477 /// <param name="options">Optional waiting parameters</param>1478 /// <returns>A task that resolves when element specified by selector string is added to DOM.1479 /// Resolves to `null` if waiting for `hidden: true` and selector is not found in DOM.</returns>1480 /// <seealso cref="WaitForXPathAsync(string, WaitForSelectorOptions)"/>1481 /// <seealso cref="Frame.WaitForSelectorAsync(string, WaitForSelectorOptions)"/>1482 public Task<ElementHandle> WaitForSelectorAsync(string selector, WaitForSelectorOptions options = null)1483 => MainFrame.WaitForSelectorAsync(selector, options ?? new WaitForSelectorOptions());1484 /// <summary>1485 /// Waits for a xpath selector to be added to the DOM1486 /// </summary>1487 /// <param name="xpath">A xpath selector of an element to wait for</param>1488 /// <param name="options">Optional waiting parameters</param>1489 /// <returns>A task which resolves when element specified by xpath string is added to DOM.1490 /// Resolves to `null` if waiting for `hidden: true` and xpath is not found in DOM.</returns>1491 /// <example>1492 /// <code>1493 /// <![CDATA[1494 /// var browser = await Puppeteer.LaunchAsync(new LaunchOptions());1495 /// var page = await browser.NewPageAsync();1496 /// string currentURL = null;1497 /// page1498 /// .WaitForXPathAsync("//img")1499 /// .ContinueWith(_ => Console.WriteLine("First URL with image: " + currentURL));1500 /// foreach (var current in new[] { "https://example.com", "https://google.com", "https://bbc.com" })1501 /// {1502 /// currentURL = current;1503 /// await page.GoToAsync(currentURL);1504 /// }1505 /// await browser.CloseAsync();1506 /// ]]>1507 /// </code>1508 /// </example>1509 /// <seealso cref="WaitForSelectorAsync(string, WaitForSelectorOptions)"/>1510 /// <seealso cref="Frame.WaitForXPathAsync(string, WaitForSelectorOptions)"/>1511 public Task<ElementHandle> WaitForXPathAsync(string xpath, WaitForSelectorOptions options = null)1512 => MainFrame.WaitForXPathAsync(xpath, options ?? new WaitForSelectorOptions());1513 /// <summary>1514 /// This resolves when the page navigates to a new URL or reloads.1515 /// It is useful for when you run code which will indirectly cause the page to navigate.1516 /// </summary>1517 /// <param name="options">navigation options</param>1518 /// <returns>Task which resolves to the main resource response.1519 /// In case of multiple redirects, the navigation will resolve with the response of the last redirect.1520 /// In case of navigation to a different anchor or navigation due to History API usage, the navigation will resolve with `null`.1521 /// </returns>1522 /// <remarks>1523 /// Usage of the <c>History API</c> <see href="https://developer.mozilla.org/en-US/docs/Web/API/History_API"/> to change the URL is considered a navigation1524 /// </remarks>1525 /// <example>1526 /// <code>1527 /// <![CDATA[1528 /// var navigationTask = page.WaitForNavigationAsync();1529 /// await page.ClickAsync("a.my-link");1530 /// await navigationTask;1531 /// ]]>1532 /// </code>1533 /// </example>1534 public Task<Response> WaitForNavigationAsync(NavigationOptions options = null) => FrameManager.WaitForFrameNavigationAsync(FrameManager.MainFrame, options);1535 /// <summary>1536 /// Waits for Network Idle1537 /// </summary>1538 /// <param name="options">Optional waiting parameters</param>1539 /// <returns>returns Task which resolves when network is idle</returns>1540 /// <example>1541 /// <code>1542 /// <![CDATA[1543 /// page.EvaluateFunctionAsync("() => fetch('some-url')");1544 /// await page.WaitForNetworkIdle(); // The Task resolves after fetch above finishes1545 /// ]]>1546 /// </code>1547 /// </example>1548 public async Task WaitForNetworkIdleAsync(WaitForNetworkIdleOptions options = null)1549 {1550 var timeout = options?.Timeout ?? DefaultTimeout;1551 var idleTime = options?.IdleTime ?? 500;1552 var networkIdleTcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);1553 var idleTimer = new Timer1554 {1555 Interval = idleTime1556 };1557 idleTimer.Elapsed += (sender, args) =>1558 {1559 networkIdleTcs.TrySetResult(true);1560 };1561 var networkManager = FrameManager.NetworkManager;1562 void Evaluate()1563 {1564 idleTimer.Stop();1565 if (networkManager.NumRequestsInProgress == 0)1566 {1567 idleTimer.Start();1568 }1569 }1570 void RequestEventListener(object sender, RequestEventArgs e) => Evaluate();1571 void ResponseEventListener(object sender, ResponseCreatedEventArgs e) => Evaluate();1572 void Cleanup()1573 {1574 idleTimer.Stop();1575 idleTimer.Dispose();1576 networkManager.Request -= RequestEventListener;1577 networkManager.Response -= ResponseEventListener;1578 }1579 networkManager.Request += RequestEventListener;1580 networkManager.Response += ResponseEventListener;1581 Evaluate();1582 await Task.WhenAny(networkIdleTcs.Task, SessionClosedTask).WithTimeout(timeout, t =>1583 {1584 Cleanup();1585 return new TimeoutException($"Timeout of {t.TotalMilliseconds} ms exceeded");1586 }).ConfigureAwait(false);1587 Cleanup();1588 if (SessionClosedTask.IsFaulted)1589 {1590 await SessionClosedTask.ConfigureAwait(false);1591 }1592 }1593 /// <summary>1594 /// Waits for a request.1595 /// </summary>1596 /// <example>1597 /// <code>1598 /// <![CDATA[1599 /// var firstRequest = await page.WaitForRequestAsync("http://example.com/resource");1600 /// return firstRequest.Url;1601 /// ]]>1602 /// </code>1603 /// </example>1604 /// <returns>A task which resolves when a matching request was made.</returns>1605 /// <param name="url">URL to wait for.</param>1606 /// <param name="options">Options.</param>1607 public Task<Request> WaitForRequestAsync(string url, WaitForOptions options = null)1608 => WaitForRequestAsync(request => request.Url == url, options);1609 /// <summary>1610 /// Waits for a request.1611 /// </summary>1612 /// <example>1613 /// <code>1614 /// <![CDATA[1615 /// var request = await page.WaitForRequestAsync(request => request.Url === "http://example.com" && request.Method === HttpMethod.Get;1616 /// return request.Url;1617 /// ]]>1618 /// </code>1619 /// </example>1620 /// <returns>A task which resolves when a matching request was made.</returns>1621 /// <param name="predicate">Function which looks for a matching request.</param>1622 /// <param name="options">Options.</param>1623 public async Task<Request> WaitForRequestAsync(Func<Request, bool> predicate, WaitForOptions options = null)1624 {1625 var timeout = options?.Timeout ?? DefaultTimeout;1626 var requestTcs = new TaskCompletionSource<Request>(TaskCreationOptions.RunContinuationsAsynchronously);1627 void requestEventListener(object sender, RequestEventArgs e)1628 {1629 if (predicate(e.Request))1630 {1631 requestTcs.TrySetResult(e.Request);1632 FrameManager.NetworkManager.Request -= requestEventListener;1633 }1634 }1635 FrameManager.NetworkManager.Request += requestEventListener;1636 await Task.WhenAny(requestTcs.Task, SessionClosedTask).WithTimeout(timeout, t =>1637 {1638 FrameManager.NetworkManager.Request -= requestEventListener;1639 return new TimeoutException($"Timeout of {t.TotalMilliseconds} ms exceeded");1640 }).ConfigureAwait(false);1641 if (SessionClosedTask.IsFaulted)1642 {1643 await SessionClosedTask.ConfigureAwait(false);1644 }1645 return await requestTcs.Task.ConfigureAwait(false);1646 }1647 /// <summary>1648 /// Waits for a response.1649 /// </summary>1650 /// <example>1651 /// <code>1652 /// <![CDATA[1653 /// var firstResponse = await page.WaitForResponseAsync("http://example.com/resource");1654 /// return firstResponse.Url;1655 /// ]]>1656 /// </code>1657 /// </example>1658 /// <returns>A task which resolves when a matching response is received.</returns>1659 /// <param name="url">URL to wait for.</param>1660 /// <param name="options">Options.</param>1661 public Task<Response> WaitForResponseAsync(string url, WaitForOptions options = null)1662 => WaitForResponseAsync(response => response.Url == url, options);1663 /// <summary>1664 /// Waits for a response.1665 /// </summary>1666 /// <example>1667 /// <code>1668 /// <![CDATA[1669 /// var response = await page.WaitForResponseAsync(response => response.Url === "http://example.com" && response.Status === HttpStatus.Ok;1670 /// return response.Url;1671 /// ]]>1672 /// </code>1673 /// </example>1674 /// <returns>A task which resolves when a matching response is received.</returns>1675 /// <param name="predicate">Function which looks for a matching response.</param>1676 /// <param name="options">Options.</param>1677 public async Task<Response> WaitForResponseAsync(Func<Response, bool> predicate, WaitForOptions options = null)1678 {1679 var timeout = options?.Timeout ?? DefaultTimeout;1680 var responseTcs = new TaskCompletionSource<Response>(TaskCreationOptions.RunContinuationsAsynchronously);1681 void responseEventListener(object sender, ResponseCreatedEventArgs e)1682 {1683 if (predicate(e.Response))1684 {1685 responseTcs.TrySetResult(e.Response);1686 FrameManager.NetworkManager.Response -= responseEventListener;1687 }1688 }1689 FrameManager.NetworkManager.Response += responseEventListener;1690 await Task.WhenAny(responseTcs.Task, SessionClosedTask).WithTimeout(timeout).ConfigureAwait(false);1691 if (SessionClosedTask.IsFaulted)1692 {1693 await SessionClosedTask.ConfigureAwait(false);1694 }1695 return await responseTcs.Task.ConfigureAwait(false);1696 }1697 /// <summary>1698 /// Waits for a page to open a file picker1699 /// </summary>1700 /// <remarks>1701 /// In non-headless Chromium, this method results in the native file picker dialog **not showing up** for the user.1702 /// </remarks>1703 /// <example>1704 /// This method is typically coupled with an action that triggers file choosing.1705 /// The following example clicks a button that issues a file chooser, and then1706 /// responds with `/tmp/myfile.pdf` as if a user has selected this file.1707 /// <code>1708 /// <![CDATA[1709 /// var waitTask = page.WaitForFileChooserAsync();1710 /// await Task.WhenAll(1711 /// waitTask,1712 /// page.ClickAsync("#upload-file-button")); // some button that triggers file selection1713 ///1714 /// await waitTask.Result.AcceptAsync('/tmp/myfile.pdf');1715 /// ]]>1716 /// </code>1717 ///1718 /// This must be called *before* the file chooser is launched. It will not return a currently active file chooser.1719 /// </example>1720 /// <param name="options">Optional waiting parameters.</param>1721 /// <returns>A task that resolves after a page requests a file picker.</returns>1722 public async Task<FileChooser> WaitForFileChooserAsync(WaitForFileChooserOptions options = null)1723 {1724 if (!_fileChooserInterceptors.Any())1725 {1726 await Client.SendAsync("Page.setInterceptFileChooserDialog", new PageSetInterceptFileChooserDialog1727 {1728 Enabled = true1729 }).ConfigureAwait(false);1730 }1731 var timeout = options?.Timeout ?? _timeoutSettings.Timeout;1732 var tcs = new TaskCompletionSource<FileChooser>(TaskCreationOptions.RunContinuationsAsynchronously);1733 var guid = Guid.NewGuid();1734 _fileChooserInterceptors.TryAdd(guid, tcs);1735 try1736 {1737 return await tcs.Task.WithTimeout(timeout).ConfigureAwait(false);1738 }1739 catch (Exception)1740 {1741 _fileChooserInterceptors.TryRemove(guid, out _);1742 throw;1743 }1744 }1745 /// <summary>1746 /// Navigate to the previous page in history.1747 /// </summary>1748 /// <returns>Task that resolves to the main resource response. In case of multiple redirects,1749 /// the navigation will resolve with the response of the last redirect. If can not go back, resolves to null.</returns>1750 /// <param name="options">Navigation parameters.</param>1751 public Task<Response> GoBackAsync(NavigationOptions options = null) => GoAsync(-1, options);1752 /// <summary>1753 /// Navigate to the next page in history.1754 /// </summary>1755 /// <returns>Task that resolves to the main resource response. In case of multiple redirects,1756 /// the navigation will resolve with the response of the last redirect. If can not go forward, resolves to null.</returns>1757 /// <param name="options">Navigation parameters.</param>1758 public Task<Response> GoForwardAsync(NavigationOptions options = null) => GoAsync(1, options);1759 /// <summary>1760 /// Resets the background color and Viewport after taking Screenshots using BurstMode.1761 /// </summary>1762 /// <returns>The burst mode off.</returns>1763 public Task SetBurstModeOffAsync()1764 {1765 _screenshotBurstModeOn = false;1766 if (_screenshotBurstModeOptions != null)1767 {1768 ResetBackgroundColorAndViewportAsync(_screenshotBurstModeOptions);1769 }1770 return Task.CompletedTask;1771 }1772 /// <summary>1773 /// Brings page to front (activates tab).1774 /// </summary>1775 /// <returns>A task that resolves when the message has been sent to Chromium.</returns>1776 public Task BringToFrontAsync() => Client.SendAsync("Page.bringToFront");1777 /// <summary>1778 /// Simulates the given vision deficiency on the page.1779 /// </summary>1780 /// <example>1781 /// await Page.EmulateVisionDeficiencyAsync(VisionDeficiency.Achromatopsia);1782 /// await Page.ScreenshotAsync("Achromatopsia.png");1783 /// </example>1784 /// <param name="type">The type of deficiency to simulate, or <see cref="VisionDeficiency.None"/> to reset.</param>1785 /// <returns>A task that resolves when the message has been sent to the browser.</returns>1786 public Task EmulateVisionDeficiencyAsync(VisionDeficiency type)1787 => Client.SendAsync("Emulation.setEmulatedVisionDeficiency", new EmulationSetEmulatedVisionDeficiencyRequest1788 {1789 Type = type,1790 });1791 /// <summary>1792 /// Changes the timezone of the page.1793 /// </summary>1794 /// <param name="timezoneId">Timezone to set. See <seealso href="https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1" >ICUâs `metaZones.txt`</seealso>1795 /// for a list of supported timezone IDs. Passing `null` disables timezone emulation.</param>1796 /// <returns>The viewport task.</returns>1797 public async Task EmulateTimezoneAsync(string timezoneId)1798 {1799 try1800 {1801 await Client.SendAsync("Emulation.setTimezoneOverride", new EmulateTimezoneRequest1802 {1803 TimezoneId = timezoneId ?? string.Empty1804 }).ConfigureAwait(false);1805 }1806 catch (Exception ex) when (ex.Message.Contains("Invalid timezone"))1807 {1808 throw new PuppeteerException($"Invalid timezone ID: {timezoneId}");1809 }1810 }1811 /// <summary>1812 /// Emulates the idle state.1813 /// If no arguments set, clears idle state emulation.1814 /// </summary>1815 /// <example>1816 /// <code>1817 /// // set idle emulation1818 /// await page.EmulateIdleStateAsync(new EmulateIdleOverrides() {IsUserActive = true, IsScreenUnlocked = false});1819 /// // do some checks here1820 /// ...1821 /// // clear idle emulation1822 /// await page.EmulateIdleStateAsync();1823 /// </code>1824 /// </example>1825 /// <param name="overrides">Overrides</param>1826 /// <returns>A task that resolves when the message has been sent to the browser.</returns>1827 public async Task EmulateIdleStateAsync(EmulateIdleOverrides overrides = null)1828 {1829 if (overrides != null)1830 {1831 await Client.SendAsync(1832 "Emulation.setIdleOverride",1833 new EmulationSetIdleOverrideRequest1834 {1835 IsUserActive = overrides.IsUserActive,1836 IsScreenUnlocked = overrides.IsScreenUnlocked,1837 }).ConfigureAwait(false);1838 }1839 else1840 {1841 await Client.SendAsync("Emulation.clearIdleOverride").ConfigureAwait(false);1842 }1843 }1844 /// <summary>1845 /// Enables CPU throttling to emulate slow CPUs.1846 /// </summary>1847 /// <param name="factor">Throttling rate as a slowdown factor (1 is no throttle, 2 is 2x slowdown, etc).</param>1848 /// <returns>A task that resolves when the message has been sent to the browser.</returns>1849 public Task EmulateCPUThrottlingAsync(decimal? factor = null)1850 {1851 if (factor != null && factor < 1)1852 {1853 throw new ArgumentException("Throttling rate should be greater or equal to 1", nameof(factor));1854 }1855 return Client.SendAsync("Emulation.setCPUThrottlingRate", new EmulationSetCPUThrottlingRateRequest1856 {1857 Rate = factor ?? 11858 });1859 }1860 internal void OnPopup(Page popupPage) => Popup?.Invoke(this, new PopupEventArgs { PopupPage = popupPage });1861 internal static async Task<Page> CreateAsync(1862 CDPSession client,1863 Target target,1864 bool ignoreHTTPSErrors,1865 ViewPortOptions defaultViewPort,1866 TaskQueue screenshotTaskQueue)1867 {1868 var page = new Page(client, target, screenshotTaskQueue);1869 await page.InitializeAsync(ignoreHTTPSErrors).ConfigureAwait(false);1870 if (defaultViewPort != null)1871 {1872 await page.SetViewportAsync(defaultViewPort).ConfigureAwait(false);1873 }1874 return page;1875 }1876 private async Task InitializeAsync(bool ignoreHTTPSErrors)1877 {1878 FrameManager = await FrameManager.CreateFrameManagerAsync(Client, this, ignoreHTTPSErrors, _timeoutSettings).ConfigureAwait(false);1879 var networkManager = FrameManager.NetworkManager;1880 Client.MessageReceived += Client_MessageReceived;1881 FrameManager.FrameAttached += (_, e) => FrameAttached?.Invoke(this, e);1882 FrameManager.FrameDetached += (_, e) => FrameDetached?.Invoke(this, e);1883 FrameManager.FrameNavigated += (_, e) => FrameNavigated?.Invoke(this, e);1884 networkManager.Request += (_, e) => Request?.Invoke(this, e);1885 networkManager.RequestFailed += (_, e) => RequestFailed?.Invoke(this, e);1886 networkManager.Response += (_, e) => Response?.Invoke(this, e);1887 networkManager.RequestFinished += (_, e) => RequestFinished?.Invoke(this, e);1888 networkManager.RequestServedFromCache += (_, e) => RequestServedFromCache?.Invoke(this, e);1889 await Task.WhenAll(1890 Client.SendAsync("Target.setAutoAttach", new TargetSetAutoAttachRequest1891 {1892 AutoAttach = true,1893 WaitForDebuggerOnStart = false,1894 Flatten = true1895 }),1896 Client.SendAsync("Performance.enable", null),1897 Client.SendAsync("Log.enable", null)).ConfigureAwait(false);1898 }1899 private async Task<Response> GoAsync(int delta, NavigationOptions options)1900 {1901 var history = await Client.SendAsync<PageGetNavigationHistoryResponse>("Page.getNavigationHistory").ConfigureAwait(false);1902 if (history.Entries.Count <= history.CurrentIndex + delta || history.CurrentIndex + delta < 0)1903 {1904 return null;1905 }1906 var entry = history.Entries[history.CurrentIndex + delta];1907 var waitTask = WaitForNavigationAsync(options);1908 await Task.WhenAll(1909 waitTask,1910 Client.SendAsync("Page.navigateToHistoryEntry", new PageNavigateToHistoryEntryRequest1911 {1912 EntryId = entry.Id1913 })).ConfigureAwait(false);1914 return waitTask.Result;1915 }1916 private Dictionary<string, decimal> BuildMetricsObject(List<Metric> metrics)1917 {1918 var result = new Dictionary<string, decimal>();1919 foreach (var item in metrics)1920 {1921 if (SupportedMetrics.Contains(item.Name))1922 {1923 result.Add(item.Name, item.Value);1924 }1925 }1926 return result;1927 }1928 private async Task<string> PerformScreenshot(ScreenshotType type, ScreenshotOptions options)1929 {1930 if (!_screenshotBurstModeOn)1931 {1932 await Client.SendAsync("Target.activateTarget", new TargetActivateTargetRequest1933 {1934 TargetId = Target.TargetId1935 }).ConfigureAwait(false);1936 }1937 var clip = options.Clip != null ? ProcessClip(options.Clip) : null;1938 if (!_screenshotBurstModeOn)1939 {1940 if (options != null && options.FullPage)1941 {1942 var metrics = _screenshotBurstModeOn1943 ? _burstModeMetrics :1944 await Client.SendAsync<PageGetLayoutMetricsResponse>("Page.getLayoutMetrics").ConfigureAwait(false);1945 if (options.BurstMode)1946 {1947 _burstModeMetrics = metrics;1948 }1949 var contentSize = metrics.ContentSize;1950 var width = Convert.ToInt32(Math.Ceiling(contentSize.Width));1951 var height = Convert.ToInt32(Math.Ceiling(contentSize.Height));1952 // Overwrite clip for full page at all times.1953 clip = new Clip1954 {1955 X = 0,1956 Y = 0,1957 Width = width,1958 Height = height,1959 Scale = 11960 };1961 var isMobile = Viewport?.IsMobile ?? false;1962 var deviceScaleFactor = Viewport?.DeviceScaleFactor ?? 1;1963 var isLandscape = Viewport?.IsLandscape ?? false;1964 var screenOrientation = isLandscape ?1965 new ScreenOrientation1966 {1967 Angle = 90,1968 Type = ScreenOrientationType.LandscapePrimary1969 } :1970 new ScreenOrientation1971 {1972 Angle = 0,1973 Type = ScreenOrientationType.PortraitPrimary1974 };1975 await Client.SendAsync("Emulation.setDeviceMetricsOverride", new EmulationSetDeviceMetricsOverrideRequest1976 {1977 Mobile = isMobile,1978 Width = width,1979 Height = height,1980 DeviceScaleFactor = deviceScaleFactor,1981 ScreenOrientation = screenOrientation1982 }).ConfigureAwait(false);1983 }1984 if (options?.OmitBackground == true && type == ScreenshotType.Png)1985 {1986 await SetTransparentBackgroundColorAsync().ConfigureAwait(false);1987 }1988 }1989 var screenMessage = new PageCaptureScreenshotRequest1990 {1991 Format = type.ToString().ToLower(CultureInfo.CurrentCulture)1992 };1993 if (options.Quality.HasValue)1994 {1995 screenMessage.Quality = options.Quality.Value;1996 }1997 if (clip != null)1998 {1999 screenMessage.Clip = clip;2000 }2001 var result = await Client.SendAsync<PageCaptureScreenshotResponse>("Page.captureScreenshot", screenMessage).ConfigureAwait(false);2002 if (options.BurstMode)2003 {2004 _screenshotBurstModeOptions = options;2005 _screenshotBurstModeOn = true;2006 }2007 else2008 {2009 await ResetBackgroundColorAndViewportAsync(options).ConfigureAwait(false);2010 }2011 return result.Data;2012 }2013 private Clip ProcessClip(Clip clip)2014 {2015 var x = Math.Round(clip.X);2016 var y = Math.Round(clip.Y);2017 return new Clip2018 {2019 X = x,2020 Y = y,2021 Width = Math.Round(clip.Width + clip.X - x, MidpointRounding.AwayFromZero),2022 Height = Math.Round(clip.Height + clip.Y - y, MidpointRounding.AwayFromZero),2023 Scale = clip.Scale2024 };2025 }2026 private Task ResetBackgroundColorAndViewportAsync(ScreenshotOptions options)2027 {2028 var omitBackgroundTask = options?.OmitBackground == true && options.Type == ScreenshotType.Png ?2029 ResetDefaultBackgroundColorAsync() : Task.CompletedTask;2030 var setViewPortTask = (options?.FullPage == true && Viewport != null) ?2031 SetViewportAsync(Viewport) : Task.CompletedTask;2032 return Task.WhenAll(omitBackgroundTask, setViewPortTask);2033 }2034 private Task ResetDefaultBackgroundColorAsync()2035 => Client.SendAsync("Emulation.setDefaultBackgroundColorOverride");2036 private Task SetTransparentBackgroundColorAsync()2037 => Client.SendAsync("Emulation.setDefaultBackgroundColorOverride", new EmulationSetDefaultBackgroundColorOverrideRequest2038 {2039 Color = new EmulationSetDefaultBackgroundColorOverrideColor2040 {2041 R = 0,2042 G = 0,2043 B = 0,2044 A = 02045 }2046 });2047 private decimal ConvertPrintParameterToInches(object parameter)2048 {2049 if (parameter == null)2050 {2051 return 0;2052 }2053 decimal pixels;2054 if (parameter is decimal || parameter is int)2055 {2056 pixels = Convert.ToDecimal(parameter, CultureInfo.CurrentCulture);2057 }2058 else2059 {2060 var text = parameter.ToString();2061 var unit = text.Substring(text.Length - 2).ToLower(CultureInfo.CurrentCulture);2062 string valueText;2063 if (_unitToPixels.ContainsKey(unit))2064 {2065 valueText = text.Substring(0, text.Length - 2);2066 }2067 else2068 {2069 // In case of unknown unit try to parse the whole parameter as number of pixels.2070 // This is consistent with phantom's paperSize behavior.2071 unit = "px";2072 valueText = text;2073 }2074 if (decimal.TryParse(valueText, NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat, out var number))2075 {2076 pixels = number * _unitToPixels[unit];2077 }2078 else2079 {2080 throw new ArgumentException($"Failed to parse parameter value: '{text}'", nameof(parameter));2081 }2082 }2083 return pixels / 96;2084 }2085 private async void Client_MessageReceived(object sender, MessageEventArgs e)2086 {2087 try2088 {2089 switch (e.MessageID)2090 {2091 case "Page.domContentEventFired":2092 DOMContentLoaded?.Invoke(this, EventArgs.Empty);2093 break;2094 case "Page.loadEventFired":2095 Load?.Invoke(this, EventArgs.Empty);2096 break;2097 case "Runtime.consoleAPICalled":2098 await OnConsoleAPIAsync(e.MessageData.ToObject<PageConsoleResponse>(true)).ConfigureAwait(false);2099 break;2100 case "Page.javascriptDialogOpening":2101 OnDialog(e.MessageData.ToObject<PageJavascriptDialogOpeningResponse>(true));2102 break;2103 case "Runtime.exceptionThrown":2104 HandleException(e.MessageData.ToObject<RuntimeExceptionThrownResponse>(true).ExceptionDetails);2105 break;2106 case "Inspector.targetCrashed":2107 OnTargetCrashed();2108 break;2109 case "Performance.metrics":2110 EmitMetrics(e.MessageData.ToObject<PerformanceMetricsResponse>(true));2111 break;2112 case "Target.attachedToTarget":2113 await OnAttachedToTargetAsync(e.MessageData.ToObject<TargetAttachedToTargetResponse>(true)).ConfigureAwait(false);2114 break;2115 case "Target.detachedFromTarget":2116 OnDetachedFromTarget(e.MessageData.ToObject<TargetDetachedFromTargetResponse>(true));2117 break;2118 case "Log.entryAdded":2119 await OnLogEntryAddedAsync(e.MessageData.ToObject<LogEntryAddedResponse>(true)).ConfigureAwait(false);2120 break;2121 case "Runtime.bindingCalled":2122 await OnBindingCalled(e.MessageData.ToObject<BindingCalledResponse>(true)).ConfigureAwait(false);2123 break;2124 case "Page.fileChooserOpened":2125 await OnFileChooserAsync(e.MessageData.ToObject<PageFileChooserOpenedResponse>(true)).ConfigureAwait(false);2126 break;2127 }2128 }2129 catch (Exception ex)2130 {2131 var message = $"Page failed to process {e.MessageID}. {ex.Message}. {ex.StackTrace}";2132 _logger.LogError(ex, message);2133 Client.Close(message);2134 }2135 }2136 private async Task OnFileChooserAsync(PageFileChooserOpenedResponse e)2137 {2138 if (_fileChooserInterceptors.Count == 0)2139 {2140 try2141 {2142 await Client.SendAsync("Page.handleFileChooser", new PageHandleFileChooserRequest2143 {2144 Action = FileChooserAction.Fallback2145 }).ConfigureAwait(false);2146 return;2147 }2148 catch (Exception ex)2149 {2150 _logger.LogError(ex, ex.ToString());2151 }2152 }2153 var frame = await FrameManager.GetFrameAsync(e.FrameId).ConfigureAwait(false);2154 var context = await frame.GetExecutionContextAsync().ConfigureAwait(false);2155 var element = await context.AdoptBackendNodeAsync(e.BackendNodeId).ConfigureAwait(false);2156 var fileChooser = new FileChooser(element, e);2157 while (_fileChooserInterceptors.Count > 0)2158 {2159 var key = _fileChooserInterceptors.FirstOrDefault().Key;2160 if (_fileChooserInterceptors.TryRemove(key, out var tcs))2161 {2162 tcs.TrySetResult(fileChooser);2163 }2164 }2165 }2166 private async Task OnBindingCalled(BindingCalledResponse e)2167 {2168 string expression;2169 try2170 {2171 var result = await ExecuteBinding(e).ConfigureAwait(false);2172 expression = EvaluationString(2173 @"function deliverResult(name, seq, result) {2174 window[name]['callbacks'].get(seq).resolve(result);2175 window[name]['callbacks'].delete(seq);2176 }",2177 e.BindingPayload.Name,2178 e.BindingPayload.Seq,2179 result);2180 }2181 catch (Exception ex)2182 {2183 if (ex is TargetInvocationException)2184 {2185 ex = ex.InnerException;2186 }2187 expression = EvaluationString(2188 @"function deliverError(name, seq, message, stack) {2189 const error = new Error(message);2190 error.stack = stack;2191 window[name]['callbacks'].get(seq).reject(error);2192 window[name]['callbacks'].delete(seq);2193 }",2194 e.BindingPayload.Name,2195 e.BindingPayload.Seq,2196 ex.Message,2197 ex.StackTrace);2198 }2199 Client.Send("Runtime.evaluate", new2200 {2201 expression,2202 contextId = e.ExecutionContextId2203 });2204 }2205 private async Task<object> ExecuteBinding(BindingCalledResponse e)2206 {2207 const string taskResultPropertyName = "Result";2208 object result;2209 var binding = _pageBindings[e.BindingPayload.Name];2210 var methodParams = binding.Method.GetParameters().Select(parameter => parameter.ParameterType).ToArray();2211 var args = e.BindingPayload.Args.Select((token, i) => token.ToObject(methodParams[i])).ToArray();2212 result = binding.DynamicInvoke(args);2213 if (result is Task taskResult)2214 {2215 await taskResult.ConfigureAwait(false);2216 if (taskResult.GetType().IsGenericType)2217 {2218 // the task is already awaited and therefore the call to property Result will not deadlock2219 result = taskResult.GetType().GetProperty(taskResultPropertyName).GetValue(taskResult);2220 }2221 }2222 return result;2223 }2224 private void OnDetachedFromTarget(TargetDetachedFromTargetResponse e)2225 {2226 var sessionId = e.SessionId;2227 if (_workers.TryGetValue(sessionId, out var worker))2228 {2229 WorkerDestroyed?.Invoke(this, new WorkerEventArgs(worker));2230 _workers.Remove(sessionId);2231 }2232 }2233 private async Task OnAttachedToTargetAsync(TargetAttachedToTargetResponse e)2234 {2235 var targetInfo = e.TargetInfo;2236 var sessionId = e.SessionId;2237 if (targetInfo.Type != TargetType.Worker && targetInfo.Type != TargetType.iFrame)2238 {2239 try2240 {2241 await Client.SendAsync("Target.detachFromTarget", new TargetDetachFromTargetRequest2242 {2243 SessionId = sessionId2244 }).ConfigureAwait(false);2245 }2246 catch (Exception ex)2247 {2248 _logger.LogError(ex.ToString());2249 }2250 return;2251 }2252 var session = Connection.FromSession(Client).GetSession(sessionId);2253 var worker = new Worker(session, targetInfo.Url, AddConsoleMessageAsync, HandleException);2254 _workers[sessionId] = worker;2255 WorkerCreated?.Invoke(this, new WorkerEventArgs(worker));2256 }2257 private async Task OnLogEntryAddedAsync(LogEntryAddedResponse e)2258 {2259 if (e.Entry.Args != null)2260 {2261 foreach (var arg in e.Entry?.Args)2262 {2263 await RemoteObjectHelper.ReleaseObjectAsync(Client, arg, _logger).ConfigureAwait(false);2264 }2265 }2266 if (e.Entry.Source != TargetType.Worker)2267 {2268 Console?.Invoke(this, new ConsoleEventArgs(new ConsoleMessage(2269 e.Entry.Level,2270 e.Entry.Text,2271 null,2272 new ConsoleMessageLocation2273 {2274 URL = e.Entry.URL,2275 LineNumber = e.Entry.LineNumber2276 })));2277 }2278 }2279 private void OnTargetCrashed()2280 {2281 if (Error == null)2282 {2283 throw new TargetCrashedException();2284 }2285 Error.Invoke(this, new ErrorEventArgs("Page crashed!"));2286 }2287 private void EmitMetrics(PerformanceMetricsResponse metrics)2288 => Metrics?.Invoke(this, new MetricEventArgs(metrics.Title, BuildMetricsObject(metrics.Metrics)));2289 private void HandleException(EvaluateExceptionResponseDetails exceptionDetails)2290 => PageError?.Invoke(this, new PageErrorEventArgs(GetExceptionMessage(exceptionDetails)));2291 private string GetExceptionMessage(EvaluateExceptionResponseDetails exceptionDetails)2292 {2293 if (exceptionDetails.Exception != null)2294 {2295 return exceptionDetails.Exception.Description;2296 }2297 var message = exceptionDetails.Text;2298 if (exceptionDetails.StackTrace != null)2299 {2300 foreach (var callframe in exceptionDetails.StackTrace.CallFrames)2301 {2302 var location = $"{callframe.Url}:{callframe.LineNumber}:{callframe.ColumnNumber}";2303 var functionName = callframe.FunctionName ?? "<anonymous>";2304 message += $"\n at {functionName} ({location})";2305 }2306 }2307 return message;2308 }2309 private void OnDialog(PageJavascriptDialogOpeningResponse message)2310 {2311 var dialog = new Dialog(Client, message.Type, message.Message, message.DefaultPrompt);2312 Dialog?.Invoke(this, new DialogEventArgs(dialog));2313 }2314 private Task OnConsoleAPIAsync(PageConsoleResponse message)2315 {2316 if (message.ExecutionContextId == 0)2317 {2318 return Task.CompletedTask;2319 }2320 var ctx = FrameManager.ExecutionContextById(message.ExecutionContextId);2321 var values = message.Args.Select(ctx.CreateJSHandle).ToArray();2322 return AddConsoleMessageAsync(message.Type, values, message.StackTrace);2323 }2324 private async Task AddConsoleMessageAsync(ConsoleType type, JSHandle[] values, Messaging.StackTrace stackTrace)2325 {2326 if (Console?.GetInvocationList().Length == 0)2327 {2328 await Task.WhenAll(values.Select(v => RemoteObjectHelper.ReleaseObjectAsync(Client, v.RemoteObject, _logger))).ConfigureAwait(false);2329 return;2330 }2331 var tokens = values.Select(i => i.RemoteObject.ObjectId != null2332 ? i.ToString()2333 : RemoteObjectHelper.ValueFromRemoteObject<string>(i.RemoteObject));2334 var location = new ConsoleMessageLocation();2335 if (stackTrace?.CallFrames?.Length > 0)2336 {2337 var callFrame = stackTrace.CallFrames[0];2338 location.URL = callFrame.URL;2339 location.LineNumber = callFrame.LineNumber;2340 location.ColumnNumber = callFrame.ColumnNumber;2341 }2342 var consoleMessage = new ConsoleMessage(type, string.Join(" ", tokens), values, location);2343 Console?.Invoke(this, new ConsoleEventArgs(consoleMessage));2344 }2345 private async Task ExposeFunctionAsync(string name, Delegate puppeteerFunction)2346 {2347 if (_pageBindings.ContainsKey(name))2348 {2349 throw new PuppeteerException($"Failed to add page binding with name {name}: window['{name}'] already exists!");2350 }2351 _pageBindings.Add(name, puppeteerFunction);2352 const string addPageBinding = @"function addPageBinding(bindingName) {2353 const binding = window[bindingName];2354 window[bindingName] = (...args) => {2355 const me = window[bindingName];2356 let callbacks = me['callbacks'];2357 if (!callbacks) {2358 callbacks = new Map();2359 me['callbacks'] = callbacks;2360 }2361 const seq = (me['lastSeq'] || 0) + 1;2362 me['lastSeq'] = seq;2363 const promise = new Promise((resolve, reject) => callbacks.set(seq, {resolve, reject}));2364 binding(JSON.stringify({name: bindingName, seq, args}));2365 return promise;2366 };2367 }";2368 var expression = EvaluationString(addPageBinding, name);2369 await Client.SendAsync("Runtime.addBinding", new RuntimeAddBindingRequest { Name = name }).ConfigureAwait(false);2370 await Client.SendAsync("Page.addScriptToEvaluateOnNewDocument", new PageAddScriptToEvaluateOnNewDocumentRequest2371 {2372 Source = expression2373 }).ConfigureAwait(false);2374 await Task.WhenAll(Frames.Select(2375 frame => frame2376 .EvaluateExpressionAsync(expression)2377 .ContinueWith(2378 task =>2379 {2380 if (task.IsFaulted)2381 {2382 _logger.LogError(task.Exception.ToString());2383 }2384 },2385 TaskScheduler.Default)))2386 .ConfigureAwait(false);2387 }2388 private static string EvaluationString(string fun, params object[] args)2389 {2390 return $"({fun})({string.Join(",", args.Select(SerializeArgument))})";2391 string SerializeArgument(object arg)2392 {2393 return arg == null2394 ? "undefined"2395 : JsonConvert.SerializeObject(arg, JsonHelper.DefaultJsonSerializerSettings);2396 }2397 }2398 /// <inheritdoc />2399 public void Dispose()2400 {2401 Dispose(true);2402 GC.SuppressFinalize(this);2403 }2404 /// <summary>2405 /// Releases all resource used by the <see cref="Page"/> object by calling the <see cref="CloseAsync"/> method.2406 /// </summary>2407 /// <remarks>Call <see cref="Dispose()"/> when you are finished using the <see cref="Page"/>. The2408 /// <see cref="Dispose()"/> method leaves the <see cref="Page"/> in an unusable state. After2409 /// calling <see cref="Dispose()"/>, you must release all references to the <see cref="Page"/> so2410 /// the garbage collector can reclaim the memory that the <see cref="Page"/> was occupying.</remarks>2411 /// <param name="disposing">Indicates whether disposal was initiated by <see cref="Dispose()"/> operation.</param>2412 protected virtual void Dispose(bool disposing)2413 => _ = DisposeAsync();2414 /// <summary>2415 /// Releases all resource used by the <see cref="Page"/> object by calling the <see cref="CloseAsync"/> method.2416 /// </summary>2417 /// <remarks>Call <see cref="DisposeAsync"/> when you are finished using the <see cref="Page"/>. The2418 /// <see cref="DisposeAsync"/> method leaves the <see cref="Page"/> in an unusable state. After2419 /// calling <see cref="DisposeAsync"/>, you must release all references to the <see cref="Page"/> so2420 /// the garbage collector can reclaim the memory that the <see cref="Page"/> was occupying.</remarks>2421 /// <returns>ValueTask</returns>2422 public ValueTask DisposeAsync() => new ValueTask(CloseAsync());2423 }2424}...
Frame.cs
Source:Frame.cs
...246 return null;247 }248 var mainExecutionContext = await MainWorld.GetExecutionContextAsync().ConfigureAwait(false);249 var result = await mainExecutionContext.AdoptElementHandleASync(handle).ConfigureAwait(false);250 await handle.DisposeAsync().ConfigureAwait(false);251 return result;252 }253 /// <summary>254 /// Waits for a selector to be added to the DOM255 /// </summary>256 /// <param name="xpath">A xpath selector of an element to wait for</param>257 /// <param name="options">Optional waiting parameters</param>258 /// <returns>A task which resolves when element specified by xpath string is added to DOM. 259 /// Resolves to `null` if waiting for `hidden: true` and xpath is not found in DOM.</returns>260 /// <example>261 /// <code>262 /// <![CDATA[263 /// var browser = await Puppeteer.LaunchAsync(new LaunchOptions());264 /// var page = await browser.NewPageAsync();265 /// string currentURL = null;266 /// page.MainFrame267 /// .WaitForXPathAsync("//img")268 /// .ContinueWith(_ => Console.WriteLine("First URL with image: " + currentURL));269 /// foreach (var current in new[] { "https://example.com", "https://google.com", "https://bbc.com" })270 /// {271 /// currentURL = current;272 /// await page.GoToAsync(currentURL);273 /// }274 /// await browser.CloseAsync();275 /// ]]>276 /// </code>277 /// </example>278 /// <seealso cref="WaitForSelectorAsync(string, WaitForSelectorOptions)"/>279 /// <seealso cref="Page.WaitForXPathAsync(string, WaitForSelectorOptions)"/>280 /// <exception cref="WaitTaskTimeoutException">If timeout occurred.</exception>281 public async Task<ElementHandle> WaitForXPathAsync(string xpath, WaitForSelectorOptions options = null)282 {283 var handle = await SecondaryWorld.WaitForXPathAsync(xpath, options).ConfigureAwait(false);284 if (handle == null)285 {286 return null;287 }288 var mainExecutionContext = await MainWorld.GetExecutionContextAsync().ConfigureAwait(false);289 var result = await mainExecutionContext.AdoptElementHandleASync(handle).ConfigureAwait(false);290 await handle.DisposeAsync().ConfigureAwait(false);291 return result;292 }293 /// <summary>294 /// Waits for a timeout295 /// </summary>296 /// <param name="milliseconds"></param>297 /// <returns>A task that resolves when after the timeout</returns>298 /// <seealso cref="Page.WaitForTimeoutAsync(int)"/>299 /// <exception cref="WaitTaskTimeoutException">If timeout occurred.</exception>300 public Task WaitForTimeoutAsync(int milliseconds) => Task.Delay(milliseconds);301 /// <summary>302 /// Waits for a function to be evaluated to a truthy value303 /// </summary>304 /// <param name="script">Function to be evaluated in browser context</param>...
DOMWorld.cs
Source:DOMWorld.cs
...254 {255 throw new SelectorException($"No node found for selector: {selector}", selector);256 }257 await handle.ClickAsync(options).ConfigureAwait(false);258 await handle.DisposeAsync().ConfigureAwait(false);259 }260 internal async Task HoverAsync(string selector)261 {262 var handle = await QuerySelectorAsync(selector).ConfigureAwait(false);263 if (handle == null)264 {265 throw new SelectorException($"No node found for selector: {selector}", selector);266 }267 await handle.HoverAsync().ConfigureAwait(false);268 await handle.DisposeAsync().ConfigureAwait(false);269 }270 internal async Task FocusAsync(string selector)271 {272 var handle = await QuerySelectorAsync(selector).ConfigureAwait(false);273 if (handle == null)274 {275 throw new SelectorException($"No node found for selector: {selector}", selector);276 }277 await handle.FocusAsync().ConfigureAwait(false);278 await handle.DisposeAsync().ConfigureAwait(false);279 }280 internal async Task<string[]> SelectAsync(string selector, params string[] values)281 {282 if (!((await QuerySelectorAsync(selector).ConfigureAwait(false)) is ElementHandle handle))283 {284 throw new SelectorException($"No node found for selector: {selector}", selector);285 }286 var result = await handle.SelectAsync(values).ConfigureAwait(false);287 await handle.DisposeAsync().ConfigureAwait(false);288 return result;289 }290 internal async Task TapAsync(string selector)291 {292 var handle = await QuerySelectorAsync(selector).ConfigureAwait(false);293 if (handle == null)294 {295 throw new SelectorException($"No node found for selector: {selector}", selector);296 }297 await handle.TapAsync().ConfigureAwait(false);298 await handle.DisposeAsync().ConfigureAwait(false);299 }300 internal async Task TypeAsync(string selector, string text, TypeOptions options = null)301 {302 var handle = await QuerySelectorAsync(selector).ConfigureAwait(false);303 if (handle == null)304 {305 throw new SelectorException($"No node found for selector: {selector}", selector);306 }307 await handle.TypeAsync(text, options).ConfigureAwait(false);308 await handle.DisposeAsync().ConfigureAwait(false);309 }310 internal Task<ElementHandle> WaitForSelectorAsync(string selector, WaitForSelectorOptions options = null)311 => WaitForSelectorOrXPathAsync(selector, false, options);312 internal Task<ElementHandle> WaitForXPathAsync(string xpath, WaitForSelectorOptions options = null)313 => WaitForSelectorOrXPathAsync(xpath, true, options);314 internal async Task<JSHandle> WaitForFunctionAsync(string script, WaitForFunctionOptions options, params object[] args)315 {316 using var waitTask = new WaitTask(317 this,318 script,319 false,320 "function",321 options.Polling,322 options.PollingInterval,323 options.Timeout ?? _timeoutSettings.Timeout,324 args);325 return await waitTask326 .Task327 .ConfigureAwait(false);328 }329 internal async Task<JSHandle> WaitForExpressionAsync(string script, WaitForFunctionOptions options)330 {331 using var waitTask = new WaitTask(332 this,333 script,334 true,335 "function",336 options.Polling,337 options.PollingInterval,338 options.Timeout ?? _timeoutSettings.Timeout);339 return await waitTask340 .Task341 .ConfigureAwait(false);342 }343 internal Task<string> GetTitleAsync() => EvaluateExpressionAsync<string>("document.title");344 private async Task<ElementHandle> GetDocument()345 {346 if (_documentCompletionSource == null)347 {348 _documentCompletionSource = new TaskCompletionSource<ElementHandle>(TaskCreationOptions.RunContinuationsAsynchronously);349 var context = await GetExecutionContextAsync().ConfigureAwait(false);350 var document = await context.EvaluateExpressionHandleAsync("document").ConfigureAwait(false);351 _documentCompletionSource.TrySetResult(document as ElementHandle);352 }353 return await _documentCompletionSource.Task.ConfigureAwait(false);354 }355 private async Task<ElementHandle> WaitForSelectorOrXPathAsync(string selectorOrXPath, bool isXPath, WaitForSelectorOptions options = null)356 {357 options = options ?? new WaitForSelectorOptions();358 var timeout = options.Timeout ?? _timeoutSettings.Timeout;359 const string predicate = @"360 function predicate(selectorOrXPath, isXPath, waitForVisible, waitForHidden) {361 const node = isXPath362 ? document.evaluate(selectorOrXPath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue363 : document.querySelector(selectorOrXPath);364 if (!node)365 return waitForHidden;366 if (!waitForVisible && !waitForHidden)367 return node;368 const element = node.nodeType === Node.TEXT_NODE ? node.parentElement : node;369 const style = window.getComputedStyle(element);370 const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox();371 const success = (waitForVisible === isVisible || waitForHidden === !isVisible);372 return success ? node : null;373 function hasVisibleBoundingBox() {374 const rect = element.getBoundingClientRect();375 return !!(rect.top || rect.bottom || rect.width || rect.height);376 }377 }";378 var polling = options.Visible || options.Hidden ? WaitForFunctionPollingOption.Raf : WaitForFunctionPollingOption.Mutation;379 using var waitTask = new WaitTask(380 this,381 predicate,382 false,383 $"{(isXPath ? "XPath" : "selector")} '{selectorOrXPath}'{(options.Hidden ? " to be hidden" : string.Empty)}",384 polling,385 null,386 timeout,387 new object[] { selectorOrXPath, isXPath, options.Visible, options.Hidden });388 var handle = await waitTask.Task.ConfigureAwait(false);389 if (!(handle is ElementHandle elementHandle))390 {391 if (handle != null)392 {393 await handle.DisposeAsync().ConfigureAwait(false);394 }395 return null;396 }397 return elementHandle;398 }399 }400}...
WaitTask.cs
Source:WaitTask.cs
...153 if (_terminated || runCount != _runCount)154 {155 if (success != null)156 {157 await success.DisposeAsync().ConfigureAwait(false);158 }159 return;160 }161 if (exception == null &&162 await _frame.EvaluateFunctionAsync<bool>("s => !s", success)163 .ContinueWith(task => task.IsFaulted || task.Result)164 .ConfigureAwait(false))165 {166 if (success != null)167 {168 await success.DisposeAsync().ConfigureAwait(false);169 }170 return;171 }172 if (exception?.Message.Contains("Execution context was destroyed") == true)173 {174 return;175 }176 if (exception?.Message.Contains("Cannot find context with specified id") == true)177 {178 return;179 }180 if (exception != null)181 {182 _taskCompletion.SetException(exception);...
Dispose
Using AI Code Generation
1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4{5 {6 static async Task Main(string[] args)7 {8 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);9 using (var browser = await Puppeteer.LaunchAsync())10 {11 var page = await browser.NewPageAsync();12 var waitTask = page.WaitForNavigationAsync();13 Console.WriteLine("Press enter to navigate to google.");14 Console.ReadLine();15 await waitTask;16 Console.WriteLine("Press enter to close the browser.");17 Console.ReadLine();18 }19 }20 }21}22using (var browser = Puppeteer.LaunchAsync().GetAwaiter().GetResult())23{24}
Dispose
Using AI Code Generation
1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4{5 {6 static async Task Main(string[] args)7 {8 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);9 using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true }))10 using (var page = await browser.NewPageAsync())11 {12 var task = page.WaitForNavigationAsync();13 await task;14 }15 }16 }17}18using System;19using System.Threading.Tasks;20using PuppeteerSharp;21{22 {23 static async Task Main(string[] args)24 {25 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);26 using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true }))27 using (var page = await browser.NewPageAsync())28 {29 var task = page.WaitForNavigationAsync();30 task.Dispose();31 }32 }33 }34}35using System;36using System.Threading.Tasks;37using PuppeteerSharp;38{39 {40 static async Task Main(string[] args)41 {42 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);43 using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true }))44 using (var page = await browser.NewPageAsync())45 {46 var task = page.WaitForNavigationAsync();47 task.Dispose();48 await task;49 }50 }51 }52}53using System;54using System.Threading.Tasks;55using PuppeteerSharp;56{57 {58 static async Task Main(string[] args)59 {60 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);61 using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions
Dispose
Using AI Code Generation
1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4{5 {6 static void Main(string[] args)7 {8 MainAsync().GetAwaiter().GetResult();9 }10 static async Task MainAsync()11 {12 using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true }))13 using (var page = await browser.NewPageAsync())14 {15 var waitTask = page.WaitForNavigationAsync();16 await page.ClickAsync("a[href='/intl/en/about/']");17 await waitTask;18 }19 }20 }21}22using System;23using System.Threading.Tasks;24using PuppeteerSharp;25{26 {27 static void Main(string[] args)28 {29 MainAsync().GetAwaiter().GetResult();30 }31 static async Task MainAsync()32 {33 using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true }))34 using (var page = await browser.NewPageAsync())35 {36 var waitTask = page.WaitForNavigationAsync();37 await page.ClickAsync("a[href='/intl/en/about/']");38 await waitTask;39 page.Dispose();40 }41 }42 }43}44using System;45using System.Threading.Tasks;46using PuppeteerSharp;47{48 {49 static void Main(string[] args)50 {51 MainAsync().GetAwaiter().GetResult();52 }53 static async Task MainAsync()54 {55 using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true }))56 using (var page = await browser.NewPageAsync())57 {58 var waitTask = page.WaitForNavigationAsync();59 await page.ClickAsync("a[href='/intl/en/about/']");60 await waitTask;61 browser.Dispose();62 }63 }64 }65}
Dispose
Using AI Code Generation
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 Args = new string[] { "--no-sandbox" }11 });12 var page = await browser.NewPageAsync();13 var waitTask = page.WaitForNavigationAsync();14 await waitTask.DisposeAsync();15 await browser.CloseAsync();16 }17 }18}
Dispose
Using AI Code Generation
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 LaunchOptions { Headless = false });9 var page = await browser.NewPageAsync();10 var waitTask = page.WaitForNavigationAsync();11 await page.EvaluateFunctionAsync("() => { document.getElementById('gbqfbb').click(); }");12 await waitTask;13 await waitTask.Dispose();14 await browser.CloseAsync();15 }16 }17}18PuppeteerSharp: How to use WaitForSelectorAsync() method?19PuppeteerSharp: How to use WaitForSelectorAsync() method?20PuppeteerSharp: How to use WaitForXPathAsync() method?21PuppeteerSharp: How to use WaitForXPathAsync() method?22PuppeteerSharp: How to use WaitForRequestAsync() method?23PuppeteerSharp: How to use WaitForRequestAsync() method?24PuppeteerSharp: How to use WaitForResponseAsync() method?25PuppeteerSharp: How to use WaitForResponseAsync() method?26PuppeteerSharp: How to use WaitForFunctionAsync() method?27PuppeteerSharp: How to use WaitForFunctionAsync() method?28PuppeteerSharp: How to use WaitForSelectorAsync() method with options?29PuppeteerSharp: How to use WaitForSelectorAsync() method with options?30PuppeteerSharp: How to use WaitForXPathAsync() method with options?31PuppeteerSharp: How to use WaitForXPathAsync() method with options?32PuppeteerSharp: How to use WaitForRequestAsync() method with options?33PuppeteerSharp: How to use WaitForRequestAsync() method with options?34PuppeteerSharp: How to use WaitForResponseAsync() method with options?35PuppeteerSharp: How to use WaitForResponseAsync() method with options?36PuppeteerSharp: How to use WaitForFunctionAsync() method with options?37PuppeteerSharp: How to use WaitForFunctionAsync() method with options?
Dispose
Using AI Code Generation
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 waitTask = page.WaitForNavigationAsync();13 await waitTask.DisposeAsync();14 await page.CloseAsync();15 await browser.CloseAsync();16 }17 }18}19How to use the PuppeteerSharp Page.WaitForNavigationAsync() method20How to use the PuppeteerSharp Page.WaitForSelectorAsync() method21How to use the PuppeteerSharp Page.WaitForXPathAsync() method22How to use the PuppeteerSharp Page.WaitForFunctionAsync() method23How to use the PuppeteerSharp Page.WaitForRequestAsync() method24How to use the PuppeteerSharp Page.WaitForResponseAsync() method25How to use the PuppeteerSharp Page.WaitForEventAsync() method26How to use the PuppeteerSharp Page.WaitForFileChooserAsync() method27How to use the PuppeteerSharp Page.WaitForTimeoutAsync() method28How to use the PuppeteerSharp Page.WaitForEventAsync() method29How to use the PuppeteerSharp Page.WaitForFunctionAsync() method30How to use the PuppeteerSharp Page.WaitForRequestAsync() method31How to use the PuppeteerSharp Page.WaitForResponseAsync() method32How to use the PuppeteerSharp Page.WaitForFileChooserAsync() method33How to use the PuppeteerSharp Page.WaitForTimeoutAsync() method34How to use the PuppeteerSharp Page.WaitForEventAsync() method35How to use the PuppeteerSharp Page.WaitForFunctionAsync() method36How to use the PuppeteerSharp Page.WaitForRequestAsync() method37How to use the PuppeteerSharp Page.WaitForResponseAsync() method38How to use the PuppeteerSharp Page.WaitForFileChooserAsync() method39How to use the PuppeteerSharp Page.WaitForTimeoutAsync() method
Dispose
Using AI Code Generation
1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4{5 {6 static async Task Main(string[] args)7 {8 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);9 {10 Args = new[] { "--no-sandbox" }11 };12 using var browser = await Puppeteer.LaunchAsync(launchOptions);13 using var page = await browser.NewPageAsync();14 await page.ScreenshotAsync("google.png");15 }16 }17}18using System;19using System.Threading.Tasks;20using PuppeteerSharp;21{22 {23 static async Task Main(string[] args)24 {25 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);26 {27 Args = new[] { "--no-sandbox" }28 };29 using var browser = await Puppeteer.LaunchAsync(launchOptions);30 using var page = await browser.NewPageAsync();31 await page.ScreenshotAsync("google.png");32 }33 }34}35using System;36using System.Threading.Tasks;37using PuppeteerSharp;38{39 {40 static async Task Main(string[] args)41 {42 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);43 {44 Args = new[] { "--no-sandbox" }45 };46 using var browser = await Puppeteer.LaunchAsync(launchOptions);47 using var page = await browser.NewPageAsync();48 await page.ScreenshotAsync("google.png");49 }50 }51}52using System;53using System.Threading.Tasks;54using PuppeteerSharp;55{
Dispose
Using AI Code Generation
1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4{5 {6 static void Main(string[] args)7 {8 var task = MainAsync();9 task.Wait();10 }11 static async Task MainAsync()12 {13 var browser = await Puppeteer.LaunchAsync(new LaunchOptions14 {15 });16 var page = await browser.NewPageAsync();17 var waitTask = page.WaitForNavigationAsync();18 await waitTask;19 waitTask.Dispose();20 await browser.CloseAsync();21 }22 }23}24using System;25using System.Threading.Tasks;26using PuppeteerSharp;27{28 {29 static void Main(string[] args)30 {31 var task = MainAsync();32 task.Wait();33 }34 static async Task MainAsync()35 {36 var browser = await Puppeteer.LaunchAsync(new LaunchOptions37 {38 });39 var page = await browser.NewPageAsync();40 var waitTask = page.WaitForNavigationAsync();41 await waitTask;42 await waitTask.DisposeAsync();43 await browser.CloseAsync();44 }45 }46}47using System;48using System.Threading.Tasks;49using PuppeteerSharp;50{51 {52 static void Main(string[] args)53 {54 var task = MainAsync();55 task.Wait();56 }57 static async Task MainAsync()58 {59 var browser = await Puppeteer.LaunchAsync(new LaunchOptions60 {61 });62 var page = await browser.NewPageAsync();63 var waitTask = page.WaitForNavigationAsync();64 await waitTask;65 await waitTask.Dispose();66 await browser.CloseAsync();67 }68 }69}
Dispose
Using AI Code Generation
1using System;2using PuppeteerSharp;3{4 {5 public WaitTask(Task task, Func<Task, Task> dispose)6 {7 Task = task;8 _dispose = dispose;9 }10 public Task Task { get; }11 private readonly Func<Task, Task> _dispose;12 public void Dispose()13 {14 _dispose(Task);15 }16 }17}18using System;19using System.Threading.Tasks;20using PuppeteerSharp;21{22 {23 public static WaitTask WithCancellation(this Task task, CancellationToken cancellationToken)24 {25 if (task.IsCompleted)26 {27 return new WaitTask(task, t => Task.CompletedTask);28 }29 var tcs = new TaskCompletionSource<bool>();30 var registration = cancellationToken.Register(31 s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs);32 return new WaitTask(33 Task.WhenAny(task, tcs.Task).Unwrap(),34 {35 registration.Dispose();36 if (t == task)37 {38 return Task.CompletedTask;39 }40 var cts = new CancellationTokenSource();41 cts.CancelAfter(100);42 return task.ContinueWith(43 _ => { },44 TaskScheduler.Default);45 });46 }47 }48}49using System;50using System.Threading.Tasks;51using PuppeteerSharp;52{53 {54 public static Task WithTimeout(this Task task, int millisecondsTimeout)55 {56 if (task.IsCompleted)57 {58 return task;59 }60 var tcs = new TaskCompletionSource<bool>();61 var timer = new Timer(_ => tcs.TrySetResult(true));62 timer.Change(millisecondsTimeout, Timeout.Infinite);63 return Task.WhenAny(task, tcs.Task).Unwrap().ContinueWith(64 {65 timer.Dispose();66 return t;67 },68 TaskScheduler.Default).Unwrap();69 }70 }71}
Dispose
Using AI Code Generation
1using PuppeteerSharp;2{3 {4 internal TaskCompletionSource<bool> TaskCompletionSource { get; set; }5 internal bool IsDisposed { get; set; }6 public void Dispose()7 {8 if (!IsDisposed)9 {10 IsDisposed = true;11 TaskCompletionSource.TrySetResult(true);12 }13 }14 }15}16using PuppeteerSharp;17using System;18using System.Threading.Tasks;19{20 {21 public void Dispose()22 {23 DisposeAsync().Wait();24 }25 public async Task DisposeAsync()26 {27 await CloseAsync().ConfigureAwait(false);28 }29 }30}31using PuppeteerSharp;32using System;33using System.Threading.Tasks;34{35 {36 public void Dispose()37 {38 DisposeAsync().Wait();39 }40 public async Task DisposeAsync()41 {42 await CloseAsync().ConfigureAwait(false);43 }44 }45}46using PuppeteerSharp;47using System;48using System.Threading.Tasks;49{50 {51 public void Dispose()52 {53 DisposeAsync().Wait();54 }55 public async Task DisposeAsync()56 {57 await CloseAsync().ConfigureAwait(false);58 }59 }60}61using PuppeteerSharp;62using System;63using System.Threading.Tasks;64{65 {66 public void Dispose()67 {68 DisposeAsync().Wait();69 }70 public async Task DisposeAsync()71 {72 await CloseAsync().ConfigureAwait(false);73 }74 }75}76using PuppeteerSharp;77using System;78using System.Threading.Tasks;79{80 {81 public void Dispose()82 {83 DisposeAsync().Wait();84 }85}86using System;87using System.Threading.Tasks;88using PuppeteerSharp;89{90 {91 static async Task Main(string[] args)92 {93 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);94 {95 Args = new[] { "--no-sandbox" }96 };97 using var browser = await Puppeteer.LaunchAsync(launchOptions);98 using var page = await browser.NewPageAsync();99 await page.ScreenshotAsync("google.png");100 }101 }102}103using System;104using System.Threading.Tasks;105using PuppeteerSharp;106{107 {108 static async Task Main(string[] args)109 {110 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);111 {112 Args = new[] { "--no-sandbox" }113 };114 using var browser = await Puppeteer.LaunchAsync(launchOptions);115 using var page = await browser.NewPageAsync();116 await page.ScreenshotAsync("google.png");117 }118 }119}120using System;121using System.Threading.Tasks;122using PuppeteerSharp;123{
Dispose
Using AI Code Generation
1using System;2using PuppeteerSharp;3{4 {5 public WaitTask(Task task, Func<Task, Task> dispose)6 {7 Task = task;8 _dispose = dispose;9 }10 public Task Task { get; }11 private readonly Func<Task, Task> _dispose;12 public void Dispose()13 {14 _dispose(Task);15 }16 }17}18using System;19using System.Threading.Tasks;20using PuppeteerSharp;21{22 {23 public static WaitTask WithCancellation(this Task task, CancellationToken cancellationToken)24 {25 if (task.IsCompleted)26 {27 return new WaitTask(task, t => Task.CompletedTask);28 }29 var tcs = new TaskCompletionSource<bool>();30 var registration = cancellationToken.Register(31 s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs);32 return new WaitTask(33 Task.WhenAny(task, tcs.Task).Unwrap(),34 {35 registration.Dispose();36 if (t == task)37 {38 return Task.CompletedTask;39 }40 var cts = new CancellationTokenSource();41 cts.CancelAfter(100);42 return task.ContinueWith(43 _ => { },44 TaskScheduler.Default);45 });46 }47 }48}49using System;50using System.Threading.Tasks;51using PuppeteerSharp;52{53 {54 public static Task WithTimeout(this Task task, int millisecondsTimeout)55 {56 if (task.IsCompleted)57 {58 return task;59 }60 var tcs = new TaskCompletionSource<bool>();61 var timer = new Timer(_ => tcs.TrySetResult(true));62 timer.Change(millisecondsTimeout, Timeout.Infinite);63 return Task.WhenAny(task, tcs.Task).Unwrap().ContinueWith(64 {65 timer.Dispose();66 return t;67 },68 TaskScheduler.Default).Unwrap();69 }70 }71}
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.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!