* Click tests

* cr

* cr

* More cs
This commit is contained in:
Darío Kondratiuk 2020-01-31 19:24:29 -03:00 коммит произвёл GitHub
Родитель 4278532046
Коммит a7b7e075af
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
24 изменённых файлов: 1302 добавлений и 6 удалений

Просмотреть файл

@ -0,0 +1,25 @@
namespace PlaywrightSharp
{
/// <summary>
/// Modifiers for <see cref="ClickOptions.Modifiers"/>
/// </summary>
public enum ClickModifier
{
/// <summary>
/// Alt key
/// </summary>
Alt,
/// <summary>
/// Control key
/// </summary>
Control,
/// <summary>
/// Meta key
/// </summary>
Meta,
/// <summary>
/// Shift Key
/// </summary>
Shift
}
}

Просмотреть файл

@ -0,0 +1,40 @@
using System.Drawing;
namespace PlaywrightSharp
{
/// <summary>
/// Options to use when clicking
/// </summary>
public class ClickOptions
{
/// <summary>
/// Time to wait between <c>mousedown</c> and <c>mouseup</c> in milliseconds. Defaults to 0
/// </summary>
public int Delay { get; set; } = 0;
/// <summary>
/// Defaults to 1. See https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail
/// </summary>
public int ClickCount { get; set; } = 1;
/// <summary>
/// The button to use for the click. Defaults to <see cref="MouseButton.Left"/>
/// </summary>
public MouseButton Button { get; set; } = MouseButton.Left;
/// <summary>
/// Wait for element to become visible (visible), hidden (hidden), present in dom (any) or do not wait at all (nowait). Defaults to visible.
/// </summary>
public WaitForOptions WaitFor { get; set; }
/// <summary>
/// A point to click relative to the top-left corner of element padding box. If not specified, clicks to some visible point of the element.
/// </summary>
public Point RelativePoint { get; set; }
/// <summary>
/// Modifier keys to press. Ensures that only these modifiers are pressed during the click, and then restores current modifiers back. If not specified, currently pressed modifiers are used.
/// </summary>
public ClickModifier[] Modifiers { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,22 @@
using System;
namespace PlaywrightSharp
{
/// <summary>
/// <see cref="IPage.Console"/> data.
/// </summary>
public class ConsoleEventArgs : EventArgs
{
/// <summary>
/// Gets the message.
/// </summary>
/// <value>The message.</value>
public ConsoleMessage Message { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ConsoleEventArgs"/> class.
/// </summary>
/// <param name="message">Message.</param>
public ConsoleEventArgs(ConsoleMessage message) => Message = message;
}
}

Просмотреть файл

@ -0,0 +1,48 @@
using System.Collections.Generic;
namespace PlaywrightSharp
{
/// <summary>
/// ConsoleMessage is part of <see cref="ConsoleEventArgs"/> used by <see cref="IPage.Console"/>
/// </summary>
public class ConsoleMessage
{
/// <summary>
/// Gets the ConsoleMessage type.
/// </summary>
/// <value>ConsoleMessageType.</value>
public ConsoleType Type { get; }
/// <summary>
/// Gets the console text.
/// </summary>
/// <value>The text.</value>
public string Text { get; }
/// <summary>
/// Gets the arguments.
/// </summary>
/// <value>The arguments.</value>
public IList<IJSHandle> Args { get; }
/// <summary>
/// Gets the location.
/// </summary>
public ConsoleMessageLocation Location { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ConsoleMessage"/> class.
/// </summary>
/// <param name="type">Type.</param>
/// <param name="text">Text.</param>
/// <param name="args">Arguments.</param>
/// <param name="location">Message location</param>
public ConsoleMessage(ConsoleType type, string text, IList<IJSHandle> args, ConsoleMessageLocation location = null)
{
Type = type;
Text = text;
Args = args;
Location = location;
}
}
}

Просмотреть файл

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
namespace PlaywrightSharp
{
/// <summary>
/// Console message location.
/// </summary>
public class ConsoleMessageLocation : IEquatable<ConsoleMessageLocation>
{
/// <summary>
/// URL of the resource if known.
/// </summary>
public string URL { get; set; }
/// <summary>
/// 0-based line number in the resource if known.
/// </summary>
public int? LineNumber { get; set; }
/// <summary>
/// 0-based column number in the resource if known.
/// </summary>
public int? ColumnNumber { get; set; }
/// <inheritdoc/>
public bool Equals(ConsoleMessageLocation other)
=> (URL, LineNumber, ColumnNumber) == (other?.URL, other?.LineNumber, other?.ColumnNumber);
/// <inheritdoc/>
public override bool Equals(object obj) => Equals(obj as ConsoleMessageLocation);
/// <inheritdoc/>
public override int GetHashCode()
=> 412870874 +
EqualityComparer<string>.Default.GetHashCode(URL) +
EqualityComparer<int?>.Default.GetHashCode(LineNumber) +
EqualityComparer<int?>.Default.GetHashCode(ColumnNumber);
/// <inheritdoc/>
public static bool operator ==(ConsoleMessageLocation location1, ConsoleMessageLocation location2)
=> EqualityComparer<ConsoleMessageLocation>.Default.Equals(location1, location2);
/// <inheritdoc/>
public static bool operator !=(ConsoleMessageLocation location1, ConsoleMessageLocation location2)
=> !(location1 == location2);
}
}

Просмотреть файл

@ -0,0 +1,85 @@
namespace PlaywrightSharp
{
/// <summary>
/// Console type used on <see cref="ConsoleMessage"/>.
/// </summary>
public enum ConsoleType
{
/// <summary>
/// Log.
/// </summary>
Log,
/// <summary>
/// Debug.
/// </summary>
Debug,
/// <summary>
/// Info.
/// </summary>
Info,
/// <summary>
/// Error.
/// </summary>
Error,
/// <summary>
/// Warning.
/// </summary>
Warning,
/// <summary>
/// Dir.
/// </summary>
Dir,
/// <summary>
/// Dirxml.
/// </summary>
Dirxml,
/// <summary>
/// Table.
/// </summary>
Table,
/// <summary>
/// Trace.
/// </summary>
Trace,
/// <summary>
/// Clear.
/// </summary>
Clear,
/// <summary>
/// StartGroup.
/// </summary>
StartGroup,
/// <summary>
/// StartGroupCollapsed.
/// </summary>
StartGroupCollapsed,
/// <summary>
/// EndGroup.
/// </summary>
EndGroup,
/// <summary>
/// Assert.
/// </summary>
Assert,
/// <summary>
/// Profile.
/// </summary>
Profile,
/// <summary>
/// ProfileEnd.
/// </summary>
ProfileEnd,
/// <summary>
/// Count.
/// </summary>
Count,
/// <summary>
/// TimeEnd.
/// </summary>
TimeEnd,
/// <summary>
/// Verbose.
/// </summary>
Verbose,
}
}

Просмотреть файл

@ -0,0 +1,13 @@
namespace PlaywrightSharp
{
/// <summary>
/// Options for <see cref="IKeyboard.DownAsync(string, DownOptions)"/>
/// </summary>
public class DownOptions
{
/// <summary>
/// If specified, generates an input event with this text
/// </summary>
public string Text { get; set; }
}
}

Просмотреть файл

@ -1,4 +1,5 @@
using System.Threading.Tasks;
using System.Text.Json;
using System.Threading.Tasks;
namespace PlaywrightSharp
{
@ -21,5 +22,24 @@ namespace PlaywrightSharp
/// </summary>
/// <returns>A <see cref="Task"/> that completes when the frame is resolved, yielding element's parent <see cref="IFrame" /></returns>
Task<IFrame> ContentFrameAsync();
/// <summary>
/// Scrolls element into view if needed, and then uses <see cref="IPage.Mouse"/> to click in the center of the element.
/// </summary>
/// <param name="options">click options</param>
/// <returns>A <see cref="Task"/> that completes when the element is successfully clicked</returns>
Task ClickAsync(ClickOptions options = null);
/// <summary>
/// Executes a function in browser context, passing the current <see cref="IElementHandle"/> as the first argument.
/// </summary>
/// <param name="script">Script to be evaluated in browser context</param>
/// <param name="args">Arguments to pass to script</param>
/// <remarks>
/// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.
/// <see cref="IJSHandle"/> instances can be passed as arguments
/// </remarks>
/// <returns>A <see cref="Task"/> that completes when the script is executed, yieling the return value of that script</returns>
Task<JsonElement?> EvaluateAsync(string script, params object[] args);
}
}

Просмотреть файл

@ -57,6 +57,11 @@ namespace PlaywrightSharp
/// </summary>
string Url { get; }
/// <summary>
/// Gets the parent <see cref="IFrame"/>, if any. Detached frames and main frames return <c>null</c>
/// </summary>
IFrame ParentFrame { get; }
/// <summary>
/// Sets the HTML markup to the frame
/// </summary>
@ -100,5 +105,54 @@ namespace PlaywrightSharp
/// <seealso cref="IPage.EvaluateAsync(string, object[])"/>
/// <returns>Task that completes when the script finishes or the promise is resolved, yielding the result of the script as an row Json element.</returns>
Task<JsonElement?> EvaluateAsync(string script, params object[] args);
/// <summary>
/// <![CDATA[
/// This method focuses the element and triggers an input event after filling. If there's no text <input>, <textarea> or [contenteditable] element matching selector, the method throws an error.
/// ]]>
/// </summary>
/// <param name="selector">A selector to query page for.</param>
/// <param name="text"><![CDATA[Value to fill for the <input>, <textarea> or [contenteditable] element]]></param>
/// <param name="options">Optional waiting parameters</param>
/// <returns>A <see cref="Task"/> that completes when the fill message is confirmed by the browser.</returns>
Task FillAsync(string selector, string text, WaitForSelectorOptions options = null);
/// <summary>
/// Waits for a selector to be added to the DOM
/// </summary>
/// <param name="selector">A selector of an element to wait for</param>
/// <param name="options">Optional waiting parameters</param>
/// <returns>A <see cref="Task"/> that completes when element specified by selector string is added to DOM, yielding the <see cref="IElementHandle"/> to wait for.
/// Resolves to `null` if waiting for `hidden: true` and selector is not found in DOM.</returns>
Task<IElementHandle> WaitForSelectorAsync(string selector, WaitForSelectorOptions options = null);
/// <summary>
/// Queries frame for the selector. If there's no such element within the frame, the method will resolve to <c>null</c>.
/// </summary>
/// <param name="selector">Selector to query frame for</param>
/// <returns>A <see cref="Task"/> that completes when the selector is found (or failed), yielding the <see cref="IElementHandle"/> pointing to the frame element</returns>
/// <seealso cref="IPage.QuerySelectorAsync(string)"/>
Task<IElementHandle> QuerySelectorAsync(string selector);
/// <summary>
/// Fetches an element with <paramref name="selector"/>, scrolls it into view if needed, and then uses <see cref="IPage.Mouse"/> to click in the center of the element.
/// </summary>
/// <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>
/// <param name="options">click options</param>
/// <returns>A <see cref="Task"/> that completes when the element matching <paramref name="selector"/> is successfully clicked</returns>
Task ClickAsync(string selector, ClickOptions options = null);
/// <summary>
/// This method runs document.querySelector within the page and passes it as the first argument to pageFunction.
/// If there's no element matching selector, the method throws an error.
/// </summary>
/// <param name="selector">A selector to query page for</param>
/// <param name="script">Script to be evaluated in browser context</param>
/// <param name="args">Arguments to pass to script</param>
/// <remarks>
/// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.
/// </remarks>
/// <returns>A <see cref="Task"/> that completes when the script finishes or the promise is resolved, yielding the result of the script</returns>
Task QuerySelectorEvaluateAsync(string selector, string script, params object[] args);
}
}

Просмотреть файл

@ -0,0 +1,32 @@
using System.Threading.Tasks;
namespace PlaywrightSharp
{
/// <summary>
/// Keyboard provides an api for managing a virtual keyboard.
/// </summary>
public interface IKeyboard
{
/// <summary>
/// <![CDATA[
/// Dispatches a <c>keydown</c> event
/// ]]>
/// </summary>
/// <param name="key">Name of key to press, such as <c>ArrowLeft</c>.</param>
/// <param name="options">down options</param>
/// <remarks>
/// If <c>key</c> is a single character and no modifier keys besides <c>Shift</c> are being held down, a <c>keypress</c>/<c>input</c> event will also generated. The <c>text</c> option can be specified to force an input event to be generated.
/// If <c>key</c> is a modifier key, <c>Shift</c>, <c>Meta</c>, <c>Control</c>, or <c>Alt</c>, subsequent key presses will be sent with that modifier active. To release the modifier key, use <see cref="UpAsync(string)"/>
/// After the key is pressed once, subsequent calls to <see cref="DownAsync(string, DownOptions)"/> will have <see href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat">repeat</see> set to <c>true</c>. To release the key, use <see cref="UpAsync(string)"/>
/// </remarks>
/// <returns>A <see cref="Task"/> that completes when the message is confirmed by the browser</returns>
Task DownAsync(string key, DownOptions options = null);
/// <summary>
/// Dispatches a <c>keyup</c> event.
/// </summary>
/// <param name="key">Name of key to release, such as `ArrowLeft`.</param>
/// <returns>A <see cref="Task"/> that completes when the message is confirmed by the browser</returns>
Task UpAsync(string key);
}
}

Просмотреть файл

@ -0,0 +1,50 @@
using System.Threading.Tasks;
namespace PlaywrightSharp
{
/// <summary>
/// Provides methods to interact with the mouse
/// </summary>
public interface IMouse
{
/// <summary>
/// Dispatches a <c>mousemove</c> event.
/// </summary>
/// <param name="x">X coordinate</param>
/// <param name="y">Y coordinate</param>
/// <param name="options">Extra options</param>
/// <returns>A <see cref="Task"/> that completes when the message is confirmed by the browser.</returns>
Task MoveAsync(decimal x, decimal y, MoveOptions options = null);
/// <summary>
/// Shortcut for <see cref="MoveAsync(decimal, decimal, MoveOptions)"/>, <see cref="DownAsync(ClickOptions)"/> and <see cref="UpAsync(ClickOptions)"/>
/// </summary>
/// <param name="x">X coordinate</param>
/// <param name="y">Y coordinate</param>
/// <param name="options">Extra options</param>
/// <returns>A <see cref="Task"/> that completes when the message is confirmed by the browser.</returns>
Task ClickAsync(decimal x, decimal y, ClickOptions options = null);
/// <summary>
/// Dispatches a <c>mousedown</c> event.
/// </summary>
/// <param name="options">Extra options</param>
/// <returns>A <see cref="Task"/> that completes when the message is confirmed by the browser.</returns>
Task DownAsync(ClickOptions options = null);
/// <summary>
/// Dispatches a <c>mouseup</c> event.
/// </summary>
/// <param name="options">Extra options</param>
/// <returns>A <see cref="Task"/> that completes when the message is confirmed by the browser.</returns>
Task UpAsync(ClickOptions options = null);
/// <summary>
/// Dispatches a <c>wheel</c> event.
/// </summary>
/// <param name="deltaX">delta X</param>
/// <param name="deltaY">delta Y</param>
/// <returns>A <see cref="Task"/> that completes when the message is confirmed by the browser.</returns>
Task WheelAsync(decimal deltaX, decimal deltaY);
}
}

Просмотреть файл

@ -106,11 +106,57 @@ namespace PlaywrightSharp
/// </summary>
IAccessibility Accessibility { get; }
/// <summary>
/// Gets this page's mouse
/// </summary>
IMouse Mouse { get; }
/// <summary>
/// Shortcut for MainFrame.Url
/// </summary>
string Url { get; }
/// <summary>
/// Gets all frames attached to the page.
/// </summary>
IFrame[] Frames { get; }
/// <summary>
/// Gets this page's keyboard
/// </summary>
IKeyboard Keyboard { get; }
/// <summary>
/// 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.
/// The arguments passed into <c>console.log</c> appear as arguments on the event handler.
/// </summary>
/// <example>
/// An example of handling <see cref="Console"/> event:
/// <code>
/// <![CDATA[
/// page.Console += (sender, e) =>
/// {
/// for (var i = 0; i < e.Message.Args.Count; ++i)
/// {
/// System.Console.WriteLine($"{i}: {e.Message.Args[i]}");
/// }
/// }
/// ]]>
/// </code>
/// </example>
event EventHandler<ConsoleEventArgs> Console;
/// <summary>
/// Raised when a JavaScript dialog appears, such as <c>alert</c>, <c>prompt</c>, <c>confirm</c> or <c>beforeunload</c>. PlaywrightSharp can respond to the dialog via <see cref="Dialog"/>'s <see cref="IDialog.AcceptAsync(string)"/> or <see cref="IDialog.DismissAsync"/> methods.
/// </summary>
event EventHandler<DialogEventArgs> Dialog;
/// <summary>
/// Closes the page.
/// </summary>
/// <returns>A <see cref="Task"/> that completes when the close process finishes.</returns>
Task CloseAsync(PageCloseOptions options = null);
/// <summary>
/// Executes a script in browser context
/// </summary>
@ -120,7 +166,7 @@ namespace PlaywrightSharp
/// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.
/// </remarks>
/// <seealso cref="IFrame.EvaluateAsync{T}(string, object[])"/>
/// <returns>Task that completes when the script finishes or the promise is resolved, yielding the result of the script</returns>
/// <returns>A <see cref="Task"/> that completes when the script finishes or the promise is resolved, yielding the result of the script</returns>
Task<T> EvaluateAsync<T>(string script, params object[] args);
/// <summary>
@ -133,9 +179,30 @@ namespace PlaywrightSharp
/// <remarks>
/// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.
/// </remarks>
/// <returns>Task that completes when the script finishes or the promise is resolved, yielding the result of the script</returns>
/// <returns>A <see cref="Task"/> that completes when the script finishes or the promise is resolved, yielding the result of the script</returns>
Task QuerySelectorEvaluateAsync(string selector, string script, params object[] args);
/// <summary>
/// <![CDATA[
/// This method focuses the element and triggers an input event after filling. If there's no text <input>, <textarea> or [contenteditable] element matching selector, the method throws an error.
/// ]]>
/// Shortcut for MainFrame.FillAsync.
/// </summary>
/// <param name="selector">A selector to query page for.</param>
/// <param name="text"><![CDATA[Value to fill for the <input>, <textarea> or [contenteditable] element]]></param>
/// <param name="options">Optional waiting parameters</param>
/// <returns>A <see cref="Task"/> that completes when the fill message is confirmed by the browser.</returns>
Task FillAsync(string selector, string text, WaitForSelectorOptions options = null);
/// <summary>
/// Waits for a selector to be added to the DOM
/// </summary>
/// <param name="selector">A selector of an element to wait for</param>
/// <param name="options">Optional waiting parameters</param>
/// <returns>A task that completes when element specified by selector string is added to DOM, yielding the <see cref="IElementHandle"/> to wait for.
/// Resolves to `null` if waiting for `hidden: true` and selector is not found in DOM.</returns>
public Task<IElementHandle> WaitForSelectorAsync(string selector, WaitForSelectorOptions options = null);
/// <summary>
/// Executes a script in browser context
/// </summary>
@ -274,5 +341,44 @@ namespace PlaywrightSharp
/// </remarks>
/// <returns>A <see cref="Task"/> that completes when the tag is added, yielding the added tag when the script's onload fires or when the script content was injected into frame</returns>
Task<IElementHandle> AddScriptTagAsync(AddTagOptions options);
/// <summary>
/// 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.
/// </summary>
/// <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>
/// <param name="options">click options</param>
/// <returns>A <see cref="Task"/> that completes when the element matching <paramref name="selector"/> is successfully clicked</returns>
Task ClickAsync(string selector, ClickOptions options = null);
/// <summary>
/// Fetches an element with <paramref name="selector"/>, scrolls it into view if needed, and then uses <see cref="Mouse"/> to triple click in the center of the element.
/// </summary>
/// <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>
/// <param name="options">click options</param>
/// <returns>A <see cref="Task"/> that completes when the element matching <paramref name="selector"/> is successfully triple clicked</returns>
Task TripleClickAsync(string selector, ClickOptions options = null);
/// <summary>
/// Sets the viewport.
/// In the case of multiple pages in a single browser, each page can have its own viewport size.
/// <see cref="SetViewportAsync(Viewport)"/> 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.
/// </summary>
/// <example>
///<![CDATA[
/// using(var page = await context.NewPageAsync())
/// {
/// await page.SetViewPortAsync(new Viewport
/// {
/// Width = 640,
/// Height = 480,
/// DeviceScaleFactor = 1
/// });
/// await page.GoToAsync('https://www.example.com');
/// }
/// ]]>
/// </example>
/// <param name="viewport">Viewport</param>
/// <returns>A<see cref="Task"/> that copletes when the message is confirmed by the browser</returns>
Task SetViewportAsync(Viewport viewport);
}
}

