From df83b16818ea84aaaab9a5e83ed491a66a777992 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Thu, 30 Jan 2025 14:41:25 +0100 Subject: [PATCH] chore(roll): roll Playwright to v1.50 (#3100) --- README.md | 4 +- src/Common/Version.props | 2 +- .../tests/mstest/basic.spec.ts | 6 +- .../Assertions/LocatorAssertionsTests.cs | 63 +++++++++++++ src/Playwright/API/Generated/IBrowser.cs | 14 +-- .../API/Generated/IBrowserContext.cs | 9 +- src/Playwright/API/Generated/IClock.cs | 12 +++ src/Playwright/API/Generated/ILocator.cs | 27 +++++- .../API/Generated/ILocatorAssertions.cs | 88 +++++++++++++------ src/Playwright/API/Generated/IPage.cs | 4 +- src/Playwright/API/Generated/ITracing.cs | 4 +- .../Options/BrowserTypeLaunchOptions.cs | 10 ++- ...owserTypeLaunchPersistentContextOptions.cs | 10 ++- .../LocatorAssertionsToBeCheckedOptions.cs | 17 ++++ ...ionsToHaveAccessibleErrorMessageOptions.cs | 60 +++++++++++++ src/Playwright/Core/LocatorAssertions.cs | 29 ++++-- src/Playwright/Core/Request.cs | 1 + src/Playwright/Core/Response.cs | 1 + 18 files changed, 301 insertions(+), 60 deletions(-) create mode 100644 src/Playwright/API/Generated/Options/LocatorAssertionsToHaveAccessibleErrorMessageOptions.cs diff --git a/README.md b/README.md index 10c05121ef..b0e5179b9f 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ | | Linux | macOS | Windows | | :--- | :---: | :---: | :---: | -| Chromium 131.0.6778.33 | ✅ | ✅ | ✅ | +| Chromium 133.0.6943.16 | ✅ | ✅ | ✅ | | WebKit 18.2 | ✅ | ✅ | ✅ | -| Firefox 132.0 | ✅ | ✅ | ✅ | +| Firefox 134.0 | ✅ | ✅ | ✅ | Playwright for .NET is the official language port of [Playwright](https://playwright.dev), the library to automate [Chromium](https://www.chromium.org/Home), [Firefox](https://www.mozilla.org/en-US/firefox/new/) and [WebKit](https://webkit.org/) with a single API. Playwright is built to enable cross-browser web automation that is **ever-green**, **capable**, **reliable** and **fast**. diff --git a/src/Common/Version.props b/src/Common/Version.props index f25bd3b8f0..48ee430aa2 100644 --- a/src/Common/Version.props +++ b/src/Common/Version.props @@ -2,7 +2,7 @@ 1.50.0 $(AssemblyVersion)-beta-2 - 1.49.0 + 1.50.0-beta-1737762224000 $(AssemblyVersion) $(AssemblyVersion) true diff --git a/src/Playwright.TestingHarnessTest/tests/mstest/basic.spec.ts b/src/Playwright.TestingHarnessTest/tests/mstest/basic.spec.ts index a7fb0795a3..c756fc830a 100644 --- a/src/Playwright.TestingHarnessTest/tests/mstest/basic.spec.ts +++ b/src/Playwright.TestingHarnessTest/tests/mstest/basic.spec.ts @@ -235,7 +235,11 @@ test('should be able to parse LaunchOptions.Proxy from runsettings', async ({ ru }).listen(3128); const waitForProxyRequest = new Promise<[string, string]>((resolve) => { - proxyServer.once('proxyReq', (proxyReq, req, res, options) => { + proxyServer.on('proxyReq', (proxyReq, req, res, options) => { + if (req.url.includes('google.com')) // Telemetry requests. + { + return; + } const authHeader = proxyReq.getHeader('authorization') as string; const auth = Buffer.from(authHeader.split(' ')[1], 'base64').toString(); resolve([req.url, auth]); diff --git a/src/Playwright.Tests/Assertions/LocatorAssertionsTests.cs b/src/Playwright.Tests/Assertions/LocatorAssertionsTests.cs index 5100422eaf..4dc9d6bd67 100644 --- a/src/Playwright.Tests/Assertions/LocatorAssertionsTests.cs +++ b/src/Playwright.Tests/Assertions/LocatorAssertionsTests.cs @@ -47,6 +47,32 @@ public async Task ShouldSupportToBeChecked() StringAssert.Contains("LocatorAssertions.ToBeCheckedAsync with timeout 300ms", exception.Message); } + [PlaywrightTest("tests/page/expect-boolean.spec.ts", "with indeterminate:true")] + public async Task WithIndeterminateTrue() + { + await Page.SetContentAsync(""); + await Page.Locator("input").EvaluateAsync("e => e.indeterminate = true"); + await Expect(Page.Locator("input")).ToBeCheckedAsync(new() { Indeterminate = true }); + } + + [PlaywrightTest("tests/page/expect-boolean.spec.ts", "with indeterminate:true and checked")] + public async Task WithIndeterminateTrueAndChecked() + { + await Page.SetContentAsync(""); + await Page.Locator("input").EvaluateAsync("e => e.indeterminate = true"); + var exception = await PlaywrightAssert.ThrowsAsync(() => Expect(Page.Locator("input")).ToBeCheckedAsync(new() { Indeterminate = true, Checked = false })); + StringAssert.Contains("Can't assert indeterminate and checked at the same time", exception.Message); + } + + [PlaywrightTest("tests/page/expect-boolean.spec.ts", "fail with indeterminate: true")] + public async Task FailWithIndeterminateTrue() + { + await Page.SetContentAsync(""); + var locator = Page.Locator("input"); + var exception = await PlaywrightAssert.ThrowsAsync(() => Expect(locator).ToBeCheckedAsync(new() { Indeterminate = true, Timeout = 1000 })); + StringAssert.Contains("LocatorAssertions.ToBeCheckedAsync with timeout 1000ms", exception.Message); + } + [PlaywrightTest("playwright-test/playwright.expect.spec.ts", "should be able to set default timeout")] public async Task ShouldBeAbleToSetDefaultTimeout() { @@ -720,6 +746,43 @@ public async Task ToHaveAccessibleDescription() await Expect(Page.Locator("div")).ToHaveAccessibleDescriptionAsync(new Regex("hello"), new() { IgnoreCase = true }); } + [PlaywrightTest("page/expect-misc.spec.ts", "toHaveAccessibleErrorMessage")] + public async Task ToHaveAccessibleErrorMessage() + { + await Page.SetContentAsync(@" +
+ +
Hello
+
This should not be considered.
+
"); + var locator = Page.Locator("input[role=\"textbox\"]"); + await Expect(locator).ToHaveAccessibleErrorMessageAsync("Hello"); + await Expect(locator).Not.ToHaveAccessibleErrorMessageAsync("hello"); + await Expect(locator).ToHaveAccessibleErrorMessageAsync("hello", new() { IgnoreCase = true }); + await Expect(locator).ToHaveAccessibleErrorMessageAsync(new Regex(@"ell\w")); + await Expect(locator).Not.ToHaveAccessibleErrorMessageAsync(new Regex("hello")); + await Expect(locator).ToHaveAccessibleErrorMessageAsync(new Regex("hello"), new() { IgnoreCase = true }); + await Expect(locator).Not.ToHaveAccessibleErrorMessageAsync("This should not be considered."); + } + + + [PlaywrightTest("page/expect-misc.spec.ts", "toHaveAccessibleErrorMessage should handle multiple aria-errormessage reference")] + public async Task ToHaveAccessibleErrorMessageShouldHandleMultipleAriaErrormessageReference() + { + await Page.SetContentAsync(@" +
+ +
First error message.
+
Second error message.
+
This should not be considered.
+
"); + var locator = Page.Locator("input[role=\"textbox\"]"); + await Expect(locator).ToHaveAccessibleErrorMessageAsync("First error message. Second error message."); + await Expect(locator).ToHaveAccessibleErrorMessageAsync(new Regex("first error message.", RegexOptions.IgnoreCase)); + await Expect(locator).ToHaveAccessibleErrorMessageAsync(new Regex("second error message.", RegexOptions.IgnoreCase)); + await Expect(locator).Not.ToHaveAccessibleErrorMessageAsync(new Regex("This should not be considered.", RegexOptions.IgnoreCase)); + } + [PlaywrightTest("page/expect-misc.spec.ts", "toHaveRole")] public async Task ToHaveRole() { diff --git a/src/Playwright/API/Generated/IBrowser.cs b/src/Playwright/API/Generated/IBrowser.cs index 80ccfe95d3..fd529ae333 100644 --- a/src/Playwright/API/Generated/IBrowser.cs +++ b/src/Playwright/API/Generated/IBrowser.cs @@ -73,9 +73,10 @@ public partial interface IBrowser /// browser and disconnects from the browser server. /// /// - /// This is similar to force quitting the browser. Therefore, you should call - /// on any 's you explicitly created earlier with **before** calling . + /// This is similar to force-quitting the browser. To close pages gracefully and ensure + /// you receive page close events, call on + /// any instances you explicitly created earlier using + /// **before** calling . /// /// /// The object itself is considered to be disposed and cannot @@ -84,9 +85,10 @@ public partial interface IBrowser /// /// /// - /// This is similar to force quitting the browser. Therefore, you should call - /// on any 's you explicitly created earlier with **before** calling . + /// This is similar to force-quitting the browser. To close pages gracefully and ensure + /// you receive page close events, call on + /// any instances you explicitly created earlier using + /// **before** calling . /// /// /// diff --git a/src/Playwright/API/Generated/IBrowserContext.cs b/src/Playwright/API/Generated/IBrowserContext.cs index 57755cf6e5..78b64d8cf3 100644 --- a/src/Playwright/API/Generated/IBrowserContext.cs +++ b/src/Playwright/API/Generated/IBrowserContext.cs @@ -436,11 +436,12 @@ public partial interface IBrowserContext /// /// /// - /// A permission or an array of permissions to grant. Permissions can be one of the - /// following values: + /// A list of permissions to grant. + /// Supported permissions differ between browsers, and even between different versions + /// of the same browser. Any permission may stop working after an update. + /// Here are some permissions that may be supported by some browsers: /// /// 'accelerometer' - /// 'accessibility-events' /// 'ambient-light-sensor' /// 'background-sync' /// 'camera' @@ -862,7 +863,7 @@ public partial interface IBrowserContext /// . /// /// - /// Maximum time in milliseconds + /// Maximum time in milliseconds. Pass 0 to disable timeout. void SetDefaultTimeout(float timeout); /// diff --git a/src/Playwright/API/Generated/IClock.cs b/src/Playwright/API/Generated/IClock.cs index f88e22a890..4ea4ad4f50 100644 --- a/src/Playwright/API/Generated/IClock.cs +++ b/src/Playwright/API/Generated/IClock.cs @@ -149,6 +149,12 @@ public partial interface IClock /// await page.Clock.PauseAtAsync(DateTime.Parse("2020-02-02"));
/// await page.Clock.PauseAtAsync("2020-02-02"); /// + /// + /// For best results, install the clock before navigating the page and set it to a time + /// slightly before the intended test time. This ensures that all timers run normally + /// during page loading, preventing the page from getting stuck. Once the page has fully + /// loaded, you can safely use to pause the clock. + /// ///
/// Time to pause at. Task PauseAtAsync(DateTime time); @@ -168,6 +174,12 @@ public partial interface IClock /// await page.Clock.PauseAtAsync(DateTime.Parse("2020-02-02"));
/// await page.Clock.PauseAtAsync("2020-02-02"); /// + /// + /// For best results, install the clock before navigating the page and set it to a time + /// slightly before the intended test time. This ensures that all timers run normally + /// during page loading, preventing the page from getting stuck. Once the page has fully + /// loaded, you can safely use to pause the clock. + /// /// /// Time to pause at. Task PauseAtAsync(string time); diff --git a/src/Playwright/API/Generated/ILocator.cs b/src/Playwright/API/Generated/ILocator.cs index 08cc0c9ecd..ef1265d349 100644 --- a/src/Playwright/API/Generated/ILocator.cs +++ b/src/Playwright/API/Generated/ILocator.cs @@ -1033,7 +1033,12 @@ public partial interface ILocator Task IsDisabledAsync(LocatorIsDisabledOptions? options = default); /// - /// Returns whether the element is editable. + /// + /// Returns whether the element is editable. + /// If the target element is not an <input>, <textarea>, <select>, + /// [contenteditable] and does not have a role allowing [aria-readonly], + /// this method throws an error. + /// /// /// If you need to assert that an element is editable, prefer /// to avoid flakiness. See assertions @@ -1157,8 +1162,8 @@ public partial interface ILocator /// Creates a locator matching all elements that match one or both of the two locators. /// /// Note that when both locators match something, the resulting locator will have multiple - /// matches and violate locator - /// strictness guidelines. + /// matches, potentially causing a locator + /// strictness violation. /// /// **Usage** /// @@ -1166,15 +1171,29 @@ public partial interface ILocator /// a security settings dialog shows up instead. In this case, you can wait for either /// a "New email" button, or a dialog and act accordingly. /// + /// + /// If both "New email" button and security dialog appear on screen, the "or" locator + /// will match both of them, possibly throwing the "strict + /// mode violation" error. In this case, you can use + /// to only match one of them. + /// /// /// var newEmail = page.GetByRole(AriaRole.Button, new() { Name = "New" });
/// var dialog = page.GetByText("Confirm security settings");
- /// await Expect(newEmail.Or(dialog)).ToBeVisibleAsync();
+ /// await Expect(newEmail.Or(dialog).First).ToBeVisibleAsync();
/// if (await dialog.IsVisibleAsync())
/// await page.GetByRole(AriaRole.Button, new() { Name = "Dismiss" }).ClickAsync();
/// await newEmail.ClickAsync(); ///
///
+ /// + /// + /// If both "New email" button and security dialog appear on screen, the "or" locator + /// will match both of them, possibly throwing the "strict + /// mode violation" error. In this case, you can use + /// to only match one of them. + /// + /// /// Alternative locator to match. ILocator Or(ILocator locator); diff --git a/src/Playwright/API/Generated/ILocatorAssertions.cs b/src/Playwright/API/Generated/ILocatorAssertions.cs index 637fadb427..22427b8a83 100644 --- a/src/Playwright/API/Generated/ILocatorAssertions.cs +++ b/src/Playwright/API/Generated/ILocatorAssertions.cs @@ -135,7 +135,7 @@ public partial interface ILocatorAssertions /// **Usage** /// /// var locator = Page.Locator("button.submit");
- /// await Expect(locator).toBeEnabledAsync(); + /// await Expect(locator).ToBeEnabledAsync(); ///
/// /// Call options @@ -400,7 +400,7 @@ public partial interface ILocatorAssertions /// **Usage** /// /// var locator = Page.GetByTestId("save-button");
- /// await Expect(locator).toHaveAccessibleDescriptionAsync("Save results to disk"); + /// await Expect(locator).ToHaveAccessibleDescriptionAsync("Save results to disk"); ///
/// /// Expected accessible description. @@ -415,13 +415,43 @@ public partial interface ILocatorAssertions /// **Usage** /// /// var locator = Page.GetByTestId("save-button");
- /// await Expect(locator).toHaveAccessibleDescriptionAsync("Save results to disk"); + /// await Expect(locator).ToHaveAccessibleDescriptionAsync("Save results to disk"); ///
/// /// Expected accessible description. /// Call options Task ToHaveAccessibleDescriptionAsync(Regex description, LocatorAssertionsToHaveAccessibleDescriptionOptions? options = default); + /// + /// + /// Ensures the points to an element with a given aria + /// errormessage. + /// + /// **Usage** + /// + /// var locator = Page.GetByTestId("username-input");
+ /// await Expect(locator).ToHaveAccessibleErrorMessageAsync("Username is required."); + ///
+ ///
+ /// Expected accessible error message. + /// Call options + Task ToHaveAccessibleErrorMessageAsync(string errorMessage, LocatorAssertionsToHaveAccessibleErrorMessageOptions? options = default); + + /// + /// + /// Ensures the points to an element with a given aria + /// errormessage. + /// + /// **Usage** + /// + /// var locator = Page.GetByTestId("username-input");
+ /// await Expect(locator).ToHaveAccessibleErrorMessageAsync("Username is required."); + ///
+ ///
+ /// Expected accessible error message. + /// Call options + Task ToHaveAccessibleErrorMessageAsync(Regex errorMessage, LocatorAssertionsToHaveAccessibleErrorMessageOptions? options = default); + /// /// /// Ensures the points to an element with a given accessible @@ -430,7 +460,7 @@ public partial interface ILocatorAssertions /// **Usage** /// /// var locator = Page.GetByTestId("save-button");
- /// await Expect(locator).toHaveAccessibleNameAsync("Save to disk"); + /// await Expect(locator).ToHaveAccessibleNameAsync("Save to disk"); ///
///
/// Expected accessible name. @@ -445,7 +475,7 @@ public partial interface ILocatorAssertions /// **Usage** /// /// var locator = Page.GetByTestId("save-button");
- /// await Expect(locator).toHaveAccessibleNameAsync("Save to disk"); + /// await Expect(locator).ToHaveAccessibleNameAsync("Save to disk"); ///
/// /// Expected accessible name. @@ -481,17 +511,19 @@ public partial interface ILocatorAssertions ///
/// /// Ensures the points to an element with given CSS classes. - /// This needs to be a full match or using a relaxed regular expression. + /// When a string is provided, it must fully match the element's class attribute. + /// To match individual classes or perform partial matches, use a regular expression: /// /// **Usage** /// /// var locator = Page.Locator("#component");
- /// await Expect(locator).ToHaveClassAsync(new Regex("selected"));
- /// await Expect(locator).ToHaveClassAsync("selected row"); + /// await Expect(locator).ToHaveClassAsync(new Regex("(^|\\s)selected(\\s|$)"));
+ /// await Expect(locator).ToHaveClassAsync("middle selected row"); ///
/// - /// Note that if array is passed as an expected value, entire lists of elements can - /// be asserted: + /// When an array is passed, the method asserts that the list of elements located matches + /// the corresponding list of expected class values. Each element's class attribute + /// is matched against the corresponding string or regular expression in the array: /// /// /// var locator = Page.Locator("list > .component");
@@ -505,17 +537,19 @@ public partial interface ILocatorAssertions ///
/// /// Ensures the points to an element with given CSS classes. - /// This needs to be a full match or using a relaxed regular expression. + /// When a string is provided, it must fully match the element's class attribute. + /// To match individual classes or perform partial matches, use a regular expression: /// /// **Usage** /// /// var locator = Page.Locator("#component");
- /// await Expect(locator).ToHaveClassAsync(new Regex("selected"));
- /// await Expect(locator).ToHaveClassAsync("selected row"); + /// await Expect(locator).ToHaveClassAsync(new Regex("(^|\\s)selected(\\s|$)"));
+ /// await Expect(locator).ToHaveClassAsync("middle selected row"); ///
/// - /// Note that if array is passed as an expected value, entire lists of elements can - /// be asserted: + /// When an array is passed, the method asserts that the list of elements located matches + /// the corresponding list of expected class values. Each element's class attribute + /// is matched against the corresponding string or regular expression in the array: /// /// /// var locator = Page.Locator("list > .component");
@@ -529,17 +563,19 @@ public partial interface ILocatorAssertions ///
/// /// Ensures the points to an element with given CSS classes. - /// This needs to be a full match or using a relaxed regular expression. + /// When a string is provided, it must fully match the element's class attribute. + /// To match individual classes or perform partial matches, use a regular expression: /// /// **Usage** /// /// var locator = Page.Locator("#component");
- /// await Expect(locator).ToHaveClassAsync(new Regex("selected"));
- /// await Expect(locator).ToHaveClassAsync("selected row"); + /// await Expect(locator).ToHaveClassAsync(new Regex("(^|\\s)selected(\\s|$)"));
+ /// await Expect(locator).ToHaveClassAsync("middle selected row"); ///
/// - /// Note that if array is passed as an expected value, entire lists of elements can - /// be asserted: + /// When an array is passed, the method asserts that the list of elements located matches + /// the corresponding list of expected class values. Each element's class attribute + /// is matched against the corresponding string or regular expression in the array: /// /// /// var locator = Page.Locator("list > .component");
@@ -553,17 +589,19 @@ public partial interface ILocatorAssertions ///
/// /// Ensures the points to an element with given CSS classes. - /// This needs to be a full match or using a relaxed regular expression. + /// When a string is provided, it must fully match the element's class attribute. + /// To match individual classes or perform partial matches, use a regular expression: /// /// **Usage** /// /// var locator = Page.Locator("#component");
- /// await Expect(locator).ToHaveClassAsync(new Regex("selected"));
- /// await Expect(locator).ToHaveClassAsync("selected row"); + /// await Expect(locator).ToHaveClassAsync(new Regex("(^|\\s)selected(\\s|$)"));
+ /// await Expect(locator).ToHaveClassAsync("middle selected row"); ///
/// - /// Note that if array is passed as an expected value, entire lists of elements can - /// be asserted: + /// When an array is passed, the method asserts that the list of elements located matches + /// the corresponding list of expected class values. Each element's class attribute + /// is matched against the corresponding string or regular expression in the array: /// /// /// var locator = Page.Locator("list > .component");
diff --git a/src/Playwright/API/Generated/IPage.cs b/src/Playwright/API/Generated/IPage.cs index 19018300a5..269901453c 100644 --- a/src/Playwright/API/Generated/IPage.cs +++ b/src/Playwright/API/Generated/IPage.cs @@ -1606,7 +1606,6 @@ public partial interface IPage /// /// Returns the PDF buffer. - /// Generating a pdf is currently only supported in Chromium headless. /// /// page.pdf() generates a pdf of the page with print css media. To generate /// a pdf with screen media, call before @@ -1661,7 +1660,6 @@ public partial interface IPage /// /// /// - /// Generating a pdf is currently only supported in Chromium headless. /// /// By default, page.pdf() generates a pdf with modified colors for printing. /// Use the
-webkit-print-color-adjust @@ -2621,7 +2619,7 @@ public partial interface IPage /// /// /// - /// Maximum time in milliseconds + /// Maximum time in milliseconds. Pass 0 to disable timeout. void SetDefaultTimeout(float timeout); /// diff --git a/src/Playwright/API/Generated/ITracing.cs b/src/Playwright/API/Generated/ITracing.cs index 4eeb3eb08e..0ba853ee74 100644 --- a/src/Playwright/API/Generated/ITracing.cs +++ b/src/Playwright/API/Generated/ITracing.cs @@ -130,10 +130,10 @@ public partial interface ITracing /// /// // All actions between GroupAsync and GroupEndAsync
/// // will be shown in the trace viewer as a group.
- /// await Page.Context().Tracing.GroupAsync("Open Playwright.dev > API");
+ /// await Page.Context.Tracing.GroupAsync("Open Playwright.dev > API");
/// await Page.GotoAsync("https://playwright.dev/");
/// await Page.GetByRole(AriaRole.Link, new() { Name = "API" }).ClickAsync();
- /// await Page.Context().Tracing.GroupEndAsync(); + /// await Page.Context.Tracing.GroupEndAsync(); ///
///
/// Use test.step instead when available. diff --git a/src/Playwright/API/Generated/Options/BrowserTypeLaunchOptions.cs b/src/Playwright/API/Generated/Options/BrowserTypeLaunchOptions.cs index 867662c076..d4c62ea89c 100644 --- a/src/Playwright/API/Generated/Options/BrowserTypeLaunchOptions.cs +++ b/src/Playwright/API/Generated/Options/BrowserTypeLaunchOptions.cs @@ -77,10 +77,14 @@ public BrowserTypeLaunchOptions(BrowserTypeLaunchOptions clone) public IEnumerable? Args { get; set; } /// + /// Browser distribution channel. /// - /// Browser distribution channel. Supported values are "chrome", "chrome-beta", "chrome-dev", - /// "chrome-canary", "msedge", "msedge-beta", "msedge-dev", "msedge-canary". Read more - /// about using Google + /// Use "chromium" to opt + /// in to new headless mode. + /// + /// + /// Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", + /// "msedge-dev", or "msedge-canary" to use branded Google /// Chrome and Microsoft Edge. /// /// diff --git a/src/Playwright/API/Generated/Options/BrowserTypeLaunchPersistentContextOptions.cs b/src/Playwright/API/Generated/Options/BrowserTypeLaunchPersistentContextOptions.cs index 45a8fad15a..0c7aa6b043 100644 --- a/src/Playwright/API/Generated/Options/BrowserTypeLaunchPersistentContextOptions.cs +++ b/src/Playwright/API/Generated/Options/BrowserTypeLaunchPersistentContextOptions.cs @@ -149,10 +149,14 @@ public BrowserTypeLaunchPersistentContextOptions(BrowserTypeLaunchPersistentCont public bool? BypassCSP { get; set; } /// + /// Browser distribution channel. /// - /// Browser distribution channel. Supported values are "chrome", "chrome-beta", "chrome-dev", - /// "chrome-canary", "msedge", "msedge-beta", "msedge-dev", "msedge-canary". Read more - /// about using Google + /// Use "chromium" to opt + /// in to new headless mode. + /// + /// + /// Use "chrome", "chrome-beta", "chrome-dev", "chrome-canary", "msedge", "msedge-beta", + /// "msedge-dev", or "msedge-canary" to use branded Google /// Chrome and Microsoft Edge. /// /// diff --git a/src/Playwright/API/Generated/Options/LocatorAssertionsToBeCheckedOptions.cs b/src/Playwright/API/Generated/Options/LocatorAssertionsToBeCheckedOptions.cs index a657ac6c0f..9f52e02c52 100644 --- a/src/Playwright/API/Generated/Options/LocatorAssertionsToBeCheckedOptions.cs +++ b/src/Playwright/API/Generated/Options/LocatorAssertionsToBeCheckedOptions.cs @@ -40,12 +40,29 @@ public LocatorAssertionsToBeCheckedOptions(LocatorAssertionsToBeCheckedOptions c } Checked = clone.Checked; + Indeterminate = clone.Indeterminate; Timeout = clone.Timeout; } + /// + /// + /// Provides state to assert for. Asserts for input to be checked by default. This option + /// can't be used when is set to true. + /// + /// [JsonPropertyName("checked")] public bool? Checked { get; set; } + /// + /// + /// Asserts that the element is in the indeterminate (mixed) state. Only supported for + /// checkboxes and radio buttons. This option can't be true when + /// is provided. + /// + /// + [JsonPropertyName("indeterminate")] + public bool? Indeterminate { get; set; } + /// Time to retry the assertion for in milliseconds. Defaults to 5000. [JsonPropertyName("timeout")] public float? Timeout { get; set; } diff --git a/src/Playwright/API/Generated/Options/LocatorAssertionsToHaveAccessibleErrorMessageOptions.cs b/src/Playwright/API/Generated/Options/LocatorAssertionsToHaveAccessibleErrorMessageOptions.cs new file mode 100644 index 0000000000..2dd1c0802c --- /dev/null +++ b/src/Playwright/API/Generated/Options/LocatorAssertionsToHaveAccessibleErrorMessageOptions.cs @@ -0,0 +1,60 @@ +/* + * 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.Text.Json.Serialization; + +#nullable enable + +namespace Microsoft.Playwright; + +public class LocatorAssertionsToHaveAccessibleErrorMessageOptions +{ + public LocatorAssertionsToHaveAccessibleErrorMessageOptions() { } + + public LocatorAssertionsToHaveAccessibleErrorMessageOptions(LocatorAssertionsToHaveAccessibleErrorMessageOptions clone) + { + if (clone == null) + { + return; + } + + IgnoreCase = clone.IgnoreCase; + Timeout = clone.Timeout; + } + + /// + /// + /// Whether to perform case-insensitive match. + /// option takes precedence over the corresponding regular expression flag if specified. + /// + /// + [JsonPropertyName("ignoreCase")] + public bool? IgnoreCase { get; set; } + + /// Time to retry the assertion for in milliseconds. Defaults to 5000. + [JsonPropertyName("timeout")] + public float? Timeout { get; set; } +} + +#nullable disable diff --git a/src/Playwright/Core/LocatorAssertions.cs b/src/Playwright/Core/LocatorAssertions.cs index 5897bb9e3d..da59bec72c 100644 --- a/src/Playwright/Core/LocatorAssertions.cs +++ b/src/Playwright/Core/LocatorAssertions.cs @@ -46,8 +46,19 @@ public Task ToBeAttachedAsync(LocatorAssertionsToBeAttachedOptions options = nul public Task ToBeCheckedAsync(LocatorAssertionsToBeCheckedOptions options = null) { - var isChecked = options == null || options.Checked == null || options.Checked == true; - return ExpectTrueAsync(isChecked ? "to.be.checked" : "to.be.unchecked", $"Locator expected {(!isChecked ? "not " : string.Empty)}to be checked", ConvertToFrameExpectOptions(options)); + var expectedValue = new Dictionary(); + if (options?.Checked != null) + { + expectedValue["checked"] = options.Checked; + } + if (options?.Indeterminate != null) + { + expectedValue["indeterminate"] = options.Indeterminate; + } + var frameExpectedOptions = ConvertToFrameExpectOptions(options) ?? new(); + frameExpectedOptions.ExpectedValue = ScriptsHelper.SerializedArgument(expectedValue); + var checkedString = options?.Indeterminate == true ? "indeterminate" : "checked"; + return ExpectTrueAsync("to.be.checked", $"Locator expected {(options?.Checked == false ? "not " : string.Empty)}to be {checkedString}", frameExpectedOptions); } public Task ToBeDisabledAsync(LocatorAssertionsToBeDisabledOptions options = null) => ExpectTrueAsync("to.be.disabled", "Locator expected to be disabled", ConvertToFrameExpectOptions(options)); @@ -200,16 +211,22 @@ public Task ToHaveValuesAsync(IEnumerable values, LocatorAssertionsToHave ExpectImplAsync("to.have.values", values.Select(regex => ExpectedRegex(regex)).ToArray(), values, "Locator expected to have matching regex", ConvertToFrameExpectOptions(options)); public Task ToHaveAccessibleDescriptionAsync(string expected, LocatorAssertionsToHaveAccessibleDescriptionOptions options = null) - => ExpectImplAsync("to.have.accessible.description", new ExpectedTextValue() { String = expected, IgnoreCase = options?.IgnoreCase }, expected, "Locator expected to have accessible description", ConvertToFrameExpectOptions(options)); + => ExpectImplAsync("to.have.accessible.description", new ExpectedTextValue() { String = expected, IgnoreCase = options?.IgnoreCase, NormalizeWhiteSpace = true }, expected, "Locator expected to have accessible description", ConvertToFrameExpectOptions(options)); public Task ToHaveAccessibleDescriptionAsync(Regex expected, LocatorAssertionsToHaveAccessibleDescriptionOptions options = null) - => ExpectImplAsync("to.have.accessible.description", ExpectedRegex(expected, new() { IgnoreCase = options?.IgnoreCase }), expected, "Locator expected to have accessible description matching regex", ConvertToFrameExpectOptions(options)); + => ExpectImplAsync("to.have.accessible.description", ExpectedRegex(expected, new() { IgnoreCase = options?.IgnoreCase, NormalizeWhiteSpace = true }), expected, "Locator expected to have accessible description matching regex", ConvertToFrameExpectOptions(options)); + + public Task ToHaveAccessibleErrorMessageAsync(string errorMessage, LocatorAssertionsToHaveAccessibleErrorMessageOptions options = null) + => ExpectImplAsync("to.have.accessible.error.message", new ExpectedTextValue() { String = errorMessage, IgnoreCase = options?.IgnoreCase }, errorMessage, "Locator expected to have accessible error message", ConvertToFrameExpectOptions(options)); + + public Task ToHaveAccessibleErrorMessageAsync(Regex errorMessage, LocatorAssertionsToHaveAccessibleErrorMessageOptions options = null) + => ExpectImplAsync("to.have.accessible.error.message", ExpectedRegex(errorMessage, new() { IgnoreCase = options?.IgnoreCase }), errorMessage, "Locator expected to have accessible error message matching regex", ConvertToFrameExpectOptions(options)); public Task ToHaveAccessibleNameAsync(string expected, LocatorAssertionsToHaveAccessibleNameOptions options = null) - => ExpectImplAsync("to.have.accessible.name", new ExpectedTextValue() { String = expected, IgnoreCase = options?.IgnoreCase }, expected, "Locator expected to have accessible name", ConvertToFrameExpectOptions(options)); + => ExpectImplAsync("to.have.accessible.name", new ExpectedTextValue() { String = expected, IgnoreCase = options?.IgnoreCase, NormalizeWhiteSpace = true }, expected, "Locator expected to have accessible name", ConvertToFrameExpectOptions(options)); public Task ToHaveAccessibleNameAsync(Regex expected, LocatorAssertionsToHaveAccessibleNameOptions options = null) - => ExpectImplAsync("to.have.accessible.name", ExpectedRegex(expected, new() { IgnoreCase = options?.IgnoreCase }), expected, "Locator expected to have accessible name matching regex", ConvertToFrameExpectOptions(options)); + => ExpectImplAsync("to.have.accessible.name", ExpectedRegex(expected, new() { IgnoreCase = options?.IgnoreCase, NormalizeWhiteSpace = true }), expected, "Locator expected to have accessible name matching regex", ConvertToFrameExpectOptions(options)); public Task ToHaveRoleAsync(AriaRole role, LocatorAssertionsToHaveRoleOptions options = null) => ExpectImplAsync("to.have.role", new ExpectedTextValue() { String = role.ToString().ToLowerInvariant() }, role, "Locator expected to have role", ConvertToFrameExpectOptions(options)); diff --git a/src/Playwright/Core/Request.cs b/src/Playwright/Core/Request.cs index f3b65b3fed..93249f697c 100644 --- a/src/Playwright/Core/Request.cs +++ b/src/Playwright/Core/Request.cs @@ -45,6 +45,7 @@ internal class Request : ChannelOwner, IRequest internal Request(ChannelOwner parent, string guid, RequestInitializer initializer) : base(parent, guid) { + MarkAsInternalType(); _initializer = initializer; RedirectedFrom = _initializer.RedirectedFrom; Timing = new(); diff --git a/src/Playwright/Core/Response.cs b/src/Playwright/Core/Response.cs index f22cab751f..aba5b2cf11 100644 --- a/src/Playwright/Core/Response.cs +++ b/src/Playwright/Core/Response.cs @@ -43,6 +43,7 @@ internal class Response : ChannelOwner, IResponse internal Response(ChannelOwner parent, string guid, ResponseInitializer initializer) : base(parent, guid) { + MarkAsInternalType(); _initializer = initializer; _initializer.Request.Timing = _initializer.Timing; _finishedTask = new();