mirror of
https://github.com/microsoft/playwright-dotnet.git
synced 2026-10-29 06:07:22 +08:00
chore(roll): roll Playwright to v1.47.0 (#3000)
This commit is contained in:
@@ -3,9 +3,9 @@
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
| :--- | :---: | :---: | :---: |
|
||||
| Chromium <!-- GEN:chromium-version -->128.0.6613.18<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Chromium <!-- GEN:chromium-version -->129.0.6668.29<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| WebKit <!-- GEN:webkit-version -->18.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->128.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->130.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
|
||||
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**.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<PropertyGroup>
|
||||
<AssemblyVersion>1.46.0</AssemblyVersion>
|
||||
<PackageVersion>$(AssemblyVersion)</PackageVersion>
|
||||
<DriverVersion>1.46.0</DriverVersion>
|
||||
<DriverVersion>1.47.0</DriverVersion>
|
||||
<ReleaseVersion>$(AssemblyVersion)</ReleaseVersion>
|
||||
<FileVersion>$(AssemblyVersion)</FileVersion>
|
||||
<NoDefaultExcludes>true</NoDefaultExcludes>
|
||||
|
||||
@@ -103,22 +103,35 @@ public class BrowserContextFetchTests : PageTestEx
|
||||
Assert.AreEqual("username=John Doe", cookieHeader);
|
||||
}
|
||||
|
||||
[PlaywrightTest("browsercontext-fetch.spec.ts", "should support queryParams")]
|
||||
public async Task ShouldSupportQueryParams()
|
||||
[PlaywrightTest("browsercontext-fetch.spec.ts", "should support paras passed as object")]
|
||||
public async Task ShouldSupportParamsPassedAsObject()
|
||||
{
|
||||
var queryString = new QueryString();
|
||||
queryString.Add("p1", "v1");
|
||||
queryString.Add("парам2", "знач2");
|
||||
var requestOptions = new APIRequestContextOptions() { Params = new Dictionary<string, object>() { { "p1", "v1" }, { "парам2", "знач2" } } };
|
||||
var requestOptions = new APIRequestContextOptions() { Params = new Dictionary<string, object>() { { "param1", "value1" }, { "парам2", "знач2" } } };
|
||||
await ForAllMethods(Context.APIRequest, async responseTask =>
|
||||
{
|
||||
var (receivedQueryString, _) = await TaskUtils.WhenAll(
|
||||
Server.WaitForRequest("/empty.html", request => request.Query),
|
||||
responseTask
|
||||
);
|
||||
Assert.AreEqual("v1", receivedQueryString["p1"].First());
|
||||
CollectionAssert.AreEquivalent(new[] { "value1", "value2" }, receivedQueryString["param1"]);
|
||||
Assert.AreEqual("знач2", receivedQueryString["парам2"].First());
|
||||
}, Server.Prefix + "/empty.html?" + queryString.ToString(), requestOptions);
|
||||
}, Server.Prefix + "/empty.html?param1=value2", requestOptions);
|
||||
}
|
||||
|
||||
[PlaywrightTest("browsercontext-fetch.spec.ts", "should support params passed as string")]
|
||||
public async Task ShouldSupportParamsPassedAsString()
|
||||
{
|
||||
var queryParams = "?param1=value1¶m1=value2&парам2=знач2";
|
||||
var requestOptions = new APIRequestContextOptions() { ParamsString = queryParams };
|
||||
await ForAllMethods(Context.APIRequest, async responseTask =>
|
||||
{
|
||||
var (receivedQueryString, _) = await TaskUtils.WhenAll(
|
||||
Server.WaitForRequest("/empty.html", request => request.Query),
|
||||
responseTask
|
||||
);
|
||||
CollectionAssert.AreEquivalent(new[] { "value1", "value2" }, receivedQueryString["param1"]);
|
||||
Assert.AreEqual("знач2", string.Join(",", receivedQueryString["парам2"]));
|
||||
}, Server.Prefix + "/empty.html", requestOptions);
|
||||
}
|
||||
|
||||
[PlaywrightTest("browsercontext-fetch.spec.ts", "should support failOnStatusCode")]
|
||||
|
||||
@@ -147,6 +147,40 @@ public class ClientCertificatesTests : BrowserTestEx
|
||||
await context.CloseAsync();
|
||||
}
|
||||
|
||||
[PlaywrightTest("", "")]
|
||||
public async Task ShouldWorkWithNewContextAndCertificateAsContent()
|
||||
{
|
||||
var context = await Browser.NewContextAsync(new()
|
||||
{
|
||||
IgnoreHTTPSErrors = true,
|
||||
ClientCertificates =
|
||||
[
|
||||
new()
|
||||
{
|
||||
Origin = "https://localhost:10000",
|
||||
Cert = File.ReadAllBytes(TestUtils.GetAsset("client-certificates/client/trusted/cert.pem")),
|
||||
Key = File.ReadAllBytes(TestUtils.GetAsset("client-certificates/client/trusted/key.pem")),
|
||||
}
|
||||
]
|
||||
});
|
||||
var page = await context.NewPageAsync();
|
||||
{
|
||||
await page.GotoAsync("https://127.0.0.1:10000");
|
||||
await Expect(page.GetByTestId("message")).ToHaveTextAsync("Sorry, but you need to provide a client certificate to continue.");
|
||||
|
||||
var response = await page.APIRequest.GetAsync("https://127.0.0.1:10000");
|
||||
StringAssert.Contains("Sorry, but you need to provide a client certificate to continue", await response.TextAsync());
|
||||
}
|
||||
{
|
||||
await page.GotoAsync("https://localhost:10000");
|
||||
await Expect(page.GetByText("Hello CN=Alice")).ToBeVisibleAsync();
|
||||
|
||||
var response = await page.APIRequest.GetAsync("https://localhost:10000");
|
||||
StringAssert.Contains("Hello CN=Alice", await response.TextAsync());
|
||||
}
|
||||
await context.CloseAsync();
|
||||
}
|
||||
|
||||
[PlaywrightTest("", "")]
|
||||
public async Task ShouldWorkWithNewPage()
|
||||
{
|
||||
|
||||
@@ -46,7 +46,7 @@ public partial interface IAPIResponse
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// An array with all the request HTTP headers associated with this response. Header
|
||||
/// An array with all the response HTTP headers associated with this response. Header
|
||||
/// names are not lower-cased. Headers with multiple entries, such as <c>Set-Cookie</c>,
|
||||
/// appear in the array multiple times.
|
||||
/// </para>
|
||||
|
||||
@@ -38,8 +38,8 @@ namespace Microsoft.Playwright;
|
||||
/// belong to the parent page's browser context.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Playwright allows creating "incognito" browser contexts with <see cref="IBrowser.NewContextAsync"/>
|
||||
/// method. "Incognito" browser contexts don't write any browsing data to disk.
|
||||
/// Playwright allows creating isolated non-persistent browser contexts with <see cref="IBrowser.NewContextAsync"/>
|
||||
/// method. Non-persistent browser contexts don't write any browsing data to disk.
|
||||
/// </para>
|
||||
/// <code>
|
||||
/// using var playwright = await Playwright.CreateAsync();<br/>
|
||||
|
||||
@@ -60,14 +60,14 @@ public partial interface IPageAssertions
|
||||
/// Makes the assertion check for the opposite condition. For example, this code tests
|
||||
/// that the page URL doesn't contain <c>"error"</c>:
|
||||
/// </para>
|
||||
/// <code>await Expect(Page).Not.ToHaveURL("error");</code>
|
||||
/// <code>await Expect(Page).Not.ToHaveURLAsync("error");</code>
|
||||
/// </summary>
|
||||
public IPageAssertions Not { get; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>Ensures the page has the given title.</para>
|
||||
/// <para>**Usage**</para>
|
||||
/// <code>await Expect(Page).ToHaveTitle("Playwright");</code>
|
||||
/// <code>await Expect(Page).ToHaveTitleAsync("Playwright");</code>
|
||||
/// </summary>
|
||||
/// <param name="titleOrRegExp">Expected title or RegExp.</param>
|
||||
/// <param name="options">Call options</param>
|
||||
@@ -76,7 +76,7 @@ public partial interface IPageAssertions
|
||||
/// <summary>
|
||||
/// <para>Ensures the page has the given title.</para>
|
||||
/// <para>**Usage**</para>
|
||||
/// <code>await Expect(Page).ToHaveTitle("Playwright");</code>
|
||||
/// <code>await Expect(Page).ToHaveTitleAsync("Playwright");</code>
|
||||
/// </summary>
|
||||
/// <param name="titleOrRegExp">Expected title or RegExp.</param>
|
||||
/// <param name="options">Call options</param>
|
||||
@@ -85,7 +85,7 @@ public partial interface IPageAssertions
|
||||
/// <summary>
|
||||
/// <para>Ensures the page is navigated to the given URL.</para>
|
||||
/// <para>**Usage**</para>
|
||||
/// <code>await Expect(Page).ToHaveURL(new Regex(".*checkout"));</code>
|
||||
/// <code>await Expect(Page).ToHaveURLAsync(new Regex(".*checkout"));</code>
|
||||
/// </summary>
|
||||
/// <param name="urlOrRegExp">Expected URL string or RegExp.</param>
|
||||
/// <param name="options">Call options</param>
|
||||
@@ -94,7 +94,7 @@ public partial interface IPageAssertions
|
||||
/// <summary>
|
||||
/// <para>Ensures the page is navigated to the given URL.</para>
|
||||
/// <para>**Usage**</para>
|
||||
/// <code>await Expect(Page).ToHaveURL(new Regex(".*checkout"));</code>
|
||||
/// <code>await Expect(Page).ToHaveURLAsync(new Regex(".*checkout"));</code>
|
||||
/// </summary>
|
||||
/// <param name="urlOrRegExp">Expected URL string or RegExp.</param>
|
||||
/// <param name="options">Call options</param>
|
||||
|
||||
@@ -73,7 +73,7 @@ public partial interface IRoute
|
||||
Task AbortAsync(string? errorCode = default);
|
||||
|
||||
/// <summary>
|
||||
/// <para>Continues route's request with optional overrides.</para>
|
||||
/// <para>Sends route's request to the network with optional overrides.</para>
|
||||
/// <para>**Usage**</para>
|
||||
/// <code>
|
||||
/// await page.RouteAsync("**/*", async route =><br/>
|
||||
@@ -91,19 +91,29 @@ public partial interface IRoute
|
||||
/// through redirects, use the combination of <see cref="IRoute.FetchAsync"/> and <see
|
||||
/// cref="IRoute.FulfillAsync"/> instead.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <see cref="IRoute.ContinueAsync"/> will immediately send the request to the network,
|
||||
/// other matching handlers won't be invoked. Use <see cref="IRoute.FallbackAsync"/>
|
||||
/// If you want next matching handler in the chain to be invoked.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="options">Call options</param>
|
||||
Task ContinueAsync(RouteContinueOptions? options = default);
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Continues route's request with optional overrides. The method is similar to <see
|
||||
/// cref="IRoute.ContinueAsync"/> with the difference that other matching handlers will
|
||||
/// be invoked before sending the request.
|
||||
/// </para>
|
||||
/// <para>**Usage**</para>
|
||||
/// <para>
|
||||
/// When several routes match the given pattern, they run in the order opposite to their
|
||||
/// registration. That way the last registered route can always override all the previous
|
||||
/// ones. In the example below, request will be handled by the bottom-most handler first,
|
||||
/// then it'll fall back to the previous one and in the end will be aborted by the first
|
||||
/// registered route.
|
||||
/// </para>
|
||||
/// <para>**Usage**</para>
|
||||
/// <code>
|
||||
/// await page.RouteAsync("**/*", route => {<br/>
|
||||
/// // Runs last.<br/>
|
||||
@@ -158,6 +168,10 @@ public partial interface IRoute
|
||||
/// await route.FallbackAsync(new() { Headers = headers });<br/>
|
||||
/// });
|
||||
/// </code>
|
||||
/// <para>
|
||||
/// Use <see cref="IRoute.ContinueAsync"/> to immediately send the request to the network,
|
||||
/// other matching handlers won't be invoked in that case.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="options">Call options</param>
|
||||
Task FallbackAsync(RouteFallbackOptions? options = default);
|
||||
|
||||
@@ -53,6 +53,7 @@ public class APIRequestContextOptions
|
||||
Method = clone.Method;
|
||||
Multipart = clone.Multipart;
|
||||
Params = clone.Params;
|
||||
ParamsString = clone.ParamsString;
|
||||
Timeout = clone.Timeout;
|
||||
}
|
||||
|
||||
@@ -181,6 +182,10 @@ public class APIRequestContextOptions
|
||||
[JsonPropertyName("params")]
|
||||
public IEnumerable<KeyValuePair<string, object>>? Params { get; set; }
|
||||
|
||||
/// <summary><para>Query parameters to be sent with the URL.</para></summary>
|
||||
[JsonPropertyName("paramsString")]
|
||||
public string? ParamsString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Request timeout in milliseconds. Defaults to <c>30000</c> (30 seconds). Pass <c>0</c>
|
||||
|
||||
@@ -83,11 +83,12 @@ public class APIRequestNewContextOptions
|
||||
/// </para>
|
||||
/// <para>**Details**</para>
|
||||
/// <para>
|
||||
/// An array of client certificates to be used. Each certificate object must have both
|
||||
/// <c>certPath</c> and <c>keyPath</c> or a single <c>pfxPath</c> to load the client
|
||||
/// certificate. Optionally, <c>passphrase</c> property should be provided if the certficiate
|
||||
/// is encrypted. The <c>origin</c> property should be provided with an exact match
|
||||
/// to the request origin that the certificate is valid for.
|
||||
/// An array of client certificates to be used. Each certificate object must have either
|
||||
/// both <c>certPath</c> and <c>keyPath</c>, a single <c>pfxPath</c>, or their corresponding
|
||||
/// direct value equivalents (<c>cert</c> and <c>key</c>, or <c>pfx</c>). Optionally,
|
||||
/// <c>passphrase</c> property should be provided if the certificate is encrypted. The
|
||||
/// <c>origin</c> property should be provided with an exact match to the request origin
|
||||
/// that the certificate is valid for.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
|
||||
@@ -124,11 +124,12 @@ public class BrowserNewContextOptions
|
||||
/// </para>
|
||||
/// <para>**Details**</para>
|
||||
/// <para>
|
||||
/// An array of client certificates to be used. Each certificate object must have both
|
||||
/// <c>certPath</c> and <c>keyPath</c> or a single <c>pfxPath</c> to load the client
|
||||
/// certificate. Optionally, <c>passphrase</c> property should be provided if the certficiate
|
||||
/// is encrypted. The <c>origin</c> property should be provided with an exact match
|
||||
/// to the request origin that the certificate is valid for.
|
||||
/// An array of client certificates to be used. Each certificate object must have either
|
||||
/// both <c>certPath</c> and <c>keyPath</c>, a single <c>pfxPath</c>, or their corresponding
|
||||
/// direct value equivalents (<c>cert</c> and <c>key</c>, or <c>pfx</c>). Optionally,
|
||||
/// <c>passphrase</c> property should be provided if the certificate is encrypted. The
|
||||
/// <c>origin</c> property should be provided with an exact match to the request origin
|
||||
/// that the certificate is valid for.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
@@ -259,14 +260,6 @@ public class BrowserNewContextOptions
|
||||
public IEnumerable<string>? Permissions { get; set; }
|
||||
|
||||
/// <summary><para>Network proxy settings to use with this context. Defaults to none.</para></summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// For Chromium on Windows the browser needs to be launched with the global proxy for
|
||||
/// this option to work. If all contexts override the proxy, global proxy will be never
|
||||
/// used and can be any string, for example <c>launch({ proxy: { server: 'http://per-context'
|
||||
/// } })</c>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[JsonPropertyName("proxy")]
|
||||
public Proxy? Proxy { get; set; }
|
||||
|
||||
|
||||
@@ -124,11 +124,12 @@ public class BrowserNewPageOptions
|
||||
/// </para>
|
||||
/// <para>**Details**</para>
|
||||
/// <para>
|
||||
/// An array of client certificates to be used. Each certificate object must have both
|
||||
/// <c>certPath</c> and <c>keyPath</c> or a single <c>pfxPath</c> to load the client
|
||||
/// certificate. Optionally, <c>passphrase</c> property should be provided if the certficiate
|
||||
/// is encrypted. The <c>origin</c> property should be provided with an exact match
|
||||
/// to the request origin that the certificate is valid for.
|
||||
/// An array of client certificates to be used. Each certificate object must have either
|
||||
/// both <c>certPath</c> and <c>keyPath</c>, a single <c>pfxPath</c>, or their corresponding
|
||||
/// direct value equivalents (<c>cert</c> and <c>key</c>, or <c>pfx</c>). Optionally,
|
||||
/// <c>passphrase</c> property should be provided if the certificate is encrypted. The
|
||||
/// <c>origin</c> property should be provided with an exact match to the request origin
|
||||
/// that the certificate is valid for.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
@@ -259,14 +260,6 @@ public class BrowserNewPageOptions
|
||||
public IEnumerable<string>? Permissions { get; set; }
|
||||
|
||||
/// <summary><para>Network proxy settings to use with this context. Defaults to none.</para></summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// For Chromium on Windows the browser needs to be launched with the global proxy for
|
||||
/// this option to work. If all contexts override the proxy, global proxy will be never
|
||||
/// used and can be any string, for example <c>launch({ proxy: { server: 'http://per-context'
|
||||
/// } })</c>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[JsonPropertyName("proxy")]
|
||||
public Proxy? Proxy { get; set; }
|
||||
|
||||
|
||||
@@ -164,11 +164,12 @@ public class BrowserTypeLaunchPersistentContextOptions
|
||||
/// </para>
|
||||
/// <para>**Details**</para>
|
||||
/// <para>
|
||||
/// An array of client certificates to be used. Each certificate object must have both
|
||||
/// <c>certPath</c> and <c>keyPath</c> or a single <c>pfxPath</c> to load the client
|
||||
/// certificate. Optionally, <c>passphrase</c> property should be provided if the certficiate
|
||||
/// is encrypted. The <c>origin</c> property should be provided with an exact match
|
||||
/// to the request origin that the certificate is valid for.
|
||||
/// An array of client certificates to be used. Each certificate object must have either
|
||||
/// both <c>certPath</c> and <c>keyPath</c>, a single <c>pfxPath</c>, or their corresponding
|
||||
/// direct value equivalents (<c>cert</c> and <c>key</c>, or <c>pfx</c>). Optionally,
|
||||
/// <c>passphrase</c> property should be provided if the certificate is encrypted. The
|
||||
/// <c>origin</c> property should be provided with an exact match to the request origin
|
||||
/// that the certificate is valid for.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
|
||||
@@ -54,13 +54,8 @@ public class ElementHandleSelectOptionOptions
|
||||
public bool? Force { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>**DEPRECATED** This option will default to <c>true</c> in the future.</para>
|
||||
/// <para>
|
||||
/// Actions that initiate navigations are waiting for these navigations to happen and
|
||||
/// for pages to start loading. You can opt out of waiting via setting this flag. You
|
||||
/// would only need this option in the exceptional cases such as navigating to inaccessible
|
||||
/// pages. Defaults to <c>false</c>.
|
||||
/// </para>
|
||||
/// <para>**DEPRECATED** This option has no effect.</para>
|
||||
/// <para>This option has no effect.</para>
|
||||
/// </summary>
|
||||
[JsonPropertyName("noWaitAfter")]
|
||||
[System.Obsolete]
|
||||
|
||||
@@ -55,13 +55,8 @@ public class FrameSelectOptionOptions
|
||||
public bool? Force { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>**DEPRECATED** This option will default to <c>true</c> in the future.</para>
|
||||
/// <para>
|
||||
/// Actions that initiate navigations are waiting for these navigations to happen and
|
||||
/// for pages to start loading. You can opt out of waiting via setting this flag. You
|
||||
/// would only need this option in the exceptional cases such as navigating to inaccessible
|
||||
/// pages. Defaults to <c>false</c>.
|
||||
/// </para>
|
||||
/// <para>**DEPRECATED** This option has no effect.</para>
|
||||
/// <para>This option has no effect.</para>
|
||||
/// </summary>
|
||||
[JsonPropertyName("noWaitAfter")]
|
||||
[System.Obsolete]
|
||||
|
||||
@@ -54,13 +54,8 @@ public class LocatorSelectOptionOptions
|
||||
public bool? Force { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>**DEPRECATED** This option will default to <c>true</c> in the future.</para>
|
||||
/// <para>
|
||||
/// Actions that initiate navigations are waiting for these navigations to happen and
|
||||
/// for pages to start loading. You can opt out of waiting via setting this flag. You
|
||||
/// would only need this option in the exceptional cases such as navigating to inaccessible
|
||||
/// pages. Defaults to <c>false</c>.
|
||||
/// </para>
|
||||
/// <para>**DEPRECATED** This option has no effect.</para>
|
||||
/// <para>This option has no effect.</para>
|
||||
/// </summary>
|
||||
[JsonPropertyName("noWaitAfter")]
|
||||
[System.Obsolete]
|
||||
|
||||
@@ -83,7 +83,7 @@ public class PageRouteFromHAROptions
|
||||
/// <para>
|
||||
/// When set to <c>minimal</c>, only record information necessary for routing from HAR.
|
||||
/// This omits sizes, timing, page, cookies, security and other types of HAR information
|
||||
/// that are not used when replaying from HAR. Defaults to <c>full</c>.
|
||||
/// that are not used when replaying from HAR. Defaults to <c>minimal</c>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[JsonPropertyName("updateMode")]
|
||||
|
||||
@@ -55,13 +55,8 @@ public class PageSelectOptionOptions
|
||||
public bool? Force { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>**DEPRECATED** This option will default to <c>true</c> in the future.</para>
|
||||
/// <para>
|
||||
/// Actions that initiate navigations are waiting for these navigations to happen and
|
||||
/// for pages to start loading. You can opt out of waiting via setting this flag. You
|
||||
/// would only need this option in the exceptional cases such as navigating to inaccessible
|
||||
/// pages. Defaults to <c>false</c>.
|
||||
/// </para>
|
||||
/// <para>**DEPRECATED** This option has no effect.</para>
|
||||
/// <para>This option has no effect.</para>
|
||||
/// </summary>
|
||||
[JsonPropertyName("noWaitAfter")]
|
||||
[System.Obsolete]
|
||||
|
||||
@@ -45,14 +45,26 @@ public partial class ClientCertificate
|
||||
[JsonPropertyName("certPath")]
|
||||
public string? CertPath { get; set; }
|
||||
|
||||
/// <summary><para>Direct value of the certificate in PEM format.</para></summary>
|
||||
[JsonPropertyName("cert")]
|
||||
public byte[]? Cert { get; set; }
|
||||
|
||||
/// <summary><para>Path to the file with the private key in PEM format.</para></summary>
|
||||
[JsonPropertyName("keyPath")]
|
||||
public string? KeyPath { get; set; }
|
||||
|
||||
/// <summary><para>Direct value of the private key in PEM format.</para></summary>
|
||||
[JsonPropertyName("key")]
|
||||
public byte[]? Key { get; set; }
|
||||
|
||||
/// <summary><para>Path to the PFX or PKCS12 encoded private key and certificate chain.</para></summary>
|
||||
[JsonPropertyName("pfxPath")]
|
||||
public string? PfxPath { get; set; }
|
||||
|
||||
/// <summary><para>Direct value of the PFX or PKCS12 encoded private key and certificate chain.</para></summary>
|
||||
[JsonPropertyName("pfx")]
|
||||
public byte[]? Pfx { get; set; }
|
||||
|
||||
/// <summary><para>Passphrase for the private key (PEM or PFX).</para></summary>
|
||||
[JsonPropertyName("passphrase")]
|
||||
public string? Passphrase { get; set; }
|
||||
|
||||
@@ -29,6 +29,7 @@ using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using Microsoft.Playwright.Helpers;
|
||||
using Microsoft.Playwright.Transport;
|
||||
using Microsoft.Playwright.Transport.Protocol;
|
||||
@@ -114,12 +115,6 @@ internal class APIRequestContext : ChannelOwner, IAPIRequestContext
|
||||
{
|
||||
throw new PlaywrightException("Only one of 'data', 'form' or 'multipart' can be specified");
|
||||
}
|
||||
|
||||
var queryParams = new Dictionary<string, string>();
|
||||
if (options.Params != null)
|
||||
{
|
||||
queryParams = options.Params.ToDictionary(x => x.Key, x => x.Value.ToString());
|
||||
}
|
||||
byte[] postData = null;
|
||||
object jsonData = null;
|
||||
string dataString = !string.IsNullOrEmpty(options.Data) ? options.Data : options.DataString;
|
||||
@@ -152,7 +147,7 @@ internal class APIRequestContext : ChannelOwner, IAPIRequestContext
|
||||
["maxRedirects"] = options?.MaxRedirects,
|
||||
["maxRetries"] = options?.MaxRetries,
|
||||
["timeout"] = options.Timeout,
|
||||
["params"] = queryParams?.ToProtocol(),
|
||||
["params"] = QueryParamsToProtocol(options.Params, options.ParamsString),
|
||||
["headers"] = options.Headers?.ToProtocol(),
|
||||
["jsonData"] = jsonData,
|
||||
["postData"] = postData != null ? Convert.ToBase64String(postData) : null,
|
||||
@@ -164,6 +159,28 @@ internal class APIRequestContext : ChannelOwner, IAPIRequestContext
|
||||
return new APIResponse(this, response?.GetProperty("response").ToObject<Transport.Protocol.APIResponse>());
|
||||
}
|
||||
|
||||
private static IEnumerable<NameValue> QueryParamsToProtocol(IEnumerable<KeyValuePair<string, object>> @params, string paramsString)
|
||||
{
|
||||
if (@params != null)
|
||||
{
|
||||
return @params.ToDictionary(x => x.Key, x => x.Value.ToString()).ToProtocol();
|
||||
}
|
||||
if (string.IsNullOrEmpty(paramsString))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var result = new List<NameValue>();
|
||||
var paramsCollection = HttpUtility.ParseQueryString(paramsString);
|
||||
foreach (var key in paramsCollection.AllKeys)
|
||||
{
|
||||
foreach (var value in paramsCollection.GetValues(key))
|
||||
{
|
||||
result.Add(new NameValue { Name = key, Value = value });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool IsJsonContentType(IDictionary<string, string> headers)
|
||||
{
|
||||
if (headers == null)
|
||||
|
||||
@@ -329,12 +329,25 @@ internal class Browser : ChannelOwner, IBrowser
|
||||
{
|
||||
["origin"] = clientCertificate.Origin,
|
||||
["passphrase"] = clientCertificate.Passphrase,
|
||||
["cert"] = clientCertificate.CertPath != null ? Convert.ToBase64String(File.ReadAllBytes(clientCertificate.CertPath)) : null,
|
||||
["key"] = clientCertificate.KeyPath != null ? Convert.ToBase64String(File.ReadAllBytes(clientCertificate.KeyPath)) : null,
|
||||
["pfx"] = clientCertificate.PfxPath != null ? Convert.ToBase64String(File.ReadAllBytes(clientCertificate.PfxPath)) : null,
|
||||
["cert"] = ReadClientCertificateFile(clientCertificate.CertPath, clientCertificate.Cert),
|
||||
["key"] = ReadClientCertificateFile(clientCertificate.KeyPath, clientCertificate.Key),
|
||||
["pfx"] = ReadClientCertificateFile(clientCertificate.PfxPath, clientCertificate.Pfx),
|
||||
}
|
||||
.Where(kv => kv.Value != null)
|
||||
.ToDictionary(kv => kv.Key, kv => kv.Value))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static string ReadClientCertificateFile(string path, byte[] value)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
return Convert.ToBase64String(value);
|
||||
}
|
||||
if (path != null)
|
||||
{
|
||||
return Convert.ToBase64String(File.ReadAllBytes(path));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +346,6 @@ internal class ElementHandle : JSHandle, IElementHandle
|
||||
return (await SendMessageToServerAsync("selectOption", new Dictionary<string, object>
|
||||
{
|
||||
["options"] = values,
|
||||
["noWaitAfter"] = noWaitAfter,
|
||||
["force"] = force,
|
||||
["timeout"] = timeout,
|
||||
}).ConfigureAwait(false))?.GetProperty("values").ToObject<string[]>();
|
||||
@@ -357,7 +356,6 @@ internal class ElementHandle : JSHandle, IElementHandle
|
||||
return (await SendMessageToServerAsync("selectOption", new Dictionary<string, object>
|
||||
{
|
||||
["elements"] = values,
|
||||
["noWaitAfter"] = noWaitAfter,
|
||||
["force"] = force,
|
||||
["timeout"] = timeout,
|
||||
}).ConfigureAwait(false))?.GetProperty("values").ToObject<string[]>();
|
||||
|
||||
@@ -179,9 +179,6 @@ internal class Frame : ChannelOwner, IFrame
|
||||
{
|
||||
["selector"] = selector,
|
||||
["elements"] = values.Select(x => x as ElementHandle),
|
||||
#pragma warning disable CS0612 // Type or member is obsolete
|
||||
["noWaitAfter"] = options?.NoWaitAfter,
|
||||
#pragma warning restore CS0612 // Type or member is obsolete
|
||||
["strict"] = options?.Strict,
|
||||
["force"] = options?.Force,
|
||||
["timeout"] = options?.Timeout,
|
||||
|
||||
@@ -37,6 +37,12 @@ internal class PlaywrightInitializer
|
||||
[JsonPropertyName("webkit")]
|
||||
public Core.BrowserType Webkit { get; set; }
|
||||
|
||||
[JsonPropertyName("bidiChromium")]
|
||||
public Core.BrowserType BidiChromium { get; set; }
|
||||
|
||||
[JsonPropertyName("bidiFirefox")]
|
||||
public Core.BrowserType BidiFirefox { get; set; }
|
||||
|
||||
[JsonPropertyName("utils")]
|
||||
public Core.LocalUtils Utils { get; set; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user