Просмотреть файл

@ -0,0 +1,28 @@
namespace PlaywrightSharp
{
/// <summary>
/// The type of button click to use with <see cref="IPage.ClickAsync(string, ClickOptions)"/>
/// </summary>
public enum MouseButton
{
/// <summary>
/// Non specified
/// </summary>
None,
/// <summary>
/// The left mouse button
/// </summary>
Left,
/// <summary>
/// The right mouse button
/// </summary>
Right,
/// <summary>
/// The middle mouse button
/// </summary>
Middle
}
}

Просмотреть файл

@ -0,0 +1,13 @@
namespace PlaywrightSharp
{
/// <summary>
/// Options for <see cref="IMouse.MoveAsync(decimal, decimal, MoveOptions)"/>
/// </summary>
public class MoveOptions
{
/// <summary>
/// Sends intermediate <c>mousemove</c> events. Defaults to 1
/// </summary>
public int Steps { get; set; } = 1;
}
}

Просмотреть файл

@ -24,4 +24,4 @@
/// <value>The referer.</value>
public string Referer { get; set; }
}
}
}

Просмотреть файл

@ -0,0 +1,14 @@
namespace PlaywrightSharp
{
/// <summary>
/// Options for <see cref="IPage.CloseAsync(PageCloseOptions)"/>.
/// </summary>
public class PageCloseOptions
{
/// <summary>
/// Defaults to <c>false</c>. Whether to run the beforeunload page handlers.
/// </summary>
/// <see href="https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload"/>
public bool RunBeforeUnload { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,25 @@
namespace PlaywrightSharp
{
/// <summary>
/// Options for <see cref="ClickOptions.WaitFor"/>
/// </summary>
public enum WaitForOptions
{
/// <summary>
/// Wait for visible
/// </summary>
Visible,
/// <summary>
/// Wait for hidden
/// </summary>
Hidden,
/// <summary>
/// Wait for any
/// </summary>
Any,
/// <summary>
/// No wait
/// </summary>
NoWait
}
}

Просмотреть файл

@ -0,0 +1,11 @@
namespace PlaywrightSharp
{
/// <summary>
/// Optional waiting parameters.
/// </summary>
/// <seealso cref="IPage.WaitForSelectorAsync(string, WaitForSelectorOptions)"/>
/// <seealso cref="IFrame.WaitForSelectorAsync(string, WaitForSelectorOptions)"/>
public class WaitForSelectorOptions
{
}
}

Просмотреть файл

@ -25,4 +25,4 @@
/// </summary>
Networkidle2
}
}
}

