How to use FileChooser class of PuppeteerSharp package

Best Puppeteer-sharp code snippet using PuppeteerSharp.FileChooser

Page.cs

Source:Page.cs Github

copy

Full Screen

...45 private readonly IDictionary<string, Worker> _workers;46 private readonly ILogger _logger;47 private readonly TaskCompletionSource<bool> _closeCompletedTcs = new(TaskCreationOptions.RunContinuationsAsynchronously);48 private readonly TimeoutSettings _timeoutSettings;49 private readonly ConcurrentDictionary<Guid, TaskCompletionSource<FileChooser>> _fileChooserInterceptors;50 private PageGetLayoutMetricsResponse _burstModeMetrics;51 private bool _screenshotBurstModeOn;52 private ScreenshotOptions _screenshotBurstModeOptions;53 private TaskCompletionSource<bool> _sessionClosedTcs;54 private static readonly Dictionary<string, decimal> _unitToPixels = new()55 {56 { "px", 1 },57 { "in", 96 },58 { "cm", 37.8m },59 { "mm", 3.78m }60 };61 /// <summary>62 /// List of supported metrics provided by the <see cref="Metrics"/> event.63 /// </summary>64 public static readonly IEnumerable<string> SupportedMetrics = new List<string>65 {66 "Timestamp",67 "Documents",68 "Frames",69 "JSEventListeners",70 "Nodes",71 "LayoutCount",72 "RecalcStyleCount",73 "LayoutDuration",74 "RecalcStyleDuration",75 "ScriptDuration",76 "TaskDuration",77 "JSHeapUsedSize",78 "JSHeapTotalSize"79 };80 private Page(81 CDPSession client,82 Target target,83 TaskQueue screenshotTaskQueue)84 {85 Client = client;86 Target = target;87 Keyboard = new Keyboard(client);88 Mouse = new Mouse(client, Keyboard);89 Touchscreen = new Touchscreen(client, Keyboard);90 Tracing = new Tracing(client);91 Coverage = new Coverage(client);92 _fileChooserInterceptors = new ConcurrentDictionary<Guid, TaskCompletionSource<FileChooser>>();93 _timeoutSettings = new TimeoutSettings();94 _emulationManager = new EmulationManager(client);95 _pageBindings = new Dictionary<string, Delegate>();96 _workers = new ConcurrentDictionary<string, Worker>();97 _logger = Client.Connection.LoggerFactory.CreateLogger<Page>();98 Accessibility = new Accessibility(client);99 _screenshotTaskQueue = screenshotTaskQueue;100 _ = target.CloseTask.ContinueWith(101 _ =>102 {103 try104 {105 Close?.Invoke(this, EventArgs.Empty);106 }107 finally108 {109 IsClosed = true;110 _closeCompletedTcs.TrySetResult(true);111 }112 },113 TaskScheduler.Default);114 }115 /// <summary>116 /// Raised when the JavaScript <c>load</c> <see href="https://developer.mozilla.org/en-US/docs/Web/Events/load"/> event is dispatched.117 /// </summary>118 public event EventHandler Load;119 /// <summary>120 /// Raised when the page crashes121 /// </summary>122 public event EventHandler<ErrorEventArgs> Error;123 /// <summary>124 /// Raised when the JavaScript code makes a call to <c>console.timeStamp</c>. For the list of metrics see <see cref="MetricsAsync"/>.125 /// </summary>126 public event EventHandler<MetricEventArgs> Metrics;127 /// <summary>128 /// Raised when a JavaScript dialog appears, such as <c>alert</c>, <c>prompt</c>, <c>confirm</c> or <c>beforeunload</c>. Puppeteer can respond to the dialog via <see cref="Dialog"/>'s <see cref="PuppeteerSharp.Dialog.Accept(string)"/> or <see cref="PuppeteerSharp.Dialog.Dismiss"/> methods.129 /// </summary>130 public event EventHandler<DialogEventArgs> Dialog;131 /// <summary>132 /// Raised when the JavaScript <c>DOMContentLoaded</c> <see href="https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded"/> event is dispatched.133 /// </summary>134 public event EventHandler DOMContentLoaded;135 /// <summary>136 /// Raised when JavaScript within the page calls one of console API methods, e.g. <c>console.log</c> or <c>console.dir</c>. Also emitted if the page throws an error or a warning.137 /// The arguments passed into <c>console.log</c> appear as arguments on the event handler.138 /// </summary>139 /// <example>140 /// An example of handling <see cref="Console"/> event:141 /// <code>142 /// <![CDATA[143 /// page.Console += (sender, e) =>144 /// {145 /// for (var i = 0; i < e.Message.Args.Count; ++i)146 /// {147 /// System.Console.WriteLine($"{i}: {e.Message.Args[i]}");148 /// }149 /// }150 /// ]]>151 /// </code>152 /// </example>153 public event EventHandler<ConsoleEventArgs> Console;154 /// <summary>155 /// Raised when a frame is attached.156 /// </summary>157 public event EventHandler<FrameEventArgs> FrameAttached;158 /// <summary>159 /// Raised when a frame is detached.160 /// </summary>161 public event EventHandler<FrameEventArgs> FrameDetached;162 /// <summary>163 /// Raised when a frame is navigated to a new url.164 /// </summary>165 public event EventHandler<FrameEventArgs> FrameNavigated;166 /// <summary>167 /// Raised when a <see cref="Response"/> is received.168 /// </summary>169 /// <example>170 /// An example of handling <see cref="Response"/> event:171 /// <code>172 /// <![CDATA[173 /// var tcs = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);174 /// page.Response += async(sender, e) =>175 /// {176 /// if (e.Response.Url.Contains("script.js"))177 /// {178 /// tcs.TrySetResult(await e.Response.TextAsync());179 /// }180 /// };181 ///182 /// await Task.WhenAll(183 /// page.GoToAsync(TestConstants.ServerUrl + "/grid.html"),184 /// tcs.Task);185 /// Console.WriteLine(await tcs.Task);186 /// ]]>187 /// </code>188 /// </example>189 public event EventHandler<ResponseCreatedEventArgs> Response;190 /// <summary>191 /// Raised when a page issues a request. The <see cref="Request"/> object is read-only.192 /// In order to intercept and mutate requests, see <see cref="SetRequestInterceptionAsync(bool)"/>193 /// </summary>194 public event EventHandler<RequestEventArgs> Request;195 /// <summary>196 /// Raised when a request finishes successfully.197 /// </summary>198 public event EventHandler<RequestEventArgs> RequestFinished;199 /// <summary>200 /// Raised when a request fails, for example by timing out.201 /// </summary>202 public event EventHandler<RequestEventArgs> RequestFailed;203 /// <summary>204 /// Raised when a request ended up loading from cache.205 /// </summary>206 public event EventHandler<RequestEventArgs> RequestServedFromCache;207 /// <summary>208 /// Raised when an uncaught exception happens within the page.209 /// </summary>210 public event EventHandler<PageErrorEventArgs> PageError;211 /// <summary>212 /// Emitted when a dedicated WebWorker (<see href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API"/>) is spawned by the page.213 /// </summary>214 public event EventHandler<WorkerEventArgs> WorkerCreated;215 /// <summary>216 /// Emitted when a dedicated WebWorker (<see href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API"/>) is terminated.217 /// </summary>218 public event EventHandler<WorkerEventArgs> WorkerDestroyed;219 /// <summary>220 /// Raised when the page closes.221 /// </summary>222 public event EventHandler Close;223 /// <summary>224 /// Raised when the page opens a new tab or window.225 /// </summary>226 public event EventHandler<PopupEventArgs> Popup;227 /// <summary>228 /// Chrome DevTools Protocol session.229 /// </summary>230 public CDPSession Client { get; }231 /// <summary>232 /// This setting will change the default maximum time for the following methods:233 /// - <see cref="GoToAsync(string, NavigationOptions)"/>234 /// - <see cref="GoBackAsync(NavigationOptions)"/>235 /// - <see cref="GoForwardAsync(NavigationOptions)"/>236 /// - <see cref="ReloadAsync(NavigationOptions)"/>237 /// - <see cref="SetContentAsync(string, NavigationOptions)"/>238 /// - <see cref="WaitForNavigationAsync(NavigationOptions)"/>239 /// **NOTE** <see cref="DefaultNavigationTimeout"/> takes priority over <seealso cref="DefaultTimeout"/>240 /// </summary>241 public int DefaultNavigationTimeout242 {243 get => _timeoutSettings.NavigationTimeout;244 set => _timeoutSettings.NavigationTimeout = value;245 }246 /// <summary>247 /// This setting will change the default maximum times for the following methods:248 /// - <see cref="GoBackAsync(NavigationOptions)"/>249 /// - <see cref="GoForwardAsync(NavigationOptions)"/>250 /// - <see cref="GoToAsync(string, NavigationOptions)"/>251 /// - <see cref="ReloadAsync(NavigationOptions)"/>252 /// - <see cref="SetContentAsync(string, NavigationOptions)"/>253 /// - <see cref="WaitForFunctionAsync(string, object[])"/>254 /// - <see cref="WaitForNavigationAsync(NavigationOptions)"/>255 /// - <see cref="WaitForRequestAsync(string, WaitForOptions)"/>256 /// - <see cref="WaitForResponseAsync(string, WaitForOptions)"/>257 /// - <see cref="WaitForXPathAsync(string, WaitForSelectorOptions)"/>258 /// - <see cref="WaitForSelectorAsync(string, WaitForSelectorOptions)"/>259 /// - <see cref="WaitForExpressionAsync(string, WaitForFunctionOptions)"/>260 /// </summary>261 public int DefaultTimeout262 {263 get => _timeoutSettings.Timeout;264 set => _timeoutSettings.Timeout = value;265 }266 /// <summary>267 /// Gets page's main frame268 /// </summary>269 /// <remarks>270 /// Page is guaranteed to have a main frame which persists during navigations.271 /// </remarks>272 public Frame MainFrame => FrameManager.MainFrame;273 /// <summary>274 /// Gets all frames attached to the page.275 /// </summary>276 /// <value>An array of all frames attached to the page.</value>277 public Frame[] Frames => FrameManager.GetFrames();278 /// <summary>279 /// Gets all workers in the page.280 /// </summary>281 public Worker[] Workers => _workers.Values.ToArray();282 /// <summary>283 /// Shortcut for <c>page.MainFrame.Url</c>284 /// </summary>285 public string Url => MainFrame.Url;286 /// <summary>287 /// Gets that target this page was created from.288 /// </summary>289 public Target Target { get; }290 /// <summary>291 /// Gets this page's keyboard292 /// </summary>293 public Keyboard Keyboard { get; }294 /// <summary>295 /// Gets this page's touchscreen296 /// </summary>297 public Touchscreen Touchscreen { get; }298 /// <summary>299 /// Gets this page's coverage300 /// </summary>301 public Coverage Coverage { get; }302 /// <summary>303 /// Gets this page's tracing304 /// </summary>305 public Tracing Tracing { get; }306 /// <summary>307 /// Gets this page's mouse308 /// </summary>309 public Mouse Mouse { get; }310 /// <summary>311 /// Gets this page's viewport312 /// </summary>313 public ViewPortOptions Viewport { get; private set; }314 /// <summary>315 /// Get the browser the page belongs to.316 /// </summary>317 public Browser Browser => Target.Browser;318 /// <summary>319 /// Get the browser context that the page belongs to.320 /// </summary>321 public BrowserContext BrowserContext => Target.BrowserContext;322 /// <summary>323 /// Get an indication that the page has been closed.324 /// </summary>325 public bool IsClosed { get; private set; }326 /// <summary>327 /// Gets the accessibility.328 /// </summary>329 public Accessibility Accessibility { get; }330 /// <summary>331 /// `true` if drag events are being intercepted, `false` otherwise.332 /// </summary>333 public bool IsDragInterceptionEnabled { get; private set; }334 internal bool JavascriptEnabled { get; set; } = true;335 internal bool HasPopupEventListeners => Popup?.GetInvocationList().Any() == true;336 internal FrameManager FrameManager { get; private set; }337 private Task SessionClosedTask338 {339 get340 {341 if (_sessionClosedTcs == null)342 {343 _sessionClosedTcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);344 Client.Disconnected += clientDisconnected;345 void clientDisconnected(object sender, EventArgs e)346 {347 _sessionClosedTcs.TrySetException(new TargetClosedException("Target closed", "Session closed"));348 Client.Disconnected -= clientDisconnected;349 }350 }351 return _sessionClosedTcs.Task;352 }353 }354 /// <summary>355 /// Sets the page's geolocation.356 /// </summary>357 /// <returns>The task.</returns>358 /// <param name="options">Geolocation options.</param>359 /// <remarks>360 /// Consider using <seealso cref="PuppeteerSharp.BrowserContext.OverridePermissionsAsync(string, IEnumerable{OverridePermission})"/> to grant permissions for the page to read its geolocation.361 /// </remarks>362 public Task SetGeolocationAsync(GeolocationOption options)363 {364 if (options == null)365 {366 throw new ArgumentNullException(nameof(options));367 }368 if (options.Longitude < -180 || options.Longitude > 180)369 {370 throw new ArgumentException($"Invalid longitude '{options.Longitude}': precondition - 180 <= LONGITUDE <= 180 failed.");371 }372 if (options.Latitude < -90 || options.Latitude > 90)373 {374 throw new ArgumentException($"Invalid latitude '{options.Latitude}': precondition - 90 <= LATITUDE <= 90 failed.");375 }376 if (options.Accuracy < 0)377 {378 throw new ArgumentException($"Invalid accuracy '{options.Accuracy}': precondition 0 <= ACCURACY failed.");379 }380 return Client.SendAsync("Emulation.setGeolocationOverride", options);381 }382 /// <summary>383 /// Whether to enable drag interception.384 /// </summary>385 /// <remarks>386 /// Activating drag interception enables the `Input.drag`,387 /// methods This provides the capability to capture drag events emitted388 /// on the page, which can then be used to simulate drag-and-drop.389 /// </remarks>390 /// <param name="enabled">Interception enabled</param>391 /// <returns>A Task that resolves when the message was confirmed by the browser</returns>392 public Task SetDragInterceptionAsync(bool enabled)393 {394 IsDragInterceptionEnabled = enabled;395 return Client.SendAsync("Input.setInterceptDrags", new InputSetInterceptDragsRequest { Enabled = enabled });396 }397 /// <summary>398 /// Returns metrics399 /// </summary>400 /// <returns>Task which resolves into a list of metrics</returns>401 /// <remarks>402 /// All timestamps are in monotonic time: monotonically increasing time in seconds since an arbitrary point in the past.403 /// </remarks>404 public async Task<Dictionary<string, decimal>> MetricsAsync()405 {406 var response = await Client.SendAsync<PerformanceGetMetricsResponse>("Performance.getMetrics").ConfigureAwait(false);407 return BuildMetricsObject(response.Metrics);408 }409 /// <summary>410 /// Fetches an element with <paramref name="selector"/>, scrolls it into view if needed, and then uses <see cref="Touchscreen"/> to tap in the center of the element.411 /// </summary>412 /// <param name="selector">A selector to search for element to tap. If there are multiple elements satisfying the selector, the first will be clicked.</param>413 /// <exception cref="SelectorException">If there's no element matching <paramref name="selector"/></exception>414 /// <returns>Task which resolves when the element matching <paramref name="selector"/> is successfully tapped</returns>415 public async Task TapAsync(string selector)416 {417 var handle = await QuerySelectorAsync(selector).ConfigureAwait(false);418 if (handle == null)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 {...

