Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Common/Version.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<AssemblyVersion>1.65.0</AssemblyVersion>
<PackageVersion>$(AssemblyVersion)</PackageVersion>
<DriverVersion>5ccfbd85521679ebf5ab4d836852bf1c544aa748</DriverVersion>
<DriverVersion>8534271f0413bae6a455b7cf43b2637391bc614b</DriverVersion>
<!-- The Node.js major version bundled with the driver. Each driver build bundles the
latest release of it. Set by the roll script to the latest Node.js LTS, matching
upstream's utils/build/update-playwright-node.mjs. -->
Expand Down
20 changes: 20 additions & 0 deletions src/Playwright.Tests/SelectorsGetByTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public async Task GetByTextShouldWork()
StringAssert.Contains(">Hello</div>", await Page.GetByText("Hello", new() { Exact = true }).EvaluateAsync<string>("e => e.outerHTML"));
}

// See https://github.com/microsoft/playwright/issues/43898
[PlaywrightTest("selector-get-by.spec.ts", "getByLabel should work")]
public async Task GetByLabelShouldWork()
{
Expand All @@ -106,6 +107,25 @@ public async Task GetByLabelShouldWork()
Assert.AreEqual(await Page.GetByLabel("Name").EvaluateAsync<string>("e => e.nodeName"), "INPUT");
Assert.AreEqual(await Page.MainFrame.GetByLabel("Name").EvaluateAsync<string>("e => e.nodeName"), "INPUT");
Assert.AreEqual(await Page.Locator("div").GetByLabel("Name").EvaluateAsync<string>("e => e.nodeName"), "INPUT");

await Page.SetContentAsync(@"
<label for=""city"">City</label><my-field id=""city"" role=""combobox"">Pick one</my-field>
<label>Street <my-field id=""street"" role=""combobox"">Pick one</my-field></label>
");
await Page.EvaluateAsync(@"() => {
customElements.define('my-field', class extends HTMLElement {
static formAssociated = true;
constructor() {
super();
this.attachInternals();
}
});
}");
Assert.AreEqual(new[] { "city", "street" }, await Page.EvaluateAsync<string[]>("() => [...document.querySelectorAll('label')].map(label => label.control?.id)"));
Assert.AreEqual(new[] { "city" }, await Page.GetByLabel("City").EvaluateAllAsync<string[]>("elements => elements.map(e => e.id)"));
Assert.AreEqual(new[] { "street" }, await Page.GetByLabel("Street").EvaluateAllAsync<string[]>("elements => elements.map(e => e.id)"));
Assert.AreEqual(new[] { "city" }, await Page.GetByRole(AriaRole.Combobox, new() { Name = "City", Exact = true }).EvaluateAllAsync<string[]>("elements => elements.map(e => e.id)"));
Assert.AreEqual(new[] { "street" }, await Page.GetByRole(AriaRole.Combobox, new() { Name = "Street", Exact = true }).EvaluateAllAsync<string[]>("elements => elements.map(e => e.id)"));
}

[PlaywrightTest("selector-get-by.spec.ts", "getByLabel should work with nested elements")]
Expand Down
19 changes: 13 additions & 6 deletions src/Playwright/API/Generated/IBrowserContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1015,12 +1015,19 @@ public partial interface IBrowserContext

/// <param name="offline">
/// Whether to emulate network being offline for the browser context.
/// Offline emulation only affects requests that go through the browser's regular network
/// stack, such as page navigations, <c>fetch()</c>, <c>XMLHttpRequest</c> and WebSockets.
/// It does not affect WebRTC traffic: established <c>RTCPeerConnection</c>s keep sending
/// and receiving media over UDP. To test WebRTC connection loss, interrupt the connection
/// outside the browser, for example by stopping the TURN server or using an OS-level
/// firewall.
/// Offline emulation affects HTTP requests, such as page navigations, <c>fetch()</c>
/// and <c>XMLHttpRequest</c>.
/// WebSocket behavior depends on the browser and whether the connection is already
/// established. Chromium and Firefox fail new WebSocket connections while offline,
/// but do not close already-open connections. Chromium can defer incoming messages
/// until the context goes back online, rather than lose them; Firefox can continue
/// delivering messages while offline. WebKit can allow both new WebSocket connections
/// and traffic on established connections while offline. Do not rely on offline emulation
/// to test WebSocket message loss or connection closure.
/// Offline emulation does not affect WebRTC traffic: established <c>RTCPeerConnection</c>s
/// keep sending and receiving media over UDP. To test WebRTC connection loss, interrupt
/// the connection outside the browser, for example by stopping the TURN server or using
/// an OS-level firewall.
/// </param>
Task SetOfflineAsync(bool offline);

Expand Down
8 changes: 8 additions & 0 deletions src/Playwright/API/Generated/IFrame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,10 @@ public partial interface IFrame
/// Allows locating input elements by the text of the associated <c>&lt;label&gt;</c>
/// or <c>aria-labelledby</c> element, or by the <c>aria-label</c> attribute.
/// </para>
/// <para>
/// Associated <c>&lt;label&gt;</c> elements are also supported for form-associated
/// custom elements.
/// </para>
/// <para>**Usage**</para>
/// <para>
/// For example, this method will find inputs by label "Username" and "Password" in
Expand All @@ -595,6 +599,10 @@ public partial interface IFrame
/// Allows locating input elements by the text of the associated <c>&lt;label&gt;</c>
/// or <c>aria-labelledby</c> element, or by the <c>aria-label</c> attribute.
/// </para>
/// <para>
/// Associated <c>&lt;label&gt;</c> elements are also supported for form-associated
/// custom elements.
/// </para>
/// <para>**Usage**</para>
/// <para>
/// For example, this method will find inputs by label "Username" and "Password" in
Expand Down
8 changes: 8 additions & 0 deletions src/Playwright/API/Generated/IFrameLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ public partial interface IFrameLocator
/// Allows locating input elements by the text of the associated <c>&lt;label&gt;</c>
/// or <c>aria-labelledby</c> element, or by the <c>aria-label</c> attribute.
/// </para>
/// <para>
/// Associated <c>&lt;label&gt;</c> elements are also supported for form-associated
/// custom elements.
/// </para>
/// <para>**Usage**</para>
/// <para>
/// For example, this method will find inputs by label "Username" and "Password" in
Expand All @@ -142,6 +146,10 @@ public partial interface IFrameLocator
/// Allows locating input elements by the text of the associated <c>&lt;label&gt;</c>
/// or <c>aria-labelledby</c> element, or by the <c>aria-label</c> attribute.
/// </para>
/// <para>
/// Associated <c>&lt;label&gt;</c> elements are also supported for form-associated
/// custom elements.
/// </para>
/// <para>**Usage**</para>
/// <para>
/// For example, this method will find inputs by label "Username" and "Password" in
Expand Down
80 changes: 80 additions & 0 deletions src/Playwright/API/Generated/IFunctionAssertions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* MIT License
*
* Copyright (c) Microsoft Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

using System.Threading.Tasks;

namespace Microsoft.Playwright;

/// <summary>
/// <para>
/// The <see cref="IFunctionAssertions"/> class provides assertion methods that retry
/// a block of code. A new instance of <see cref="IFunctionAssertions"/> is created
/// by calling <see cref="IPlaywrightAssertions.Expect"/>:
/// </para>
/// <code>
/// using Microsoft.Playwright;<br/>
/// using Microsoft.Playwright.MSTest;<br/>
/// <br/>
/// namespace PlaywrightTests;<br/>
/// <br/>
/// [TestClass]<br/>
/// public class ExampleTests : PageTest<br/>
/// {<br/>
/// [TestMethod]<br/>
/// public async Task ApiEventuallySucceeds()<br/>
/// {<br/>
/// await Expect(async () =&gt;<br/>
/// {<br/>
/// var response = await Page.APIRequest.GetAsync("https://api.example.com");<br/>
/// Assert.AreEqual(200, response.Status);<br/>
/// }).ToPassAsync();<br/>
/// }<br/>
/// }
/// </code>
/// </summary>
public partial interface IFunctionAssertions
{
/// <summary>
/// <para>
/// Retries the callback until it completes without throwing an exception, or until
/// the timeout is reached. When the timeout is reached, throws a <see cref="PlaywrightAssertionException"/>
/// with the last exception that the callback has thrown.
/// </para>
/// <para>**Usage**</para>
/// <code>
/// await Expect(async () =&gt;<br/>
/// {<br/>
/// var response = await Page.APIRequest.GetAsync("https://api.example.com");<br/>
/// Assert.AreEqual(200, response.Status);<br/>
/// }).ToPassAsync(new()<br/>
/// {<br/>
/// // Probe, wait 1s, probe, wait 2s, probe, wait 10s, probe, wait 10s, probe<br/>
/// Intervals = [1_000, 2_000, 10_000],<br/>
/// Timeout = 60_000,<br/>
/// });
/// </code>
/// </summary>
/// <param name="options">Call options</param>
Task ToPassAsync(FunctionAssertionsToPassOptions? options = default);
}
8 changes: 8 additions & 0 deletions src/Playwright/API/Generated/ILocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,10 @@ public partial interface ILocator
/// Allows locating input elements by the text of the associated <c>&lt;label&gt;</c>
/// or <c>aria-labelledby</c> element, or by the <c>aria-label</c> attribute.
/// </para>
/// <para>
/// Associated <c>&lt;label&gt;</c> elements are also supported for form-associated
/// custom elements.
/// </para>
/// <para>**Usage**</para>
/// <para>
/// For example, this method will find inputs by label "Username" and "Password" in
Expand All @@ -747,6 +751,10 @@ public partial interface ILocator
/// Allows locating input elements by the text of the associated <c>&lt;label&gt;</c>
/// or <c>aria-labelledby</c> element, or by the <c>aria-label</c> attribute.
/// </para>
/// <para>
/// Associated <c>&lt;label&gt;</c> elements are also supported for form-associated
/// custom elements.
/// </para>
/// <para>**Usage**</para>
/// <para>
/// For example, this method will find inputs by label "Username" and "Password" in
Expand Down
8 changes: 8 additions & 0 deletions src/Playwright/API/Generated/IPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,10 @@ public partial interface IPage
/// Allows locating input elements by the text of the associated <c>&lt;label&gt;</c>
/// or <c>aria-labelledby</c> element, or by the <c>aria-label</c> attribute.
/// </para>
/// <para>
/// Associated <c>&lt;label&gt;</c> elements are also supported for form-associated
/// custom elements.
/// </para>
/// <para>**Usage**</para>
/// <para>
/// For example, this method will find inputs by label "Username" and "Password" in
Expand All @@ -1070,6 +1074,10 @@ public partial interface IPage
/// Allows locating input elements by the text of the associated <c>&lt;label&gt;</c>
/// or <c>aria-labelledby</c> element, or by the <c>aria-label</c> attribute.
/// </para>
/// <para>
/// Associated <c>&lt;label&gt;</c> elements are also supported for form-associated
/// custom elements.
/// </para>
/// <para>**Usage**</para>
/// <para>
/// For example, this method will find inputs by label "Username" and "Password" in
Expand Down
17 changes: 17 additions & 0 deletions src/Playwright/API/Generated/IPlaywrightAssertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
* SOFTWARE.
*/

using System;
using System.Threading.Tasks;

namespace Microsoft.Playwright;

/// <summary>
Expand Down Expand Up @@ -64,6 +67,20 @@ public partial interface IPlaywrightAssertions
/// <param name="response"><see cref="IAPIResponse"/> object to use for assertions.</param>
IAPIResponseAssertions Expect(IAPIResponse response);

/// <summary>
/// <para>Creates a <see cref="IFunctionAssertions"/> object for the given callback.</para>
/// <para>**Usage**</para>
/// <code>
/// await Expect(async () =&gt;<br/>
/// {<br/>
/// var response = await Page.APIRequest.GetAsync("https://api.example.com");<br/>
/// Assert.AreEqual(200, response.Status);<br/>
/// }).ToPassAsync();
/// </code>
/// </summary>
/// <param name="callback">Callback to retry. A synchronous <c>Action</c> is accepted as well.</param>
IFunctionAssertions Expect(Func<Task> callback);

/// <summary>
/// <para>Creates a <see cref="ILocatorAssertions"/> object for the given <see cref="ILocator"/>.</para>
/// <para>**Usage**</para>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* MIT License
*
* Copyright (c) Microsoft Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace Microsoft.Playwright;

public class FunctionAssertionsToPassOptions
{
public FunctionAssertionsToPassOptions() { }

public FunctionAssertionsToPassOptions(FunctionAssertionsToPassOptions clone)
{
if (clone == null)
{
return;
}

Intervals = clone.Intervals;
Timeout = clone.Timeout;
}

/// <summary>
/// <para>
/// Time to wait between the retries in milliseconds. The last interval is used for
/// all the following retries. Defaults to <c>[100, 250, 500, 1000]</c>.
/// </para>
/// </summary>
[JsonPropertyName("intervals")]
public IEnumerable<int>? Intervals { get; set; }

/// <summary>
/// <para>
/// Time to retry the callback for in milliseconds. Defaults to <c>30000</c>, change
/// the default with <c>SetDefaultExpectToPassTimeout</c>. Pass <c>0</c> to disable
/// the timeout.
/// </para>
/// </summary>
[JsonPropertyName("timeout")]
public float? Timeout { get; set; }
}
4 changes: 4 additions & 0 deletions src/Playwright/Assertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
* SOFTWARE.
*/

using System;
using System.Threading.Tasks;
using Microsoft.Playwright.Core;

namespace Microsoft.Playwright;
Expand All @@ -45,6 +47,8 @@ public static class Assertions

public static IAPIResponseAssertions Expect(IAPIResponse response) => new APIResponseAssertions(response, false);

public static IFunctionAssertions Expect(Func<Task> callback) => new FunctionAssertions(callback);

/// <summary>
/// Creates assertions that prefix any failure message with <paramref name="message"/>, providing
/// extra context in test reports.
Expand Down
41 changes: 41 additions & 0 deletions src/Playwright/Core/FunctionAssertions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* MIT License
*
* Copyright (c) Microsoft Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

using System;
using System.Threading.Tasks;

namespace Microsoft.Playwright.Core;

internal class FunctionAssertions : IFunctionAssertions
{
private readonly Func<Task> _callback;

public FunctionAssertions(Func<Task> callback)
{
_callback = callback ?? throw new ArgumentNullException(nameof(callback));
}

public Task ToPassAsync(FunctionAssertionsToPassOptions? options = default)
=> throw new NotImplementedException();
}
Loading