Просмотреть файл

@ -25,7 +25,7 @@ namespace PlaywrightSharp.Tests.BaseTests
}
}
internal Task<IBrowserContext> NewContextAsync(BrowserContextOptions options) => Browser.NewContextAsync(options);
internal Task<IBrowserContext> NewContextAsync(BrowserContextOptions options = null) => Browser.NewContextAsync(options);
internal async Task<IPage> NewPageAsync(BrowserContextOptions options = null)
{

Просмотреть файл

@ -0,0 +1,599 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading.Tasks;
using PlaywrightSharp.Tests.Attributes;
using PlaywrightSharp.Tests.BaseTests;
using Xunit;
using Xunit.Abstractions;
namespace PlaywrightSharp.Tests.Page
{
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
public class ClickTests : PlaywrightSharpPageBaseTest
{
/// <inheritdoc/>
public ClickTests(ITestOutputHelper output) : base(output)
{
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click the button</playwright-it>
[Fact]
public async Task ShouldClickTheButton()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.ClickAsync("button");
Assert.Equal("Clicked", await Page.EvaluateAsync<string>("result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click svg</playwright-it>
[Fact]
public async Task ShouldClickSvg()
{
await Page.SetContentAsync($@"
<svg height=""100"" width=""100"">
<circle onclick=""javascript:window.__CLICKED=42"" cx=""50"" cy=""50"" r=""40"" stroke=""black"" stroke-width=""3"" fill=""red""/>
</svg>
");
await Page.ClickAsync("circle");
Assert.Equal(42, await Page.EvaluateAsync<int>("() => window.__CLICKED"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click svg</playwright-it>
[Fact]
public async Task ShouldClickTheButtonIfWindowNodeIsRemoved()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.EvaluateAsync("delete window.Node");
await Page.ClickAsync("button");
Assert.Equal("Clicked", await Page.EvaluateAsync<string>("result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click on a span with an inline element inside</playwright-it>
[Fact]
public async Task ShouldClickOnASpanWithAnInlineElementInside()
{
await Page.SetContentAsync($@"
<style>
span::before {{
content: 'q';
}}
</style>
<span onclick='javascript:window.CLICKED=42'></span>
");
await Page.ClickAsync("span");
Assert.Equal(42, await Page.EvaluateAsync<int>("() => window.CLICKED"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should not throw UnhandledPromiseRejection when page closes</playwright-it>
[Fact]
public async Task ShouldGracefullyFailWhenPageCloses()
{
var context = await NewContextAsync();
var newPage = await context.NewPageAsync();
await Assert.ThrowsAsync<TargetClosedException>(() => Task.WhenAll(
newPage.CloseAsync(),
newPage.Mouse.ClickAsync(1, 2)
));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click the button after navigation </playwright-it>
[Fact]
public async Task ShouldClickTheButtonAfterNavigation()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.ClickAsync("button");
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.ClickAsync("button");
Assert.Equal("Clicked", await Page.EvaluateAsync<string>("result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click the button after a cross origin navigation </playwright-it>
[Fact]
public async Task ShouldClickTheButtonAfterACrossOriginNavigation()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.ClickAsync("button");
await Page.GoToAsync(TestConstants.CrossProcessHttpPrefix + "/input/button.html");
await Page.ClickAsync("button");
Assert.Equal("Clicked", await Page.EvaluateAsync<string>("result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click with disabled javascript</playwright-it>
[Fact]
public async Task ShouldClickWithDisabledJavascript()
{
var page = await NewPageAsync(new BrowserContextOptions { JavaScriptEnabled = false });
await page.GoToAsync(TestConstants.ServerUrl + "/wrappedlink.html");
await Task.WhenAll(
page.ClickAsync("a"),
page.WaitForNavigationAsync()
);
Assert.Equal(TestConstants.ServerUrl + "/wrappedlink.html#clicked", Page.Url);
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click when one of inline box children is outside of viewport</playwright-it>
[Fact]
public async Task ShouldClickWhenOneOfInlineBoxChildrenIsOutsideOfViewport()
{
await Page.SetContentAsync($@"
<style>
i {{
position: absolute;
top: -1000px;
}}
</style>
<span onclick='javascript:window.CLICKED = 42;'><i>woof</i><b>doggo</b></span>
");
await Page.ClickAsync("span");
Assert.Equal(42, await Page.EvaluateAsync<int>("() => window.CLICKED"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should select the text by triple clicking</playwright-it>
[Fact]
public async Task ShouldSelectTheTextByTripleClicking()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/textarea.html");
const string text = "This is the text that we are going to try to select. Let's see how it goes.";
await Page.FillAsync("textarea", text);
await Page.TripleClickAsync("textarea");
Assert.Equal(text, await Page.EvaluateAsync<string>("window.getSelection().toString()"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click offscreen buttons</playwright-it>
[Fact]
public async Task ShouldClickOffscreenButtons()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/offscreenbuttons.html");
var messages = new List<string>();
Page.Console += (sender, e) => messages.Add(e.Message.Text);
for (int i = 0; i < 11; ++i)
{
// We might've scrolled to click a button - reset to (0, 0).
await Page.EvaluateAsync("() => window.scrollTo(0, 0)");
await Page.ClickAsync($"#btn{i}");
}
Assert.Equal(new List<string>
{
"button #0 clicked",
"button #1 clicked",
"button #2 clicked",
"button #3 clicked",
"button #4 clicked",
"button #5 clicked",
"button #6 clicked",
"button #7 clicked",
"button #8 clicked",
"button #9 clicked",
"button #10 clicked"
}, messages);
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should waitFor visible when already visible</playwright-it>
[Fact]
public async Task ShouldWaitForVisibleWhenAlreadyVisible()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.ClickAsync("button");
Assert.Equal("Clicked", await Page.EvaluateAsync<string>("result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should waitFor hidden when already hidden</playwright-it>
[Fact]
public async Task ShouldWaitForHiddenWhenAlreadyHidden()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.QuerySelectorEvaluateAsync("button", "b => b.style.display = 'none'");
var exception = await Assert.ThrowsAsync<PlaywrightSharpException>(()
=> Page.ClickAsync("button", new ClickOptions { WaitFor = WaitForOptions.Hidden }));
Assert.Equal("Node is either not visible or not an HTMLElement", exception.Message);
Assert.Equal("Was not clicked", await Page.EvaluateAsync<string>("result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should waitFor hidden</playwright-it>
[Fact]
public async Task ShouldWaitForHidden()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
var clickTask = Page.ClickAsync("button", new ClickOptions { WaitFor = WaitForOptions.Hidden });
for (int i = 0; i < 5; i++)
{
await Page.EvaluateAsync("1");
}
Assert.False(clickTask.IsCompleted);
await Page.QuerySelectorEvaluateAsync("button", "b => b.style.display = 'none'");
var exception = await Assert.ThrowsAsync<PlaywrightSharpException>(() => clickTask);
Assert.Equal("Node is either not visible or not an HTMLElement", exception.Message);
Assert.Equal("Was not clicked", await Page.EvaluateAsync<string>("result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should waitFor visible</playwright-it>
[Fact]
public async Task ShouldWaitForVisible()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.QuerySelectorEvaluateAsync("button", "b => b.style.display = 'none'");
var clickTask = Page.ClickAsync("button");
for (int i = 0; i < 5; i++)
{
await Page.EvaluateAsync("1");
}
Assert.False(clickTask.IsCompleted);
await Page.QuerySelectorEvaluateAsync("button", "b => b.style.display = 'block'");
Assert.True(clickTask.IsCompleted);
Assert.Equal("Clicked", await Page.EvaluateAsync<string>("result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click wrapped links</playwright-it>
[Fact]
public async Task ShouldClickWrappedLinks()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/wrappedlink.html");
await Page.ClickAsync("a");
Assert.True(await Page.EvaluateAsync<bool>("window.__clicked"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click on checkbox input and toggle</playwright-it>
[Fact]
public async Task ShouldClickOnCheckboxInputAndToggle()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/checkbox.html");
Assert.Null(await Page.EvaluateAsync("result.check"));
await Page.ClickAsync("input#agree");
Assert.True(await Page.EvaluateAsync<bool>("result.check"));
Assert.Equal(new[] {
"mouseover",
"mouseenter",
"mousemove",
"mousedown",
"mouseup",
"click",
"input",
"change"
}, await Page.EvaluateAsync<string[]>("result.events"));
await Page.ClickAsync("input#agree");
Assert.False(await Page.EvaluateAsync<bool>("result.check"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click on checkbox label and toggle</playwright-it>
[Fact]
public async Task ShouldClickOnCheckboxLabelAndToggle()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/checkbox.html");
Assert.Null(await Page.EvaluateAsync("result.check"));
await Page.ClickAsync("label[for=\"agree\"]");
Assert.True(await Page.EvaluateAsync<bool>("result.check"));
Assert.Equal(new[] {
"click",
"input",
"change"
}, await Page.EvaluateAsync<string[]>("result.events"));
await Page.ClickAsync("label[for=\"agree\"]");
Assert.False(await Page.EvaluateAsync<bool>("result.check"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should fail to click a missing button</playwright-it>
[Fact]
public async Task ShouldFailToClickAMissingButton()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
var exception = await Assert.ThrowsAsync<SelectorException>(()
=> Page.ClickAsync("button.does-not-exist"));
Assert.Equal("No node found for selector: button.does-not-exist", exception.Message);
Assert.Equal("button.does-not-exist", exception.Selector);
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should not hang with touch-enabled viewports</playwright-it>
[Fact]
public async Task ShouldNotHangWithTouchEnabledViewports()
{
await Page.SetViewportAsync(TestConstants.IPhone.ViewPort);
await Page.Mouse.DownAsync();
await Page.Mouse.MoveAsync(100, 10);
await Page.Mouse.UpAsync();
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should scroll and click the button</playwright-it>
[Fact]
public async Task ShouldScrollAndClickTheButton()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/scrollable.html");
await Page.ClickAsync("#button-5");
Assert.Equal("clicked", await Page.EvaluateAsync<string>("document.querySelector(\"#button-5\").textContent"));
await Page.ClickAsync("#button-80");
Assert.Equal("clicked", await Page.EvaluateAsync<string>("document.querySelector(\"#button-80\").textContent"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should double click the button</playwright-it>
[Fact]
public async Task ShouldDoubleClickTheButton()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.EvaluateAsync(@"{
window.double = false;
const button = document.querySelector('button');
button.addEventListener('dblclick', event => {
window.double = true;
});
}");
var button = await Page.QuerySelectorAsync("button");
await button.ClickAsync(new ClickOptions { ClickCount = 2 });
Assert.True(await Page.EvaluateAsync<bool>("double"));
Assert.Equal("Clicked", await Page.EvaluateAsync<string>("result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click a partially obscured button</playwright-it>
[Fact]
public async Task ShouldClickAPartiallyObscuredButton()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.EvaluateAsync(@"{
const button = document.querySelector('button');
button.textContent = 'Some really long text that will go offscreen';
button.style.position = 'absolute';
button.style.left = '368px';
}");
await Page.ClickAsync("button");
Assert.Equal("Clicked", await Page.EvaluateAsync<string>("result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click a rotated button</playwright-it>
[Fact]
public async Task ShouldClickARotatedButton()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/rotatedButton.html");
await Page.ClickAsync("button");
Assert.Equal("Clicked", await Page.EvaluateAsync<string>("result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should fire contextmenu event on right click</playwright-it>
[Fact]
public async Task ShouldFireContextmenuEventOnRightClick()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/scrollable.html");
await Page.ClickAsync("#button-8", new ClickOptions { Button = MouseButton.Right });
Assert.Equal("context menu", await Page.EvaluateAsync<string>("document.querySelector('#button-8').textContent"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click links which cause navigation</playwright-it>
[Fact]
public async Task ShouldClickLinksWhichCauseNavigation()
{
await Page.SetContentAsync($"<a href=\"{TestConstants.EmptyPage}\">empty.html</a>");
// This await should not hang.
await Page.ClickAsync("a");
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click the button inside an iframe</playwright-it>
[Fact]
public async Task ShouldClickTheButtonInsideAnIframe()
{
await Page.GoToAsync(TestConstants.EmptyPage);
await Page.SetContentAsync("<div style=\"width:100px;height:100px\">spacer</div>");
await FrameUtils.AttachFrameAsync(Page, "button-test", TestConstants.ServerUrl + "/input/button.html");
var frame = Page.FirstChildFrame();
var button = await frame.QuerySelectorAsync("button");
await button.ClickAsync();
Assert.Equal("Clicked", await frame.EvaluateAsync<string>("window.result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click the button with fixed position inside an iframe</playwright-it>
[Fact(Skip = "See test in playwright")]
public async Task ShouldClickTheButtonWithFixedPositionInsideAnIframe()
{
await Page.GoToAsync(TestConstants.EmptyPage);
await Page.SetViewportAsync(new Viewport
{
Width = 500,
Height = 500
});
await Page.SetContentAsync("<div style=\"width:100px;height:2000px\">spacer</div>");
await FrameUtils.AttachFrameAsync(Page, "button-test", TestConstants.ServerUrl + "/input/button.html");
var frame = Page.FirstChildFrame();
await frame.QuerySelectorEvaluateAsync("button", "button => button.style.setProperty('position', 'fixed')");
await frame.ClickAsync("button");
Assert.Equal("Clicked", await frame.EvaluateAsync<string>("window.result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click the button with deviceScaleFactor set</playwright-it>
[Fact]
public async Task ShouldClickTheButtonWithDeviceScaleFactorSet()
{
await Page.SetViewportAsync(new Viewport { Width = 400, Height = 400, DeviceScaleFactor = 5 });
Assert.Equal(5, await Page.EvaluateAsync<int>("window.devicePixelRatio"));
await Page.SetContentAsync("<div style=\"width:100px;height:100px\">spacer</div>");
await FrameUtils.AttachFrameAsync(Page, "button-test", TestConstants.ServerUrl + "/input/button.html");
var frame = Page.FirstChildFrame();
var button = await frame.QuerySelectorAsync("button");
await button.ClickAsync();
Assert.Equal("Clicked", await frame.EvaluateAsync<string>("window.result"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click the button with px border with relative point</playwright-it>
[Fact]
public async Task ShouldClickTheButtonWithPxBorderWithRelativePoint()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.QuerySelectorEvaluateAsync("button", "button => button.style.borderWidth = '8px'");
await Page.ClickAsync("button", new ClickOptions { RelativePoint = new Point { X = 20, Y = 10 } });
Assert.Equal("Clicked", await Page.EvaluateAsync<string>("window.result"));
// Safari reports border-relative offsetX/offsetY.
Assert.Equal(TestConstants.IsWebKit ? 20 + 8 : 20, await Page.EvaluateAsync<int>("offsetX"));
Assert.Equal(TestConstants.IsWebKit ? 10 + 8 : 10, await Page.EvaluateAsync<int>("offsetY"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click the button with em border with relative point</playwright-it>
[Fact]
public async Task ShouldClickTheButtonWithEmBorderWithRelativePoint()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.QuerySelectorEvaluateAsync("button", "button => button.style.borderWidth = '2em'");
await Page.QuerySelectorEvaluateAsync("button", "button => button.style.fontSize = '12px'");
await Page.ClickAsync("button", new ClickOptions { RelativePoint = new Point { X = 20, Y = 10 } });
Assert.Equal("Clicked", await Page.EvaluateAsync<string>("window.result"));
// Safari reports border-relative offsetX/offsetY.
Assert.Equal(TestConstants.IsWebKit ? 12 * 2 + 20 : 20, await Page.EvaluateAsync<int>("offsetX"));
Assert.Equal(TestConstants.IsWebKit ? 12 * 2 + 20 : 10, await Page.EvaluateAsync<int>("offsetY"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click a very large button with relative point</playwright-it>
[Fact]
public async Task ShouldClickAVeryLargeButtonWithRelativePoint()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.QuerySelectorEvaluateAsync("button", "button => button.style.borderWidth = '8px'");
await Page.QuerySelectorEvaluateAsync("button", "button.style.height = button.style.width = '2000px'");
await Page.ClickAsync("button", new ClickOptions { RelativePoint = new Point { X = 1900, Y = 1910 } });
Assert.Equal("Clicked", await Page.EvaluateAsync<string>("window.result"));
// Safari reports border-relative offsetX/offsetY.
Assert.Equal(TestConstants.IsWebKit ? 1900 + 8 : 1900, await Page.EvaluateAsync<int>("offsetX"));
Assert.Equal(TestConstants.IsWebKit ? 1910 + 8 : 1910, await Page.EvaluateAsync<int>("offsetY"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click a button in scrolling container with relative point</playwright-it>
[Fact(Skip = "Skipped in Playwright")]
public async Task ShouldClickAButtonInScrollingContainerWithRelativePoint()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.QuerySelectorEvaluateAsync("button", @"button => {
const container = document.createElement('div');
container.style.overflow = 'auto';
container.style.width = '200px';
container.style.height = '200px';
button.parentElement.insertBefore(container, button);
container.appendChild(button);
button.style.height = '2000px';
button.style.width = '2000px';
}");
await Page.ClickAsync("button", new ClickOptions { RelativePoint = new Point { X = 1900, Y = 1910 } });
Assert.Equal("Clicked", await Page.EvaluateAsync<string>("window.result"));
// Safari reports border-relative offsetX/offsetY.
Assert.Equal(1900, await Page.EvaluateAsync<int>("offsetX"));
Assert.Equal(1910, await Page.EvaluateAsync<int>("offsetY"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should update modifiers correctly</playwright-it>
[SkipBrowserAndPlayformFact(skipWebkit: true)]
public async Task ShouldUpdateModifiersCorrectly()
{
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
await Page.ClickAsync("button", new ClickOptions { Modifiers = new[] { ClickModifier.Shift } });
Assert.True(await Page.EvaluateAsync<bool>("shiftKey"));
await Page.ClickAsync("button", new ClickOptions { Modifiers = new ClickModifier[] { } });
Assert.False(await Page.EvaluateAsync<bool>("shiftKey"));
await Page.Keyboard.DownAsync("Shift");
await Page.ClickAsync("button", new ClickOptions { Modifiers = new ClickModifier[] { } });
Assert.False(await Page.EvaluateAsync<bool>("shiftKey"));
await Page.ClickAsync("button");
Assert.True(await Page.EvaluateAsync<bool>("shiftKey"));
await Page.Keyboard.UpAsync("Shift");
await Page.ClickAsync("button");
Assert.False(await Page.EvaluateAsync<bool>("shiftKey"));
}
///<playwright-file>click.spec.js</playwright-file>
///<playwright-describe>Page.click</playwright-describe>
///<playwright-it>should click an offscreen element when scroll-behavior is smooth</playwright-it>
[SkipBrowserAndPlayformFact(skipChromium: true)]
public async Task ShouldClickAnOffscreenElementWhenScrollBehaviorIsSmooth()
{
await Page.SetContentAsync(@$"
<div style=""border: 1px solid black; height: 500px; overflow: auto; width: 500px; scroll-behavior: smooth"">
<button style=""margin-top: 2000px"" onClick=""window.clicked = true"" >hi</button>
</div>");
await Page.ClickAsync("button");
Assert.True(await Page.EvaluateAsync<bool>("window.clicked"));
}
}
}

Просмотреть файл

@ -0,0 +1,10 @@
using System;
using System.Linq;
namespace PlaywrightSharp.Tests
{
internal static class PageExtensions
{
public static IFrame FirstChildFrame(this IPage page) => page.Frames.FirstOrDefault(f => f.ParentFrame == page.MainFrame);
}
}

Просмотреть файл

@ -0,0 +1,31 @@
namespace PlaywrightSharp
{
/// <summary>
/// Exception thrown when an element selector returns null.
/// </summary>
public class SelectorException : PlaywrightSharpException
{
/// <summary>
/// Gets the selector.
/// </summary>
/// <value>The selector.</value>
public string Selector { get; }
/// <summary>
/// Initializes a new instance of the <see cref="SelectorException"/> class.
/// </summary>
/// <param name="message">Message.</param>
public SelectorException(string message) : base(message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SelectorException"/> class.
/// </summary>
/// <param name="message">Message.</param>
/// <param name="selector">Selector.</param>
public SelectorException(string message, string selector) : base(message)
{
Selector = selector;
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
namespace PlaywrightSharp
{
/// <summary>
/// Exception thrown by a connection when it detects that the target was closed.
/// </summary>
public class TargetClosedException : PlaywrightSharpException
{
/// <summary>
/// Close Reason.
/// </summary>
/// <value>The close reason.</value>
public string CloseReason { get; }
/// <summary>
/// Initializes a new instance of the <see cref="TargetClosedException"/> class.
/// </summary>
/// <param name="message">Message.</param>
/// <param name="closeReason">Close reason.</param>
public TargetClosedException(string message, string closeReason) : base($"{message} ({closeReason})")
=> CloseReason = closeReason;
}
}