Full Screen

Full Screen

ScheduleController.cs

Source:ScheduleController.cs Github

copy

Full Screen

...384 var html2 = await page.GetContentAsync();385 if (html2.Contains("Welcome to Instagram"))386 {387 page.EvaluateExpressionAsync(@"document.querySelector(""header button"").click()");388 var fileChooser = await page.WaitForFileChooserAsync();389 await fileChooser.AcceptAsync(new string[] { HostingEnvironment.MapPath(schedule.ImagePath) });390 await PageNavigation(page);391 }392 else393 {394 try395 {396 page.EvaluateExpressionAsync(ClickButton("Your Story"));397 var fileChooser = await page.WaitForFileChooserAsync();398 await fileChooser.AcceptAsync(new string[] { HostingEnvironment.MapPath(schedule.ImagePath) });399 await PageNavigation(page);400 }401 catch (Exception ex)402 {403 page.EvaluateExpressionAsync(ClickButton("Not Now"));404 var fileChooser = await page.WaitForFileChooserAsync();405 await fileChooser.AcceptAsync(new string[] { HostingEnvironment.MapPath(schedule.ImagePath) });406 await PageNavigation(page);407 }408 }409 try410 {411 System.Threading.Thread.Sleep(5000);412 await page.EvaluateExpressionAsync(ClickButton("Add to your story"));413 System.Threading.Thread.Sleep(500);414 await PageNavigation(page);415 System.Threading.Thread.Sleep(5000);416 schedule.PostedStatus = true;417 schedule.LastTryDate = DateTime.Now;418 schedule.Exception = "";419 }420 catch (Exception ex)421 {422 schedule.PostedStatus = true;423 schedule.LastTryDate = DateTime.Now;424 schedule.Exception = "Story Already Posted";425 }426 }427 else428 {429 page.EvaluateExpressionAsync(@"document.querySelector(""div[data-testid=new-post-button]"").click()");430 var fileChooser = await page.WaitForFileChooserAsync();431 await fileChooser.AcceptAsync(new string[] { HostingEnvironment.MapPath(schedule.ImagePath) });432 await PageNavigation(page);433 System.Threading.Thread.Sleep(5000);434 await page.EvaluateExpressionAsync(ClickButton("Next"));435 await PageNavigation(page);436 System.Threading.Thread.Sleep(5000);437 for (int i = 0; i < 4; i++)438 {439 await page.Keyboard.DownAsync(key: "Tab");440 System.Threading.Thread.Sleep(500);441 }442 await page.Keyboard.TypeAsync(schedule.Caption, new TypeOptions { Delay = 200 });443 await page.EvaluateExpressionAsync(ClickButton("Share"));444 System.Threading.Thread.Sleep(500);...

Full Screen

Full Screen

LicenseActivator.cs

Source:LicenseActivator.cs Github

copy

Full Screen

...78 await AcceptTosIfRequired(page);79 //Upload file80 await page.WaitForSelectorAsync("#licenseFile");81 Console.WriteLine("Uploading file...");82 var fileChooserTask = page.WaitForFileChooserAsync();83 await page.ClickAsync("#licenseFile");84 var fileChooser = await fileChooserTask;85 await fileChooser.AcceptAsync(cliOptions.LicenseFile);86 await page.ClickAsync("input[value='Next']");87 //Activate your license88 var unityPersonalEditionButton = await page.WaitForSelectorAsync("label[for='type_personal']");89 Console.WriteLine("Selecting edition...");90 await unityPersonalEditionButton.ClickAsync();91 var notUseUnityInProfessionalCapacity = await page.WaitForSelectorAsync("label[for='option3']");92 await notUseUnityInProfessionalCapacity.ClickAsync();93 var nextButton = await page.WaitForSelectorAsync(".selected input[value='Next']");94 await nextButton.ClickAsync();95 //Download license file96 await page.WaitForSelectorAsync("input[value='Download license file']");...

Full Screen

Full Screen

HomeController.cs

Source:HomeController.cs Github

copy

Full Screen

...84 System.Threading.Thread.Sleep(5000);85 //Dont add await for this86 page.EvaluateExpressionAsync(87 @"document.querySelector(""div[data-testid=new-post-button]"").click()");88 var fileChooser = await page.WaitForFileChooserAsync();89 await fileChooser.AcceptAsync(new string[] { "C:\\Users\\Zawar\\Desktop\\New folder (4)\\cover6.jpg" });90 System.Threading.Thread.Sleep(5000);91 await page.EvaluateExpressionAsync(ClickButton("Next"));92 System.Threading.Thread.Sleep(5000);93 for (int i = 0; i < 4; i++)94 {95 await page.Keyboard.DownAsync(key: "Tab");96 System.Threading.Thread.Sleep(500);97 }98 await page.Keyboard.TypeAsync("Automated caption", new TypeOptions { Delay = 200 });99 await page.EvaluateExpressionAsync(ClickButton("Share"));100 System.Threading.Thread.Sleep(1600000);101 }102 catch (Exception ex)...

Full Screen

Full Screen

FileChooserAcceptTests.cs

Source:FileChooserAcceptTests.cs Github

copy

Full Screen

...7using Xunit.Abstractions;8namespace PuppeteerSharp.Tests.InputTests9{10 [Collection(TestConstants.TestFixtureCollectionName)]11 public class FileChooserAcceptTests : PuppeteerPageBaseTest12 {13 public FileChooserAcceptTests(ITestOutputHelper output) : base(output)14 {15 }16 [PuppeteerTest("input.spec.ts", "FileChooser.accept", "should accept single file")]17 [SkipBrowserFact(skipFirefox: true)]18 public async Task ShouldAcceptSingleFile()19 {20 await Page.SetContentAsync("<input type=file oninput='javascript:console.timeStamp()'>");21 var waitForTask = Page.WaitForFileChooserAsync();22 var metricsTcs = new TaskCompletionSource<bool>();23 await Task.WhenAll(24 waitForTask,25 Page.ClickAsync("input"));26 Page.Metrics += (_, _) => metricsTcs.TrySetResult(true);27 await Task.WhenAll(28 waitForTask.Result.AcceptAsync(TestConstants.FileToUpload),29 metricsTcs.Task);30 Assert.Equal(1, await Page.QuerySelectorAsync("input").EvaluateFunctionAsync<int>("input => input.files.length"));31 Assert.Equal(32 "file-to-upload.txt",33 await Page.QuerySelectorAsync("input").EvaluateFunctionAsync<string>("input => input.files[0].name"));34 }35 [PuppeteerTest("input.spec.ts", "FileChooser.accept", "should be able to read selected file")]36 [SkipBrowserFact(skipFirefox: true)]37 public async Task ShouldBeAbleToReadSelectedFile()38 {39 await Page.SetContentAsync("<input type=file>");40 _ = Page.WaitForFileChooserAsync().ContinueWith(t => t.Result.AcceptAsync(TestConstants.FileToUpload));41 Assert.Equal(42 "contents of the file",43 await Page.QuerySelectorAsync("input").EvaluateFunctionAsync<string>(@"async picker =>44 {45 picker.click();46 await new Promise(x => picker.oninput = x);47 const reader = new FileReader();48 const promise = new Promise(fulfill => reader.onload = fulfill);49 reader.readAsText(picker.files[0]);50 return promise.then(() => reader.result);51 }"));52 }53 [PuppeteerTest("input.spec.ts", "FileChooser.accept", "should be able to reset selected files with empty file list")]54 [SkipBrowserFact(skipFirefox: true)]55 public async Task ShouldBeAbleToResetSelectedFilesWithEmptyFileList()56 {57 await Page.SetContentAsync("<input type=file>");58 _ = Page.WaitForFileChooserAsync().ContinueWith(t => t.Result.AcceptAsync(TestConstants.FileToUpload));59 Assert.Equal(60 1,61 await Page.QuerySelectorAsync("input").EvaluateFunctionAsync<int>(@"async picker =>62 {63 picker.click();64 await new Promise(x => picker.oninput = x);65 return picker.files.length;66 }"));67 _ = Page.WaitForFileChooserAsync().ContinueWith(t => t.Result.AcceptAsync());68 Assert.Equal(69 0,70 await Page.QuerySelectorAsync("input").EvaluateFunctionAsync<int>(@"async picker =>71 {72 picker.click();73 await new Promise(x => picker.oninput = x);74 return picker.files.length;75 }"));76 }77 [PuppeteerTest("input.spec.ts", "FileChooser.accept", "should not accept multiple files for single-file input")]78 [SkipBrowserFact(skipFirefox: true)]79 public async Task ShouldNotAcceptMultipleFilesForSingleFileInput()80 {81 await Page.SetContentAsync("<input type=file>");82 var waitForTask = Page.WaitForFileChooserAsync();83 await Task.WhenAll(84 waitForTask,85 Page.ClickAsync("input"));86 await Assert.ThrowsAsync<PuppeteerException>(() => waitForTask.Result.AcceptAsync(87 "./assets/file-to-upload.txt",88 "./assets/pptr.png"));89 }90 [PuppeteerTest("input.spec.ts", "FileChooser.accept", "should fail for non-existent files")]91 [SkipBrowserFact(skipFirefox: true)]92 public async Task ShouldFailForNonExistentFiles()93 {94 await Page.SetContentAsync("<input type=file>");95 var waitForTask = Page.WaitForFileChooserAsync();96 await Task.WhenAll(97 waitForTask,98 Page.ClickAsync("input"));99 await Assert.ThrowsAsync<PuppeteerException>(() => waitForTask.Result.AcceptAsync("file-does-not-exist.txt"));100 }101 [PuppeteerTest("input.spec.ts", "FileChooser.accept", "should fail when accepting file chooser twice")]102 [SkipBrowserFact(skipFirefox: true)]103 public async Task ShouldFailWhenAcceptingFileChooserTwice()104 {105 await Page.SetContentAsync("<input type=file>");106 var waitForTask = Page.WaitForFileChooserAsync();107 await Task.WhenAll(108 waitForTask,109 Page.ClickAsync("input"));110 var fileChooser = waitForTask.Result;111 await fileChooser.AcceptAsync();112 var ex = await Assert.ThrowsAsync<PuppeteerException>(() => waitForTask.Result.AcceptAsync());113 Assert.Equal("Cannot accept FileChooser which is already handled!", ex.Message);114 }115 }116}...

Full Screen

Full Screen

FileChooser.cs

Source:FileChooser.cs Github

copy

Full Screen

...5using PuppeteerSharp.Messaging;6namespace PuppeteerSharp7{8 /// <summary>9 /// <see cref="FileChooser"/> objects are returned via the <seealso cref="Page.WaitForFileChooserAsync(WaitForFileChooserOptions)"/> method.10 /// File choosers let you react to the page requesting for a file.11 /// </summary>12 /// <example>13 /// <code>14 /// <![CDATA[15 /// var waitTask = page.WaitForFileChooserAsync();16 /// await Task.WhenAll(17 /// waitTask,18 /// page.ClickAsync("#upload-file-button")); // some button that triggers file selection19 /// 20 /// await waitTask.Result.AcceptAsync('/tmp/myfile.pdf');21 /// ]]>22 /// </code>23 /// </example>24 /// <remarks>25 /// In browsers, only one file chooser can be opened at a time.26 /// All file choosers must be accepted or canceled. Not doing so will prevent subsequent file choosers from appearing.27 /// </remarks>28 public class FileChooser29 {30 private CDPSession _client;31 private bool _handled;32 internal FileChooser(CDPSession client, PageFileChooserOpenedResponse e)33 {34 _client = client;35 IsMultiple = e.Mode != "selectSingle";36 _handled = false;37 }38 /// <summary>39 /// Whether file chooser allow for <see href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-multiple">multiple</see> file selection.40 /// </summary>41 public bool IsMultiple { get; }42 /// <summary>43 /// Accept the file chooser request with given paths. 44 /// If some of the filePaths are relative paths, then they are resolved relative to the current working directory.45 /// </summary>46 /// <param name="filePaths">File paths to send to the file chooser</param>47 /// <returns>A task that resolves after the accept message is processed by the browser</returns>48 public Task AcceptAsync(params string[] filePaths)49 {50 if (_handled)51 {52 throw new PuppeteerException("Cannot accept FileChooser which is already handled!");53 }54 _handled = true;55 var files = filePaths.Select(Path.GetFullPath);56 return _client.SendAsync("Page.handleFileChooser", new PageHandleFileChooserRequest57 {58 Action = FileChooserAction.Accept,59 Files = files,60 });61 }62 /// <summary>63 /// Closes the file chooser without selecting any files.64 /// </summary>65 /// <returns>A task that resolves after the cancel message is processed by the browser</returns>66 public Task CancelAsync()67 {68 if (_handled)69 {70 throw new PuppeteerException("Cannot accept FileChooser which is already handled!");71 }72 _handled = true;73 return _client.SendAsync("Page.handleFileChooser", new PageHandleFileChooserRequest74 {75 Action = FileChooserAction.Cancel76 });77 }78 }79}...

Full Screen

Full Screen

FileChooserIsMultipleTests.cs

Source:FileChooserIsMultipleTests.cs Github

copy

Full Screen

...7using Xunit.Abstractions;8namespace PuppeteerSharp.Tests.InputTests9{10 [Collection(TestConstants.TestFixtureCollectionName)]11 public class FileChooserIsMultipleTests : PuppeteerPageBaseTest12 {13 public FileChooserIsMultipleTests(ITestOutputHelper output) : base(output)14 {15 }16 [PuppeteerTest("input.spec.ts", "FileChooser.isMultiple", "should work for single file pick")]17 [SkipBrowserFact(skipFirefox: true)]18 public async Task ShouldWorkForSingleFilePick()19 {20 await Page.SetContentAsync("<input type=file>");21 var waitForTask = Page.WaitForFileChooserAsync();22 await Task.WhenAll(23 waitForTask,24 Page.ClickAsync("input"));25 Assert.False(waitForTask.Result.IsMultiple);26 }27 [PuppeteerTest("input.spec.ts", "FileChooser.isMultiple", "should work for \"multiple\"")]28 [SkipBrowserFact(skipFirefox: true)]29 public async Task ShouldWorkForMultiple()30 {31 await Page.SetContentAsync("<input type=file multiple>");32 var waitForTask = Page.WaitForFileChooserAsync();33 await Task.WhenAll(34 waitForTask,35 Page.ClickAsync("input"));36 Assert.True(waitForTask.Result.IsMultiple);37 }38 [PuppeteerTest("input.spec.ts", "FileChooser.isMultiple", "should work for \"webkitdirectory\"")]39 [SkipBrowserFact(skipFirefox: true)]40 public async Task ShouldWorkForWebkitDirectory()41 {42 await Page.SetContentAsync("<input type=file multiple webkitdirectory>");43 var waitForTask = Page.WaitForFileChooserAsync();44 await Task.WhenAll(45 waitForTask,46 Page.ClickAsync("input"));47 Assert.True(waitForTask.Result.IsMultiple);48 }49 }50}...

Full Screen

Full Screen

FileChooserCancelTests.cs

Source:FileChooserCancelTests.cs Github

copy

Full Screen

...5using Xunit.Abstractions;6namespace PuppeteerSharp.Tests.InputTests7{8 [Collection(TestConstants.TestFixtureCollectionName)]9 public class FileChooserCancelTests : PuppeteerPageBaseTest10 {11 public FileChooserCancelTests(ITestOutputHelper output) : base(output)12 {13 }14 [Fact]15 public async Task ShouldCancelDialog()16 {17 // Consider file chooser canceled if we can summon another one.18 // There's no reliable way in WebPlatform to see that FileChooser was19 // canceled.20 await Page.SetContentAsync("<input type=file>");21 var waitForTask = Page.WaitForFileChooserAsync();22 await Task.WhenAll(23 waitForTask,24 Page.ClickAsync("input"));25 var fileChooser = waitForTask.Result;26 await fileChooser.CancelAsync();27 await Task.WhenAll(28 Page.WaitForFileChooserAsync(),29 Page.ClickAsync("input"));30 }31 [Fact]32 public async Task ShouldFailWhenCancelingFileChooserTwice()33 {34 await Page.SetContentAsync("<input type=file>");35 var waitForTask = Page.WaitForFileChooserAsync();36 await Task.WhenAll(37 waitForTask,38 Page.ClickAsync("input"));39 var fileChooser = waitForTask.Result;40 await fileChooser.CancelAsync();41 var ex = await Assert.ThrowsAsync<PuppeteerException>(() => fileChooser.CancelAsync());42 Assert.Equal("Cannot accept FileChooser which is already handled!", ex.Message);43 }44 }45}...

Full Screen

Full Screen

FileChooser

Using AI Code Generation

copy

Full Screen

1using System;2using System.Threading.Tasks;3using PuppeteerSharp;4{5 {6 static void Main(string[] args)7 {8 MainAsync().GetAwaiter().GetResult();9 }10 static async Task MainAsync()11 {12 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);13 using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true }))14 using (var page = await browser.NewPageAsync())15 {16 var fileChooser = await page.WaitForFileChooserAsync();17 await fileChooser.SetFilesAsync(@"C:\Users\user\Desktop\1.txt");18 }19 }20 }21}22const puppeteer = require('puppeteer');23(async () => {24 const browser = await puppeteer.launch();25 const page = await browser.newPage();26 const [fileChooser] = await Promise.all([27 page.waitForFileChooser(),28 ]);29 await fileChooser.accept(['C:\\Users\\user\\Desktop\\1.txt']);30 await browser.close();31})();

Full Screen

Full Screen

FileChooser

Using AI Code Generation

copy

Full Screen

1using PuppeteerSharp;2using System;3using System.IO;4using System.Threading.Tasks;5{6 {7 static async Task Main(string[] args)8 {9 {10 Args = new string[] { "--no-sandbox", "--disable-setuid-sandbox" }11 };12 var browser = await Puppeteer.LaunchAsync(options);13 var page = await browser.NewPageAsync();14 await page.ScreenshotAsync("google.png");15 await page.ClickAsync("a[href='/search?q=google+drive']");16 await page.ScreenshotAsync("googleDrive.png");17 await page.ClickAsync("a[href='/search?q=google+docs']");18 await page.ScreenshotAsync("googleDocs.png");19 await browser.CloseAsync();20 Console.WriteLine("done");21 }22 }23}24using PuppeteerSharp;25using System;26using System.IO;27using System.Threading.Tasks;28{29 {30 static async Task Main(string[] args)31 {32 {33 Args = new string[] { "--no-sandbox", "--disable-setuid-sandbox" }34 };35 var browser = await Puppeteer.LaunchAsync(options);36 var page = await browser.NewPageAsync();37 await page.ScreenshotAsync("google.png");38 await page.ClickAsync("a[href='/search?q=google+drive']");39 await page.ScreenshotAsync("googleDrive.png");40 await page.ClickAsync("a[href='/search?q=google+docs']");41 await page.ScreenshotAsync("googleDocs.png");42 await browser.CloseAsync();43 Console.WriteLine("done");44 }45 }46}47using PuppeteerSharp;48using System;49using System.IO;50using System.Threading.Tasks;51{52 {53 static async Task Main(string[] args)54 {55 {56 Args = new string[] { "--no-sandbox

Full Screen

Full Screen

FileChooser

Using AI Code Generation

copy

Full Screen

1using System.Threading.Tasks;2using PuppeteerSharp;3{4 {5 static async Task Main(string[] args)6 {7 {8 };9 using (var browser = await Puppeteer.LaunchAsync(options))10 {11 using (var page = await browser.NewPageAsync())12 {13 var fileChooser = await page.WaitForFileChooserAsync();14 await fileChooser.SetFilesAsync("C:/Users/username/Desktop/file.txt");15 }16 }17 }18 }19}

Full Screen

Full Screen

FileChooser

Using AI Code Generation

copy

Full Screen

1var fileChooser = await page.WaitForFileChooserAsync();2await fileChooser.SetFilesAsync("C:\\Users\\username\\Desktop\\1.txt");3await page.ClickAsync("#buttonId");4var fileChooser = await page.WaitForFileChooserAsync();5await fileChooser.SetFilesAsync("C:\\Users\\username\\Desktop\\1.txt");6await page.ClickAsync("#buttonId");7var fileChooser = await page.WaitForFileChooserAsync();8await fileChooser.SetFilesAsync("C:\\Users\\username\\Desktop\\1.txt");9await page.ClickAsync("#buttonId");10var fileChooser = await page.WaitForFileChooserAsync();

Full Screen

Full Screen

Automation Testing Tutorials

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

LambdaTest Learning Hubs:

YouTube

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

Run Puppeteer-sharp automation tests on LambdaTest cloud grid

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

Most used methods in FileChooser

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful