diff --git a/README.md b/README.md index 8c7e7dd38..c093f98a9 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ | | Linux | macOS | Windows | | :--- | :---: | :---: | :---: | -| Chromium 138.0.7204.23 | ✅ | ✅ | ✅ | +| Chromium 139.0.7258.5 | ✅ | ✅ | ✅ | | WebKit 18.5 | ✅ | ✅ | ✅ | -| Firefox 139.0 | ✅ | ✅ | ✅ | +| Firefox 140.0.2 | ✅ | ✅ | ✅ | 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 91e7bd1a2..b3cfb3761 100644 --- a/src/Common/Version.props +++ b/src/Common/Version.props @@ -2,7 +2,7 @@ 1.53.0 $(AssemblyVersion) - 1.53.1 + 1.54.0-alpha-2025-07-08 $(AssemblyVersion) $(AssemblyVersion) true diff --git a/src/Playwright.TestingHarnessTest/package-lock.json b/src/Playwright.TestingHarnessTest/package-lock.json index 004e13de9..bddf649d7 100644 --- a/src/Playwright.TestingHarnessTest/package-lock.json +++ b/src/Playwright.TestingHarnessTest/package-lock.json @@ -7,19 +7,18 @@ "": { "name": "playwright.testingharnesstest", "devDependencies": { - "@playwright/test": "1.53.1", + "@playwright/test": "1.54.0-alpha-2025-07-08", "@types/node": "^22.12.0", "fast-xml-parser": "^4.5.0" } }, "node_modules/@playwright/test": { - "version": "1.53.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.1.tgz", - "integrity": "sha512-Z4c23LHV0muZ8hfv4jw6HngPJkbbtZxTkxPNIg7cJcTc9C28N/p2q7g3JZS2SiKBBHJ3uM1dgDye66bB7LEk5w==", + "version": "1.54.0-alpha-2025-07-08", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.0-alpha-2025-07-08.tgz", + "integrity": "sha512-uBk5p/PS5SzKjVL+k4DW4fC2LDOulhjrzmaw59QMhlwoqf+5Bnse8dN9d/0+ByvpK2L/FlT12LEqoT3N2l6Y2A==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "playwright": "1.53.1" + "playwright": "1.54.0-alpha-2025-07-08" }, "bin": { "playwright": "cli.js" @@ -67,7 +66,6 @@ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -77,13 +75,12 @@ } }, "node_modules/playwright": { - "version": "1.53.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.1.tgz", - "integrity": "sha512-LJ13YLr/ocweuwxyGf1XNFWIU4M2zUSo149Qbp+A4cpwDjsxRPj7k6H25LBrEHiEwxvRbD8HdwvQmRMSvquhYw==", + "version": "1.54.0-alpha-2025-07-08", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.0-alpha-2025-07-08.tgz", + "integrity": "sha512-slDsPlbNhtpgn2OmfQ/VGWrx6JPQsSWUR44Ma4SyupPwWcBrrSBnCQe1VHmrT4m+vJqkL5VfavcJaQWauIzl5A==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.53.1" + "playwright-core": "1.54.0-alpha-2025-07-08" }, "bin": { "playwright": "cli.js" @@ -96,11 +93,10 @@ } }, "node_modules/playwright-core": { - "version": "1.53.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.1.tgz", - "integrity": "sha512-Z46Oq7tLAyT0lGoFx4DOuB1IA9D1TPj0QkYxpPVUnGDqHHvDpCftu1J2hM2PiWsNMoZh8+LQaarAWcDfPBc6zg==", + "version": "1.54.0-alpha-2025-07-08", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.0-alpha-2025-07-08.tgz", + "integrity": "sha512-1hHsBW2qcAyVd0NM50RuBPQ+aZXUbMfQD8zxcbHc/aNG4WVwlmzbF3gBPOb4yCQKLHNTEpJX8y82wXjJUQCVzg==", "dev": true, - "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, @@ -124,12 +120,12 @@ }, "dependencies": { "@playwright/test": { - "version": "1.53.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.1.tgz", - "integrity": "sha512-Z4c23LHV0muZ8hfv4jw6HngPJkbbtZxTkxPNIg7cJcTc9C28N/p2q7g3JZS2SiKBBHJ3uM1dgDye66bB7LEk5w==", + "version": "1.54.0-alpha-2025-07-08", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.0-alpha-2025-07-08.tgz", + "integrity": "sha512-uBk5p/PS5SzKjVL+k4DW4fC2LDOulhjrzmaw59QMhlwoqf+5Bnse8dN9d/0+ByvpK2L/FlT12LEqoT3N2l6Y2A==", "dev": true, "requires": { - "playwright": "1.53.1" + "playwright": "1.54.0-alpha-2025-07-08" } }, "@types/node": { @@ -158,19 +154,19 @@ "optional": true }, "playwright": { - "version": "1.53.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.1.tgz", - "integrity": "sha512-LJ13YLr/ocweuwxyGf1XNFWIU4M2zUSo149Qbp+A4cpwDjsxRPj7k6H25LBrEHiEwxvRbD8HdwvQmRMSvquhYw==", + "version": "1.54.0-alpha-2025-07-08", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.0-alpha-2025-07-08.tgz", + "integrity": "sha512-slDsPlbNhtpgn2OmfQ/VGWrx6JPQsSWUR44Ma4SyupPwWcBrrSBnCQe1VHmrT4m+vJqkL5VfavcJaQWauIzl5A==", "dev": true, "requires": { "fsevents": "2.3.2", - "playwright-core": "1.53.1" + "playwright-core": "1.54.0-alpha-2025-07-08" } }, "playwright-core": { - "version": "1.53.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.1.tgz", - "integrity": "sha512-Z46Oq7tLAyT0lGoFx4DOuB1IA9D1TPj0QkYxpPVUnGDqHHvDpCftu1J2hM2PiWsNMoZh8+LQaarAWcDfPBc6zg==", + "version": "1.54.0-alpha-2025-07-08", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.0-alpha-2025-07-08.tgz", + "integrity": "sha512-1hHsBW2qcAyVd0NM50RuBPQ+aZXUbMfQD8zxcbHc/aNG4WVwlmzbF3gBPOb4yCQKLHNTEpJX8y82wXjJUQCVzg==", "dev": true }, "strnum": { diff --git a/src/Playwright.TestingHarnessTest/package.json b/src/Playwright.TestingHarnessTest/package.json index 9bd312111..ae50c0bc1 100644 --- a/src/Playwright.TestingHarnessTest/package.json +++ b/src/Playwright.TestingHarnessTest/package.json @@ -2,7 +2,7 @@ "name": "playwright.testingharnesstest", "private": true, "devDependencies": { - "@playwright/test": "1.53.1", + "@playwright/test": "1.54.0-alpha-2025-07-08", "@types/node": "^22.12.0", "fast-xml-parser": "^4.5.0" } diff --git a/src/Playwright.Tests/BrowserContextBasicTests.cs b/src/Playwright.Tests/BrowserContextBasicTests.cs index 4b31a729f..c0f352b7e 100644 --- a/src/Playwright.Tests/BrowserContextBasicTests.cs +++ b/src/Playwright.Tests/BrowserContextBasicTests.cs @@ -145,11 +145,11 @@ public async Task ShouldRespectDeviceScaleFactor() { await using var context = await Browser.NewContextAsync(new() { - DeviceScaleFactor = 3 + DeviceScaleFactor = 3.5F }); var page = await context.NewPageAsync(); - Assert.AreEqual(3, await page.EvaluateAsync("window.devicePixelRatio")); + Assert.AreEqual(3.5F, await page.EvaluateAsync("window.devicePixelRatio")); } [PlaywrightTest("browsercontext-basic.spec.ts", "should not allow deviceScaleFactor with null viewport")] diff --git a/src/Playwright.Tests/BrowserContextFetchTests.cs b/src/Playwright.Tests/BrowserContextFetchTests.cs index cde263449..881275332 100644 --- a/src/Playwright.Tests/BrowserContextFetchTests.cs +++ b/src/Playwright.Tests/BrowserContextFetchTests.cs @@ -607,8 +607,8 @@ public async Task ShouldSupportTimeoutOption() { await Task.Delay(5000); }); - var exception = await PlaywrightAssert.ThrowsAsync(async () => await Context.APIRequest.GetAsync(Server.Prefix + "/slow", new() { Timeout = 10 })); - StringAssert.Contains("Request timed out after 10ms", exception.Message); + var exception = await PlaywrightAssert.ThrowsAsync(() => Context.APIRequest.GetAsync(Server.Prefix + "/slow", new() { Timeout = 1000 })); + StringAssert.Contains("Timeout 1000ms exceeded", exception.Message); } [PlaywrightTest("browsercontext-fetch.spec.ts", "should dispose")] diff --git a/src/Playwright.Tests/GeolocationTests.cs b/src/Playwright.Tests/GeolocationTests.cs index 54e057f25..9cdf76ee8 100644 --- a/src/Playwright.Tests/GeolocationTests.cs +++ b/src/Playwright.Tests/GeolocationTests.cs @@ -72,7 +72,7 @@ await Context.SetGeolocationAsync(new() await using var context2 = await Browser.NewContextAsync(new() { Permissions = new[] { "geolocation" }, - Geolocation = new() { Latitude = 20, Longitude = 20 }, + Geolocation = new() { Latitude = 10.5F, Longitude = 11.5F }, }); var page2 = await context2.NewPageAsync(); @@ -88,7 +88,7 @@ await Context.SetGeolocationAsync(new() @"() => new Promise(resolve => navigator.geolocation.getCurrentPosition(position => { resolve({latitude: position.coords.latitude, longitude: position.coords.longitude}); }))"); - AssertEqual(20, 20, geolocation2); + AssertEqual(10.5F, 11.5F, geolocation2); } [PlaywrightTest("geolocation.spec.ts", "should not modify passed default options object")] diff --git a/src/Playwright.Tests/GlobalFetchTests.cs b/src/Playwright.Tests/GlobalFetchTests.cs index c3003221f..e2b9e6c7d 100644 --- a/src/Playwright.Tests/GlobalFetchTests.cs +++ b/src/Playwright.Tests/GlobalFetchTests.cs @@ -81,8 +81,8 @@ public async Task ShouldSupportGlobalTimeoutOption() { var request = await Playwright.APIRequest.NewContextAsync(new() { Timeout = 100 }); Server.SetRoute("/empty.html", async request => await Task.Delay(5_000)); - var exception = Assert.ThrowsAsync(() => request.GetAsync(Server.EmptyPage)); - StringAssert.Contains("Request timed out after 100ms", exception.Message); + var exception = Assert.ThrowsAsync(() => request.GetAsync(Server.EmptyPage)); + StringAssert.Contains("Timeout 100ms exceeded", exception.Message); await request.DisposeAsync(); } diff --git a/src/Playwright.Tests/InterceptionTests.cs b/src/Playwright.Tests/InterceptionTests.cs index 1ec94ee47..8bd629f16 100644 --- a/src/Playwright.Tests/InterceptionTests.cs +++ b/src/Playwright.Tests/InterceptionTests.cs @@ -100,6 +100,13 @@ bool URLMatches(string baseURL, string url, string glob) Assert.True(URLMatches("http://playwright.dev/foo", "http://playwright.dev/foo?bar", "\\\\?bar")); Assert.True(URLMatches("http://first.host/", "http://second.host/foo", "**/foo")); Assert.True(URLMatches("http://playwright.dev/", "http://localhost/", "*//localhost/")); + + // Should work with baseURL and various non-http schemes. + Assert.True(URLMatches("http://playwright.dev/", "about:blank", "about:blank")); + Assert.False(URLMatches("http://playwright.dev/", "about:blank", "http://playwright.dev/")); + Assert.True(URLMatches("http://playwright.dev/", "about:blank", "about:*")); + Assert.True(URLMatches("http://playwright.dev/", "data:text/html,", "data:*/*")); + Assert.True(URLMatches("http://playwright.dev/", "file://path/to/file", "file://**")); } [PlaywrightTest("interception.spec.ts", "should intercept by glob")] diff --git a/src/Playwright.Tests/PageAddLocatorHandlerTests.cs b/src/Playwright.Tests/PageAddLocatorHandlerTests.cs index 082733fe6..50d9e32d4 100644 --- a/src/Playwright.Tests/PageAddLocatorHandlerTests.cs +++ b/src/Playwright.Tests/PageAddLocatorHandlerTests.cs @@ -324,7 +324,7 @@ await Page.EvaluateAsync(@"() => }"); var error = await PlaywrightAssert.ThrowsAsync(() => Page.Locator("#target").ClickAsync(new() { Timeout = 3000 })); Assert.AreEqual(0, await Page.EvaluateAsync("window.clicked")); - await Expect(Page.Locator("#interstitial")).ToBeVisibleAsync(); + Assert.True(await Page.Locator("#interstitial").IsVisibleAsync()); Assert.AreEqual(1, called); StringAssert.Contains("locator handler has finished, waiting for GetByRole(AriaRole.Button, new() { Name = \"close\" }) to be hidden", error.Message); } diff --git a/src/Playwright.Tests/PageRequestInterceptTests.cs b/src/Playwright.Tests/PageRequestInterceptTests.cs index 20d9e9166..b59f7672d 100644 --- a/src/Playwright.Tests/PageRequestInterceptTests.cs +++ b/src/Playwright.Tests/PageRequestInterceptTests.cs @@ -216,8 +216,8 @@ public async Task ShouldSupportTimeoutOptionInRouteFetch() }); await Page.RouteAsync("**/*", async (route) => { - var error = await PlaywrightAssert.ThrowsAsync(() => route.FetchAsync(new() { Timeout = 1000 })); - Assert.True(error.Message.Contains("Request timed out after 1000ms")); + var error = await PlaywrightAssert.ThrowsAsync(() => route.FetchAsync(new() { Timeout = 1000 })); + Assert.True(error.Message.Contains("Timeout 1000ms exceeded")); }); var error = await PlaywrightAssert.ThrowsAsync(() => Page.GotoAsync(Server.Prefix + "/slow", new() { Timeout = 2000 })); Assert.True(error.Message.Contains("Timeout 2000ms exceeded")); diff --git a/src/Playwright.Tests/SelectorsRegisterTests.cs b/src/Playwright.Tests/SelectorsRegisterTests.cs index f299fc0bc..cb9453858 100644 --- a/src/Playwright.Tests/SelectorsRegisterTests.cs +++ b/src/Playwright.Tests/SelectorsRegisterTests.cs @@ -77,6 +77,27 @@ public async Task ShouldWork() StringAssert.Contains("Unknown engine \"tAG\" while parsing selector tAG=DIV", exception.Message); } + [PlaywrightTest("selectors-register.spec.ts", "should throw \"already registered\" error when registering")] + public async Task ShouldThrowAlreadyRegisteredErrorWhenRegistering() + { + const string createSelector = @"({ + create(root, target) { + return target.nodeName; + }, + query(root, selector) { + return root.querySelector(selector); + }, + queryAll(root, selector) { + return Array.from(root.querySelectorAll(selector)); + } + })"; + + await TestUtils.RegisterEngineAsync(Playwright, "alreadyRegistered", createSelector); + + var exception = await PlaywrightAssert.ThrowsAsync(() => Playwright.Selectors.RegisterAsync("alreadyRegistered", new() { Script = createSelector })); + StringAssert.Contains("\"alreadyRegistered\" selector engine has been already registered", exception.Message); + } + [PlaywrightTest("selectors-register.spec.ts", "should work with path")] public async Task ShouldWorkWithPath() { diff --git a/src/Playwright.Tests/TracingTests.cs b/src/Playwright.Tests/TracingTests.cs index 055f176dd..8fa12bbac 100644 --- a/src/Playwright.Tests/TracingTests.cs +++ b/src/Playwright.Tests/TracingTests.cs @@ -47,6 +47,7 @@ await Context.Tracing.StartAsync(new() await page.ClickAsync("\"Click\""); await page.Mouse.MoveAsync(20, 20); await page.Mouse.DblClickAsync(20, 30); + await page.APIRequest.GetAsync(Server.Prefix + "/empty.html"); await page.Keyboard.InsertTextAsync("abc"); await page.WaitForTimeoutAsync(2000); // Give it some time to produce screenshots. await page.CloseAsync(); @@ -64,6 +65,7 @@ await Expect(traceViewer.ActionTitles).ToHaveTextAsync([ new Regex(@"Click"), new Regex(@"Mouse move"), new Regex(@"Double click"), + new Regex(@"GET ""/empty.html"""), new Regex(@"Insert ""abc"""), new Regex(@"Wait for timeout"), new Regex(@"Close") @@ -404,7 +406,7 @@ class TraceViewerPage(IPage page) public ILocator ActionTitles => Page.Locator(".action-title"); - public ILocator StackFrames => Page.GetByTestId("stack-trace-list").Locator(".list-view-entry"); + public ILocator StackFrames => Page.GetByRole(AriaRole.List, new() { Name = "Stack trace" }).GetByRole(AriaRole.Listitem); public async Task SelectActionAsync(string title, int ordinal = 0) { diff --git a/src/Playwright.Tests/UnrouteBehaviorTests.cs b/src/Playwright.Tests/UnrouteBehaviorTests.cs index f386c26ed..17a646655 100644 --- a/src/Playwright.Tests/UnrouteBehaviorTests.cs +++ b/src/Playwright.Tests/UnrouteBehaviorTests.cs @@ -380,4 +380,40 @@ await Page.RouteAsync(new Regex(".*"), (route) => await Page.CloseAsync(); await route.FulfillAsync(new() { Status = (int)HttpStatusCode.OK }); } + + [PlaywrightTest("unroute-behavior.spec.ts", "should not continue requests in flight (page)")] + public async Task ShouldNotContinueRequestsInFlightPage() + { + await Page.GotoAsync(Server.EmptyPage); + + var routePromise = new TaskCompletionSource(); + await Page.RouteAsync(new Regex(".*"), async (route) => + { + routePromise.SetResult(route); + await Page.WaitForTimeoutAsync(3000); + await route.FulfillAsync(new() { Status = (int)HttpStatusCode.OK }); + }); + + Page.EvaluateAsync("() => fetch('/')").IgnoreException(); + await routePromise.Task; + await Page.UnrouteAllAsync(new() { Behavior = UnrouteBehavior.Wait }); + } + + [PlaywrightTest("unroute-behavior.spec.ts", "should not continue requests in flight (context)")] + public async Task ShouldNotContinueRequestsInFlightContext() + { + await Page.GotoAsync(Server.EmptyPage); + + var routePromise = new TaskCompletionSource(); + await Context.RouteAsync(new Regex(".*"), async (route) => + { + routePromise.SetResult(route); + await Page.WaitForTimeoutAsync(3000); + await route.FulfillAsync(new() { Status = (int)HttpStatusCode.OK }); + }); + + Page.EvaluateAsync("() => fetch('/')").IgnoreException(); + await routePromise.Task; + await Context.UnrouteAllAsync(new() { Behavior = UnrouteBehavior.Wait }); + } } diff --git a/src/Playwright/API/Generated/IBrowserContext.cs b/src/Playwright/API/Generated/IBrowserContext.cs index 1062bbbf4..45d1211de 100644 --- a/src/Playwright/API/Generated/IBrowserContext.cs +++ b/src/Playwright/API/Generated/IBrowserContext.cs @@ -279,8 +279,8 @@ public partial interface IBrowserContext /// /// - /// Returns the browser instance of the context. If it was launched as a persistent - /// context null gets returned. + /// Gets the browser instance that owns the context. Returns null if the context + /// is created outside of normal browser, e.g. Android or Electron. /// /// IBrowser? Browser { get; } @@ -471,6 +471,7 @@ public partial interface IBrowserContext /// 'notifications' /// 'payment-handler' /// 'storage-access' + /// 'local-fonts' /// /// /// Call options diff --git a/src/Playwright/API/Generated/IMouse.cs b/src/Playwright/API/Generated/IMouse.cs index 436a3d8c0..0491cd1fc 100644 --- a/src/Playwright/API/Generated/IMouse.cs +++ b/src/Playwright/API/Generated/IMouse.cs @@ -31,6 +31,12 @@ namespace Microsoft.Playwright; /// The Mouse class operates in main-frame CSS pixels relative to the top-left corner /// of the viewport. /// +/// +/// If you want to debug where the mouse moved, you can use the Trace +/// viewer or Playwright +/// Inspector. A red dot showing the location of the mouse will be shown for every +/// mouse action. +/// /// Every page object has its own Mouse, accessible with . /// /// await Page.Mouse.MoveAsync(0, 0);
@@ -42,6 +48,14 @@ namespace Microsoft.Playwright; /// await Page.Mouse.UpAsync(); ///
/// +/// +/// +/// If you want to debug where the mouse moved, you can use the Trace +/// viewer or Playwright +/// Inspector. A red dot showing the location of the mouse will be shown for every +/// mouse action. +/// +/// public partial interface IMouse { /// diff --git a/src/Playwright/API/Generated/Types/BrowserContextCookiesResult.cs b/src/Playwright/API/Generated/Types/BrowserContextCookiesResult.cs index 241392f3e..8598ee841 100644 --- a/src/Playwright/API/Generated/Types/BrowserContextCookiesResult.cs +++ b/src/Playwright/API/Generated/Types/BrowserContextCookiesResult.cs @@ -68,4 +68,8 @@ public partial class BrowserContextCookiesResult [Required] [JsonPropertyName("sameSite")] public SameSiteAttribute SameSite { get; set; } = default!; + + /// + [JsonPropertyName("partitionKey")] + public string? PartitionKey { get; set; } } diff --git a/src/Playwright/API/Generated/Types/Cookie.cs b/src/Playwright/API/Generated/Types/Cookie.cs index 8932e2603..99dd8061c 100644 --- a/src/Playwright/API/Generated/Types/Cookie.cs +++ b/src/Playwright/API/Generated/Types/Cookie.cs @@ -71,4 +71,13 @@ public partial class Cookie /// Optional. [JsonPropertyName("sameSite")] public SameSiteAttribute? SameSite { get; set; } + + /// + /// + /// For partitioned third-party cookies (aka CHIPS), + /// the partition key. Optional. + /// + /// + [JsonPropertyName("partitionKey")] + public string? PartitionKey { get; set; } } diff --git a/src/Playwright/Core/AssertionsBase.cs b/src/Playwright/Core/AssertionsBase.cs index d53e1ef9d..26c35a977 100644 --- a/src/Playwright/Core/AssertionsBase.cs +++ b/src/Playwright/Core/AssertionsBase.cs @@ -42,15 +42,17 @@ internal class AssertionsBase { private static float _defaultTimeout = 5_000; - public AssertionsBase(ILocator actual, bool isNot) + public AssertionsBase(bool isNot) { - ActualLocator = (Locator)actual; IsNot = isNot; } protected bool IsNot { get; } - protected Locator ActualLocator { get; } + protected virtual Task CallExpectAsync(string expression, FrameExpectOptions expectOptions, string title) + { + throw new NotImplementedException("CallExpectAsync must be implemented in a derived class."); + } protected async Task ExpectImplAsync(string expression, ExpectedTextValue textValue, object expected, string message, string title, FrameExpectOptions options) { @@ -75,7 +77,7 @@ protected async Task ExpectImplAsync(string expression, FrameExpectOptions expec { message = message.Replace("expected to", "expected not to"); } - var result = await ActualLocator.ExpectAsync(expression, expectOptions, title).ConfigureAwait(false); + var result = await CallExpectAsync(expression, expectOptions, title).ConfigureAwait(false); if (result.Matches == IsNot) { var actual = result.Received; diff --git a/src/Playwright/Core/BrowserContext.cs b/src/Playwright/Core/BrowserContext.cs index 50436cd84..469ba996b 100644 --- a/src/Playwright/Core/BrowserContext.cs +++ b/src/Playwright/Core/BrowserContext.cs @@ -43,6 +43,7 @@ internal class BrowserContext : ChannelOwner, IBrowserContext private readonly TaskCompletionSource _closeTcs = new(); private readonly Dictionary _bindings = new(); private readonly BrowserContextInitializer _initializer; + private readonly string? _baseURL; internal readonly Tracing _tracing; private readonly Clock _clock; internal readonly HashSet _backgroundPages = new(); @@ -66,6 +67,10 @@ internal BrowserContext(ChannelOwner parent, string guid, BrowserContextInitiali _request = initializer.RequestContext; _request._timeoutSettings = this._timeoutSettings; _initializer = initializer; + if (_initializer.Options.TryGetProperty("baseURL", out var baseURL)) + { + _baseURL = baseURL.GetString(); + } } private event EventHandler? _requestImpl; @@ -136,7 +141,7 @@ public event EventHandler RequestFailed internal Page? OwnerPage { get; set; } - internal Options Options => _initializer.Options; + internal string? BaseURL => _baseURL; internal bool ClosingOrClosed { get; private set; } @@ -281,6 +286,15 @@ internal async Task InitializeHarFromOptionsAsync(BrowserNewContextOptions optio await RecordIntoHarAsync(options.RecordHarPath, null, routeFromHAROptions, contentPolicy).ConfigureAwait(false); } + internal string? VideosDir() + { + if (_initializer.Options.TryGetProperty("recordVideo", out var recordVideo)) + { + return recordVideo.GetProperty("dir").GetString(); + } + return null; + } + [MethodImpl(MethodImplOptions.NoInlining)] public Task AddCookiesAsync(IEnumerable cookies) => SendMessageToServerAsync( "addCookies", @@ -716,7 +730,7 @@ internal bool UrlMatches(string url, string globMatch) => new URLMatch() { glob = globMatch, - baseURL = Options.BaseURL, + baseURL = BaseURL, }.Match(url); private Task RouteAsync(string? globMatch, Regex? reMatch, Func? funcMatch, Delegate handler, BrowserContextRouteOptions? options) @@ -727,7 +741,7 @@ private Task RouteAsync(string? globMatch, Regex? reMatch, Func? f glob = globMatch, re = reMatch, func = funcMatch, - baseURL = Options.BaseURL, + baseURL = BaseURL, }, Handler = handler, Times = options?.Times, @@ -745,7 +759,7 @@ private async Task UnrouteAsync(string? globMatch, Regex? reMatch, Func(); foreach (var routeHandler in _routes) { - if (routeHandler.urlMatcher.Equals(globMatch, reMatch, funcMatch, Options.BaseURL, false) && (handler == null || routeHandler.Handler == handler)) + if (routeHandler.urlMatcher.Equals(globMatch, reMatch, funcMatch, BaseURL, false) && (handler == null || routeHandler.Handler == handler)) { removed.Add(routeHandler); } @@ -760,13 +774,12 @@ private async Task UnrouteAsync(string? globMatch, Regex? reMatch, Func removed, List remaining, UnrouteBehavior? behavior) { _routes = remaining; - await UpdateInterceptionAsync().ConfigureAwait(false); - if (behavior == null || behavior == UnrouteBehavior.Default) + if (behavior != null && behavior != UnrouteBehavior.Default) { - return; + var tasks = removed.Select(routeHandler => routeHandler.StopAsync(behavior.Value)); + await Task.WhenAll(tasks).ConfigureAwait(false); } - var tasks = removed.Select(routeHandler => routeHandler.StopAsync(behavior.Value)); - await Task.WhenAll(tasks).ConfigureAwait(false); + await UpdateInterceptionAsync().ConfigureAwait(false); } private async Task UpdateInterceptionAsync() @@ -928,7 +941,7 @@ private Task RouteWebSocketAsync(string? globMatch, Regex? reMatch, Func { - ["timeout"] = timeout, + ["waitTimeout"] = timeout, }); [MethodImpl(MethodImplOptions.NoInlining)] @@ -314,7 +314,7 @@ await waiter.WaitForEventAsync(this, "LoadState", s => glob = urlString, re = urlRegex, func = urlFunc, - baseURL = (Page as Page)?.Context.Options.BaseURL, + baseURL = (Page as Page)?.Context.BaseURL, }.Match(e.Url); }); @@ -890,7 +890,7 @@ public Task DragAndDropAsync(string source, string target, FrameDragAndDropOptio ["targetPosition"] = options?.TargetPosition, }); - internal async Task ExpectAsync(string selector, string expression, FrameExpectOptions options) + internal async Task ExpectAsync(string? selector, string expression, FrameExpectOptions options) { var result = await SendMessageToServerAsync("expect", new Dictionary { @@ -919,7 +919,7 @@ private Task WaitForURLAsync(string? urlString, Regex? urlRegex, Func new LocatorAssertions(ActualLocator, !IsNot); + protected override Task CallExpectAsync(string expression, FrameExpectOptions expectOptions, string title) + { + return ActualLocator.ExpectAsync(expression, expectOptions, title); + } + public Task ToBeAttachedAsync(LocatorAssertionsToBeAttachedOptions? options = null) { var attached = options == null || options.Attached == null || options.Attached == true; diff --git a/src/Playwright/Core/Page.cs b/src/Playwright/Core/Page.cs index bd56f912b..89a853688 100644 --- a/src/Playwright/Core/Page.cs +++ b/src/Playwright/Core/Page.cs @@ -198,7 +198,7 @@ public IVideo? Video { get { - if (Context.Options?.RecordVideo?.Dir == null) + if (Context.VideosDir() == null) { return null; } @@ -1228,7 +1228,7 @@ private Task RouteAsync(string? globMatch, Regex? reMatch, Func? f glob = globMatch, re = reMatch, func = funcMatch, - baseURL = Context.Options.BaseURL, + baseURL = Context.BaseURL, }, Handler = handler, Times = options?.Times, @@ -1246,7 +1246,7 @@ private async Task UnrouteAsync(string? globMatch, Regex? reMatch, Func(); foreach (var routeHandler in _routes) { - if (routeHandler.urlMatcher.Equals(globMatch, reMatch, funcMatch, Context.Options.BaseURL, false) && (handler == null || routeHandler.Handler == handler)) + if (routeHandler.urlMatcher.Equals(globMatch, reMatch, funcMatch, Context.BaseURL, false) && (handler == null || routeHandler.Handler == handler)) { removed.Add(routeHandler); } @@ -1261,13 +1261,13 @@ private async Task UnrouteAsync(string? globMatch, Regex? reMatch, Func removed, List remaining, UnrouteBehavior? behavior) { _routes = remaining; - await UpdateInterceptionAsync().ConfigureAwait(false); - if (behavior == null || behavior == UnrouteBehavior.Default) + if (behavior != null && behavior != UnrouteBehavior.Default) { + var tasks = removed.Select(routeHandler => routeHandler.StopAsync(behavior.Value)); + await Task.WhenAll(tasks).ConfigureAwait(false); return; } - var tasks = removed.Select(routeHandler => routeHandler.StopAsync(behavior.Value)); - await Task.WhenAll(tasks).ConfigureAwait(false); + await UpdateInterceptionAsync().ConfigureAwait(false); } private async Task UpdateInterceptionAsync() @@ -1594,7 +1594,7 @@ private Task RouteWebSocketAsync(string? globMatch, Regex? urlRegex, Func new PageAssertions(_page, !IsNot); - private static T PassThroughNonNull(T value) + protected override Task CallExpectAsync(string expression, FrameExpectOptions expectOptions, string title) { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - return value; + var frame = _page.MainFrame; + return frame.WrapApiCallAsync( + () => frame.ExpectAsync(null, expression, expectOptions), + false, + title); } public Task ToHaveTitleAsync(string titleOrRegExp, PageAssertionsToHaveTitleOptions? options = null) => @@ -58,7 +56,7 @@ public Task ToHaveTitleAsync(Regex titleOrRegExp, PageAssertionsToHaveTitleOptio ExpectImplAsync("to.have.title", ExpectedRegex(titleOrRegExp, new() { NormalizeWhiteSpace = true }), titleOrRegExp, "Page title expected to be", "Expect \"ToHaveTitleAsync\"", ConvertToFrameExpectOptions(options)); public Task ToHaveURLAsync(string urlOrRegExp, PageAssertionsToHaveURLOptions? options = null) => - ExpectImplAsync("to.have.url", new ExpectedTextValue() { String = URLMatch.ConstructURLBasedOnBaseURL(_page.Context.Options.BaseURL, urlOrRegExp), IgnoreCase = options?.IgnoreCase }, urlOrRegExp, "Page URL expected to be", "Expect \"ToHaveURLAsync\"", ConvertToFrameExpectOptions(options)); + ExpectImplAsync("to.have.url", new ExpectedTextValue() { String = URLMatch.ConstructURLBasedOnBaseURL(_page.Context.BaseURL, urlOrRegExp), IgnoreCase = options?.IgnoreCase }, urlOrRegExp, "Page URL expected to be", "Expect \"ToHaveURLAsync\"", ConvertToFrameExpectOptions(options)); public Task ToHaveURLAsync(Regex urlOrRegExp, PageAssertionsToHaveURLOptions? options = null) => ExpectImplAsync("to.have.url", ExpectedRegex(urlOrRegExp, new() { IgnoreCase = options?.IgnoreCase }), urlOrRegExp, "Page URL expected to match regex", "Expect \"ToHaveURLAsync\"", ConvertToFrameExpectOptions(options)); diff --git a/src/Playwright/Core/Selectors.cs b/src/Playwright/Core/Selectors.cs index 030d8beda..506fd7c9c 100644 --- a/src/Playwright/Core/Selectors.cs +++ b/src/Playwright/Core/Selectors.cs @@ -23,6 +23,7 @@ */ using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.Playwright.Helpers; @@ -36,6 +37,11 @@ internal class Selectors : ISelectors public async Task RegisterAsync(string name, SelectorsRegisterOptions? options = default) { + if (_selectorEngines.Where(engine => engine["name"]?.ToString() == name).Any()) + { + throw new PlaywrightException($"\"{name}\" selector engine has been already registered"); + } + options ??= new SelectorsRegisterOptions(); var source = ScriptsHelper.EvaluationScript(options.Script, options.Path, false); var engine = new Dictionary() diff --git a/src/Playwright/Core/WebSocketRoute.cs b/src/Playwright/Core/WebSocketRoute.cs index fde2f963c..a056c144b 100644 --- a/src/Playwright/Core/WebSocketRoute.cs +++ b/src/Playwright/Core/WebSocketRoute.cs @@ -177,7 +177,13 @@ internal async Task AfterHandleAsync() return; } // Ensure that websocket is "open" and can send messages without an actual server connection. - await SendMessageToServerAsync("ensureOpened").ConfigureAwait(false); + try + { + await SendMessageToServerAsync("ensureOpened").ConfigureAwait(false); + } + catch + { + } } } diff --git a/src/Playwright/Helpers/URLMatch.cs b/src/Playwright/Helpers/URLMatch.cs index 4562e7caf..86f8c4dfe 100644 --- a/src/Playwright/Helpers/URLMatch.cs +++ b/src/Playwright/Helpers/URLMatch.cs @@ -224,6 +224,12 @@ string MapToken(string original, string replacement) // Escaped `\\?` behaves the same as `?` in our glob patterns. match = match.Replace("\\\\?", "?"); + // Special case about: URLs as they are not relative to baseURL + if (match.StartsWith("about:") || match.StartsWith("data:") || match.StartsWith("chrome:") || + match.StartsWith("edge:") || match.StartsWith("file:")) + { + return match; + } // Glob symbols may be escaped in the URL and some of them such as ? affect resolution, // so we replace them with safe components first. var relativePath = string.Join("/", match.Split('/').Select((token, index) => diff --git a/src/Playwright/Transport/Protocol/Generated/BrowserContextInitializer.cs b/src/Playwright/Transport/Protocol/Generated/BrowserContextInitializer.cs index f5060b1ec..a7372428a 100644 --- a/src/Playwright/Transport/Protocol/Generated/BrowserContextInitializer.cs +++ b/src/Playwright/Transport/Protocol/Generated/BrowserContextInitializer.cs @@ -38,5 +38,5 @@ internal class BrowserContextInitializer : EventTargetInitializer public Core.Tracing Tracing { get; set; } = null!; [JsonPropertyName("options")] - public Options Options { get; set; } = null!; + public System.Text.Json.JsonElement Options { get; set; } } diff --git a/src/Playwright/Transport/Protocol/Generated/Options.cs b/src/Playwright/Transport/Protocol/Generated/Options.cs deleted file mode 100644 index 8ae316c09..000000000 --- a/src/Playwright/Transport/Protocol/Generated/Options.cs +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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.Transport.Protocol; - -internal class Options -{ - [JsonPropertyName("noDefaultViewport")] - public bool? NoDefaultViewport { get; set; } - - [JsonPropertyName("viewport")] - public ViewportSize Viewport { get; set; } = null!; - - [JsonPropertyName("screen")] - public ViewportSize Screen { get; set; } = null!; - - [JsonPropertyName("ignoreHTTPSErrors")] - public bool? IgnoreHTTPSErrors { get; set; } - - [JsonPropertyName("clientCertificates")] - public List ClientCertificates { get; set; } = null!; - - [JsonPropertyName("javaScriptEnabled")] - public bool? JavaScriptEnabled { get; set; } - - [JsonPropertyName("bypassCSP")] - public bool? BypassCSP { get; set; } - - [JsonPropertyName("userAgent")] - public string UserAgent { get; set; } = null!; - - [JsonPropertyName("locale")] - public string Locale { get; set; } = null!; - - [JsonPropertyName("timezoneId")] - public string TimezoneId { get; set; } = null!; - - [JsonPropertyName("geolocation")] - public OptionsGeolocation Geolocation { get; set; } = null!; - - [JsonPropertyName("permissions")] - public List Permissions { get; set; } = null!; - - [JsonPropertyName("extraHTTPHeaders")] - public List ExtraHTTPHeaders { get; set; } = null!; - - [JsonPropertyName("offline")] - public bool? Offline { get; set; } - - [JsonPropertyName("httpCredentials")] - public OptionsHttpCredentials HttpCredentials { get; set; } = null!; - - [JsonPropertyName("deviceScaleFactor")] - public int? DeviceScaleFactor { get; set; } - - [JsonPropertyName("isMobile")] - public bool? IsMobile { get; set; } - - [JsonPropertyName("hasTouch")] - public bool? HasTouch { get; set; } - - [JsonPropertyName("colorScheme")] - public string ColorScheme { get; set; } = null!; - - [JsonPropertyName("reducedMotion")] - public string ReducedMotion { get; set; } = null!; - - [JsonPropertyName("forcedColors")] - public string ForcedColors { get; set; } = null!; - - [JsonPropertyName("acceptDownloads")] - public string AcceptDownloads { get; set; } = null!; - - [JsonPropertyName("contrast")] - public string Contrast { get; set; } = null!; - - [JsonPropertyName("baseURL")] - public string BaseURL { get; set; } = null!; - - [JsonPropertyName("recordVideo")] - public OptionsRecordVideo RecordVideo { get; set; } = null!; - - [JsonPropertyName("strictSelectors")] - public bool? StrictSelectors { get; set; } - - [JsonPropertyName("serviceWorkers")] - public string ServiceWorkers { get; set; } = null!; - - [JsonPropertyName("selectorEngines")] - public List SelectorEngines { get; set; } = null!; - - [JsonPropertyName("testIdAttributeName")] - public string TestIdAttributeName { get; set; } = null!; -} diff --git a/src/Playwright/Transport/Protocol/Generated/OptionsClientCertificates.cs b/src/Playwright/Transport/Protocol/Generated/OptionsClientCertificates.cs deleted file mode 100644 index 1bb3bd4d2..000000000 --- a/src/Playwright/Transport/Protocol/Generated/OptionsClientCertificates.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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; - -namespace Microsoft.Playwright.Transport.Protocol; - -internal class OptionsClientCertificates -{ - [JsonPropertyName("origin")] - public string Origin { get; set; } = null!; - - [JsonPropertyName("cert")] - public byte[] Cert { get; set; } = null!; - - [JsonPropertyName("key")] - public byte[] Key { get; set; } = null!; - - [JsonPropertyName("passphrase")] - public string Passphrase { get; set; } = null!; - - [JsonPropertyName("pfx")] - public byte[] Pfx { get; set; } = null!; -} diff --git a/src/Playwright/Transport/Protocol/Generated/OptionsGeolocation.cs b/src/Playwright/Transport/Protocol/Generated/OptionsGeolocation.cs deleted file mode 100644 index ceff46f3f..000000000 --- a/src/Playwright/Transport/Protocol/Generated/OptionsGeolocation.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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; - -namespace Microsoft.Playwright.Transport.Protocol; - -internal class OptionsGeolocation -{ - [JsonPropertyName("longitude")] - public int Longitude { get; set; } - - [JsonPropertyName("latitude")] - public int Latitude { get; set; } - - [JsonPropertyName("accuracy")] - public int? Accuracy { get; set; } -} diff --git a/src/Playwright/Transport/Protocol/Generated/OptionsHttpCredentials.cs b/src/Playwright/Transport/Protocol/Generated/OptionsHttpCredentials.cs deleted file mode 100644 index 474ba3a54..000000000 --- a/src/Playwright/Transport/Protocol/Generated/OptionsHttpCredentials.cs +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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; - -namespace Microsoft.Playwright.Transport.Protocol; - -internal class OptionsHttpCredentials -{ - [JsonPropertyName("username")] - public string Username { get; set; } = null!; - - [JsonPropertyName("password")] - public string Password { get; set; } = null!; - - [JsonPropertyName("origin")] - public string Origin { get; set; } = null!; - - [JsonPropertyName("send")] - public string Send { get; set; } = null!; -} diff --git a/src/Playwright/Transport/Protocol/Generated/OptionsRecordVideo.cs b/src/Playwright/Transport/Protocol/Generated/OptionsRecordVideo.cs deleted file mode 100644 index ae1239d2c..000000000 --- a/src/Playwright/Transport/Protocol/Generated/OptionsRecordVideo.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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; - -namespace Microsoft.Playwright.Transport.Protocol; - -internal class OptionsRecordVideo -{ - [JsonPropertyName("dir")] - public string Dir { get; set; } = null!; - - [JsonPropertyName("size")] - public ViewportSize Size { get; set; } = null!; -} diff --git a/src/Playwright/Transport/Protocol/Generated/PlaywrightInitializer.cs b/src/Playwright/Transport/Protocol/Generated/PlaywrightInitializer.cs index a6b510da9..4dd26950c 100644 --- a/src/Playwright/Transport/Protocol/Generated/PlaywrightInitializer.cs +++ b/src/Playwright/Transport/Protocol/Generated/PlaywrightInitializer.cs @@ -37,11 +37,11 @@ internal class PlaywrightInitializer [JsonPropertyName("webkit")] public Core.BrowserType Webkit { get; set; } = null!; - [JsonPropertyName("bidiChromium")] - public Core.BrowserType BidiChromium { get; set; } = null!; + [JsonPropertyName("_bidiChromium")] + public Core.BrowserType _bidiChromium { get; set; } = null!; - [JsonPropertyName("bidiFirefox")] - public Core.BrowserType BidiFirefox { get; set; } = null!; + [JsonPropertyName("_bidiFirefox")] + public Core.BrowserType _bidiFirefox { get; set; } = null!; [JsonPropertyName("utils")] public Core.LocalUtils Utils { get; set; } = null!;