diff --git a/src/.editorconfig b/src/.editorconfig
index b5d069ce8e..a7814561c3 100644
--- a/src/.editorconfig
+++ b/src/.editorconfig
@@ -184,6 +184,7 @@ dotnet_diagnostic.CA1305.severity = error
dotnet_diagnostic.CA1307.severity = none
dotnet_diagnostic.CA1308.severity = none
dotnet_diagnostic.CA1508.severity = none
+dotnet_diagnostic.CA1510.severity = none
dotnet_diagnostic.CA1725.severity = error
dotnet_diagnostic.CA1801.severity = suggestion
dotnet_diagnostic.CA1812.severity = none
diff --git a/src/Common/Dependencies.props b/src/Common/Dependencies.props
index ba44be21a3..e569218942 100644
--- a/src/Common/Dependencies.props
+++ b/src/Common/Dependencies.props
@@ -18,10 +18,6 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
- all
- runtime; build; native; contentfiles; analyzers
-
all
runtime; build; native; contentfiles; analyzers
diff --git a/src/Playwright.NUnit/Playwright.NUnit.csproj b/src/Playwright.NUnit/Playwright.NUnit.csproj
index 34131840d8..91971b038d 100644
--- a/src/Playwright.NUnit/Playwright.NUnit.csproj
+++ b/src/Playwright.NUnit/Playwright.NUnit.csproj
@@ -9,7 +9,7 @@
and fixtures to enable using it within NUnit.
icon.png
- netcoreapp3.1;net462
+ net8.0;net462
true
true
Microsoft.Playwright.NUnit
diff --git a/src/Playwright.NUnit/SkipAttribute.cs b/src/Playwright.NUnit/SkipAttribute.cs
index 728cd9ce7f..75134cd388 100644
--- a/src/Playwright.NUnit/SkipAttribute.cs
+++ b/src/Playwright.NUnit/SkipAttribute.cs
@@ -63,7 +63,7 @@ public void ApplyToTest(Test test)
{
if (_combinations.Any(combination =>
{
- var requirements = (Enum.GetValues(typeof(Targets)) as Targets[]).Where(x => combination.HasFlag(x));
+ var requirements = ((Targets[])Enum.GetValues(typeof(Targets))).Where(x => combination.HasFlag(x));
return requirements.All(flag =>
flag switch
{
diff --git a/src/Playwright.Tests/PageEvaluateTests.cs b/src/Playwright.Tests/PageEvaluateTests.cs
index 9fafc56364..b5e3c437d7 100644
--- a/src/Playwright.Tests/PageEvaluateTests.cs
+++ b/src/Playwright.Tests/PageEvaluateTests.cs
@@ -549,7 +549,7 @@ public async Task ShouldNotLeakHandles()
[PlaywrightTest("page-evaluate.spec.ts", "should evaluate exception with a function on the stack")]
public async Task ShouldEvaluateExceptionWithAFunctionOnTheStack()
{
- var exception = await Page.EvaluateAsync(@"() => {
+ var exception = await Page.EvaluateAsync(@"() => {
return (function functionOnStack() {
return new Error('error message');
})();
diff --git a/src/Playwright/Core/APIRequest.cs b/src/Playwright/Core/APIRequest.cs
index a52c4db15b..07096e5edb 100644
--- a/src/Playwright/Core/APIRequest.cs
+++ b/src/Playwright/Core/APIRequest.cs
@@ -60,7 +60,11 @@ async Task IAPIRequest.NewContextAsync(APIRequestNewContextO
throw new PlaywrightException($"The specified storage state file does not exist: {options?.StorageStatePath}");
}
+#if NET
+ storageState = await File.ReadAllTextAsync(options?.StorageStatePath).ConfigureAwait(false);
+#else
storageState = File.ReadAllText(options?.StorageStatePath);
+#endif
}
if (!string.IsNullOrEmpty(storageState))
{
diff --git a/src/Playwright/Core/APIRequestContext.cs b/src/Playwright/Core/APIRequestContext.cs
index 91737ede16..6bd4ac286e 100644
--- a/src/Playwright/Core/APIRequestContext.cs
+++ b/src/Playwright/Core/APIRequestContext.cs
@@ -220,7 +220,11 @@ await SendMessageToServerAsync("storageState").ConfigureAwait(fals
if (!string.IsNullOrEmpty(options?.Path))
{
+#if NET
+ await File.WriteAllTextAsync(options?.Path, state).ConfigureAwait(false);
+#else
File.WriteAllText(options?.Path, state);
+#endif
}
return state;
diff --git a/src/Playwright/Core/Browser.cs b/src/Playwright/Core/Browser.cs
index 783162a114..30b4c51dc9 100644
--- a/src/Playwright/Core/Browser.cs
+++ b/src/Playwright/Core/Browser.cs
@@ -150,7 +150,11 @@ public async Task NewContextAsync(BrowserNewContextOptions opti
throw new PlaywrightException($"The specified storage state file does not exist: {options.StorageStatePath}");
}
+#if NET
+ storageState = await File.ReadAllTextAsync(options.StorageStatePath).ConfigureAwait(false);
+#else
storageState = File.ReadAllText(options.StorageStatePath);
+#endif
}
if (!string.IsNullOrEmpty(storageState))
diff --git a/src/Playwright/Core/BrowserContext.cs b/src/Playwright/Core/BrowserContext.cs
index 4af6c800a7..515f016c32 100644
--- a/src/Playwright/Core/BrowserContext.cs
+++ b/src/Playwright/Core/BrowserContext.cs
@@ -544,7 +544,11 @@ await SendMessageToServerAsync("storageState").ConfigureAwait(fals
if (!string.IsNullOrEmpty(options?.Path))
{
+#if NET
+ await File.WriteAllTextAsync(options?.Path, state).ConfigureAwait(false);
+#else
File.WriteAllText(options?.Path, state);
+#endif
}
return state;
diff --git a/src/Playwright/Core/BrowserType.cs b/src/Playwright/Core/BrowserType.cs
index 46bd747fd9..9b41786781 100644
--- a/src/Playwright/Core/BrowserType.cs
+++ b/src/Playwright/Core/BrowserType.cs
@@ -181,7 +181,9 @@ void ClosePipe()
{
pipe.CloseAsync().IgnoreException();
}
+#pragma warning disable CA2000 // Dispose objects before losing scope
var connection = new Connection(_connection.LocalUtils);
+#pragma warning restore CA2000 // Dispose objects before losing scope
connection.MarkAsRemote();
connection.Close += (_, _) => ClosePipe();
diff --git a/src/Playwright/Core/ElementHandle.cs b/src/Playwright/Core/ElementHandle.cs
index 6fcf3e3128..acae5d3540 100644
--- a/src/Playwright/Core/ElementHandle.cs
+++ b/src/Playwright/Core/ElementHandle.cs
@@ -122,7 +122,11 @@ public async Task ScreenshotAsync(ElementHandleScreenshotOptions options
if (!string.IsNullOrEmpty(options.Path))
{
Directory.CreateDirectory(new FileInfo(options.Path).Directory.FullName);
+#if NET
+ await File.WriteAllBytesAsync(options.Path, result).ConfigureAwait(false);
+#else
File.WriteAllBytes(options.Path, result);
+#endif
}
return result;
@@ -204,7 +208,7 @@ public async Task SetInputFilesAsync(IEnumerable files, ElementHandleSet
{
throw new PlaywrightException("Cannot set input files to detached element.");
}
- var converted = await SetInputFilesHelpers.ConvertInputFilesAsync(files, (BrowserContext)frame.Page.Context).ConfigureAwait(false);
+ var converted = await SetInputFilesHelpers.ConvertInputFilesAsync(files.ToList(), (BrowserContext)frame.Page.Context).ConfigureAwait(false);
await SendMessageToServerAsync("setInputFiles", new Dictionary
{
["payloads"] = converted.Payloads,
@@ -221,7 +225,7 @@ public Task SetInputFilesAsync(FilePayload files, ElementHandleSetInputFilesOpti
public async Task SetInputFilesAsync(IEnumerable files, ElementHandleSetInputFilesOptions options = default)
{
- var converted = SetInputFilesHelpers.ConvertInputFiles(files);
+ var converted = SetInputFilesHelpers.ConvertInputFiles(files.ToList());
await SendMessageToServerAsync("setInputFiles", new Dictionary
{
["payloads"] = converted.Payloads,
diff --git a/src/Playwright/Core/Frame.cs b/src/Playwright/Core/Frame.cs
index dbb2d6c2b6..f68e976452 100644
--- a/src/Playwright/Core/Frame.cs
+++ b/src/Playwright/Core/Frame.cs
@@ -478,7 +478,12 @@ public async Task AddScriptTagAsync(FrameAddScriptTagOptions opt
var content = options?.Content;
if (!string.IsNullOrEmpty(options?.Path))
{
- content = ScriptsHelper.AddSourceUrlToScript(File.ReadAllText(options.Path), options.Path);
+#if NET
+ string source = await File.ReadAllTextAsync(options.Path).ConfigureAwait(false);
+#else
+ string source = File.ReadAllText(options.Path);
+#endif
+ content = ScriptsHelper.AddSourceUrlToScript(source, options.Path);
}
return await SendMessageToServerAsync("addScriptTag", new Dictionary
@@ -496,7 +501,11 @@ public async Task AddStyleTagAsync(FrameAddStyleTagOptions optio
var content = options?.Content;
if (!string.IsNullOrEmpty(options?.Path))
{
+#if NET
+ content = await File.ReadAllTextAsync(options.Path).ConfigureAwait(false);
+#else
content = File.ReadAllText(options.Path);
+#endif
content += "//# sourceURL=" + options.Path.Replace("\n", string.Empty);
}
@@ -515,7 +524,7 @@ public Task SetInputFilesAsync(string selector, string files, FrameSetInputFiles
[MethodImpl(MethodImplOptions.NoInlining)]
public async Task SetInputFilesAsync(string selector, IEnumerable files, FrameSetInputFilesOptions options = default)
{
- var converted = await SetInputFilesHelpers.ConvertInputFilesAsync(files, (BrowserContext)Page.Context).ConfigureAwait(false);
+ var converted = await SetInputFilesHelpers.ConvertInputFilesAsync(files.ToList(), (BrowserContext)Page.Context).ConfigureAwait(false);
#pragma warning disable CS0612 // Type or member is obsolete
await _setInputFilesAsync(selector, converted, options?.NoWaitAfter, options?.Timeout, options?.Strict).ConfigureAwait(false);
#pragma warning restore CS0612 // Type or member is obsolete
@@ -528,7 +537,7 @@ public Task SetInputFilesAsync(string selector, FilePayload files, FrameSetInput
[MethodImpl(MethodImplOptions.NoInlining)]
public async Task SetInputFilesAsync(string selector, IEnumerable files, FrameSetInputFilesOptions options = default)
{
- var converted = SetInputFilesHelpers.ConvertInputFiles(files);
+ var converted = SetInputFilesHelpers.ConvertInputFiles(files.ToList());
#pragma warning disable CS0612 // Type or member is obsolete
await _setInputFilesAsync(selector, converted, noWaitAfter: options?.NoWaitAfter, timeout: options?.Timeout, options?.Strict).ConfigureAwait(false);
#pragma warning restore CS0612 // Type or member is obsolete
diff --git a/src/Playwright/Core/Page.cs b/src/Playwright/Core/Page.cs
index 45f0f9dc37..cd9cf8a515 100644
--- a/src/Playwright/Core/Page.cs
+++ b/src/Playwright/Core/Page.cs
@@ -711,7 +711,11 @@ public async Task ScreenshotAsync(PageScreenshotOptions options = defaul
if (!string.IsNullOrEmpty(options.Path))
{
Directory.CreateDirectory(new FileInfo(options.Path).Directory.FullName);
+#if NET
+ await File.WriteAllBytesAsync(options.Path, result).ConfigureAwait(false);
+#else
File.WriteAllBytes(options.Path, result);
+#endif
}
return result;
@@ -916,7 +920,11 @@ public async Task PdfAsync(PagePdfOptions options = default)
if (!string.IsNullOrEmpty(options?.Path))
{
Directory.CreateDirectory(new FileInfo(options.Path).Directory.FullName);
+#if NET
+ await File.WriteAllBytesAsync(options.Path, result).ConfigureAwait(false);
+#else
File.WriteAllBytes(options.Path, result);
+#endif
}
return result;
diff --git a/src/Playwright/Core/Request.cs b/src/Playwright/Core/Request.cs
index f3b65b3fed..f94aa7b5f1 100644
--- a/src/Playwright/Core/Request.cs
+++ b/src/Playwright/Core/Request.cs
@@ -70,12 +70,11 @@ public IFrame Frame
var frame = _initializer.Frame;
if (frame.Page == null)
{
- throw new PlaywrightException(string.Join("\n", new string[]
- {
- "Frame for this navigation request is not available, because the request",
- "was issued before the frame is created. You can check whether the request",
- "is a navigation request by calling isNavigationRequest() method.",
- }));
+ throw new PlaywrightException("""
+ Frame for this navigation request is not available, because the request
+ was issued before the frame is created. You can check whether the request
+ is a navigation request by calling isNavigationRequest() method.
+ """);
}
return frame;
}
diff --git a/src/Playwright/Core/Route.cs b/src/Playwright/Core/Route.cs
index 0ac2ef1561..2113f5404c 100644
--- a/src/Playwright/Core/Route.cs
+++ b/src/Playwright/Core/Route.cs
@@ -192,7 +192,11 @@ private async Task> NormalizeFulfillParametersAsync(
if (!string.IsNullOrEmpty(path))
{
+#if NET
+ byte[] content = await File.ReadAllBytesAsync(path).ConfigureAwait(false);
+#else
byte[] content = File.ReadAllBytes(path);
+#endif
resultBody = Convert.ToBase64String(content);
isBase64 = true;
length = resultBody.Length;
diff --git a/src/Playwright/Core/Waiter.cs b/src/Playwright/Core/Waiter.cs
index e46ad8d32e..bc55bd96ea 100644
--- a/src/Playwright/Core/Waiter.cs
+++ b/src/Playwright/Core/Waiter.cs
@@ -150,10 +150,16 @@ internal void RejectOnTimeout(int? timeout, string message)
return;
}
+#pragma warning disable CA2000 // Dispose objects before losing scope
var cts = new CancellationTokenSource();
+#pragma warning restore CA2000 // Dispose objects before losing scope
RejectOn(
new TaskCompletionSource().Task.WithTimeout(timeout.Value, _ => new TimeoutException(message), cts.Token),
- () => cts.Cancel());
+ () =>
+ {
+ cts.Cancel();
+ cts.Dispose();
+ });
}
internal Task WaitForEventAsync(object eventSource, string e, Func predicate)
@@ -250,7 +256,11 @@ private static async Task WrapActionAsync(Func action, CancellationTokenSo
}
catch
{
+#if NET
+ await cts.CancelAsync().ConfigureAwait(false);
+#else
cts.Cancel();
+#endif
throw;
}
}
diff --git a/src/Playwright/Helpers/Driver.cs b/src/Playwright/Helpers/Driver.cs
index 3ac3bad489..1270736c03 100644
--- a/src/Playwright/Helpers/Driver.cs
+++ b/src/Playwright/Helpers/Driver.cs
@@ -100,9 +100,14 @@ private static bool TryGetCodeBase(Assembly assembly, out Uri codeBase)
{
try
{
- // assembly.CodeBase might throw with:
- // System.NotSupportedException: CodeBase is not supported on assemblies loaded from a single-file bundle.
+ // assembly.Location/CodeBase might throw with:
+ // System.NotSupportedException: Location/CodeBase is not supported on assemblies loaded from a single-file bundle.
+ // Still using CodeBase for legacy .NET because of behaviour difference with shadow-copy (see https://learn.microsoft.com/en-us/dotnet/api/system.reflection.assembly.location?view=net-8.0#remarks)
+#if NET
+ Uri.TryCreate(assembly.Location, UriKind.Absolute, out codeBase);
+#else
Uri.TryCreate(assembly.CodeBase, UriKind.Absolute, out codeBase);
+#endif
return true;
}
catch (NotSupportedException)
diff --git a/src/Playwright/Helpers/SetInputFilesHelpers.cs b/src/Playwright/Helpers/SetInputFilesHelpers.cs
index a077784ecc..72c92bb890 100644
--- a/src/Playwright/Helpers/SetInputFilesHelpers.cs
+++ b/src/Playwright/Helpers/SetInputFilesHelpers.cs
@@ -65,7 +65,7 @@ private static (string[] LocalPaths, string LocalDirectory) ResolvePathsAndDirec
return (localPaths?.ToArray(), localDirectory);
}
- private static IEnumerable GetFilesRecursive(string directory)
+ private static List GetFilesRecursive(string directory)
{
var files = new List();
files.AddRange(Directory.GetFiles(directory));
@@ -76,16 +76,16 @@ private static IEnumerable GetFilesRecursive(string directory)
return files;
}
- public static async Task ConvertInputFilesAsync(IEnumerable files, BrowserContext context)
+ public static async Task ConvertInputFilesAsync(List files, BrowserContext context)
{
- if (!files.Any())
+ if (files.Count == 0)
{
return new() { Payloads = [] };
}
- var (localPaths, localDirectory) = ResolvePathsAndDirectoryForInputFiles(files.ToList());
+ var (localPaths, localDirectory) = ResolvePathsAndDirectoryForInputFiles(files);
if (context._connection.IsRemote)
{
- files = localDirectory != null ? GetFilesRecursive(localDirectory) : localPaths;
+ files = localDirectory != null ? GetFilesRecursive(localDirectory) : localPaths.ToList();
var result = await context.SendMessageToServerAsync("createTempFiles", new Dictionary
{
["rootDirName"] = localDirectory != null ? new DirectoryInfo(localDirectory).Name : null,
@@ -97,12 +97,12 @@ public static async Task ConvertInputFilesAsync(IEnumerable<
}).ToArray(),
}).ConfigureAwait(false);
var writableStreams = result.Value.GetProperty("writableStreams").EnumerateArray();
- if (writableStreams.Count() != files.Count())
+ if (writableStreams.Count() != files.Count)
{
- throw new Exception("Mismatch between the number of files and the number of writeable streams");
+ throw new PlaywrightException("Mismatch between the number of files and the number of writeable streams");
}
var streams = new List();
- for (var i = 0; i < files.Count(); i++)
+ for (var i = 0; i < files.Count; i++)
{
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
await using (var writeableStream = context._connection.GetObject(writableStreams.ElementAt(i).GetProperty("guid").ToString()) as WritableStream)
@@ -122,7 +122,7 @@ public static async Task ConvertInputFilesAsync(IEnumerable<
return new() { LocalPaths = localPaths, LocalDirectory = localDirectory };
}
- public static SetInputFilesFiles ConvertInputFiles(IEnumerable files)
+ public static SetInputFilesFiles ConvertInputFiles(List files)
{
var filePayloadExceedsSizeLimit = files.Sum(f => f.Buffer.Length) > SizeLimitInBytes;
if (filePayloadExceedsSizeLimit)
diff --git a/src/Playwright/Helpers/StringExtensions.cs b/src/Playwright/Helpers/StringExtensions.cs
index 47dc084ccb..87dccd2ae2 100644
--- a/src/Playwright/Helpers/StringExtensions.cs
+++ b/src/Playwright/Helpers/StringExtensions.cs
@@ -615,7 +615,11 @@ public static Dictionary ParseQueryString(this string query)
var result = new Dictionary();
+#if NET
+ if (query.StartsWith('?'))
+#else
if (query.StartsWith("?", StringComparison.InvariantCultureIgnoreCase))
+#endif
{
query = query.Substring(1, query.Length - 1);
}
diff --git a/src/Playwright/Helpers/URLMatch.cs b/src/Playwright/Helpers/URLMatch.cs
index ff5c60922e..62b3df9517 100644
--- a/src/Playwright/Helpers/URLMatch.cs
+++ b/src/Playwright/Helpers/URLMatch.cs
@@ -65,7 +65,11 @@ public bool Match(string url)
internal static string JoinWithBaseURL(string baseUrl, string url)
{
if (string.IsNullOrEmpty(baseUrl)
+#if NET
+ || (url?.StartsWith('*') ?? false)
+#else
|| (url?.StartsWith("*", StringComparison.InvariantCultureIgnoreCase) ?? false)
+#endif
|| !Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
{
return url;
diff --git a/src/Playwright/Playwright.cs b/src/Playwright/Playwright.cs
index b1c493a39d..e9f5ecf451 100644
--- a/src/Playwright/Playwright.cs
+++ b/src/Playwright/Playwright.cs
@@ -40,8 +40,10 @@ public static class Playwright
/// A that completes when the playwright driver is ready to be used.
public static async Task CreateAsync()
{
+#pragma warning disable CA2000 // Dispose objects before losing scope
var transport = new StdIOTransport();
var connection = new Connection();
+#pragma warning restore CA2000 // Dispose objects before losing scope
transport.MessageReceived += (_, message) =>
{
Connection.TraceMessage("pw:channel:recv", message);
diff --git a/src/Playwright/Playwright.csproj b/src/Playwright/Playwright.csproj
index 9ae89e6229..95255bccd1 100644
--- a/src/Playwright/Playwright.csproj
+++ b/src/Playwright/Playwright.csproj
@@ -7,7 +7,7 @@
The .NET port of Playwright, used to automate Chromium, Firefox and WebKit with a single API.
Playwright enables reliable end-to-end testing for modern web apps. It is built to enable cross-browser web automation that is ever-green, capable, reliable and fast. Learn more at https://playwright.dev/dotnet/.
icon.png
- netstandard2.0
+ netstandard2.0;net8.0
true
Microsoft.Playwright.xml
true
@@ -25,15 +25,17 @@
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
diff --git a/src/Playwright/Transport/Connection.cs b/src/Playwright/Transport/Connection.cs
index 23d837217b..41b9eb59ab 100644
--- a/src/Playwright/Transport/Connection.cs
+++ b/src/Playwright/Transport/Connection.cs
@@ -314,105 +314,78 @@ internal void Dispatch(PlaywrightServerMessage message)
private ChannelOwner CreateRemoteObject(string parentGuid, ChannelOwnerType type, string guid, JsonElement? initializer)
{
- ChannelOwner result = null;
var parent = string.IsNullOrEmpty(parentGuid) ? _rootObject : Objects[parentGuid];
switch (type)
{
case ChannelOwnerType.APIRequestContext:
- result = new APIRequestContext(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new APIRequestContext(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.Artifact:
- result = new Artifact(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new Artifact(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.BindingCall:
- result = new BindingCall(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new BindingCall(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.Playwright:
- result = new PlaywrightImpl(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new PlaywrightImpl(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.Browser:
var browserInitializer = initializer?.ToObject(DefaultJsonSerializerOptions);
- result = new Browser(parent, guid, browserInitializer);
- break;
+ return new Browser(parent, guid, browserInitializer);
case ChannelOwnerType.BrowserType:
var browserTypeInitializer = initializer?.ToObject(DefaultJsonSerializerOptions);
- result = new Core.BrowserType(parent, guid, browserTypeInitializer);
- break;
+ return new Core.BrowserType(parent, guid, browserTypeInitializer);
case ChannelOwnerType.BrowserContext:
var browserContextInitializer = initializer?.ToObject(DefaultJsonSerializerOptions);
- result = new BrowserContext(parent, guid, browserContextInitializer);
- break;
+ return new BrowserContext(parent, guid, browserContextInitializer);
case ChannelOwnerType.CDPSession:
- result = new CDPSession(parent, guid);
- break;
+ return new CDPSession(parent, guid);
case ChannelOwnerType.Dialog:
- result = new Dialog(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new Dialog(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.ElementHandle:
- result = new ElementHandle(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new ElementHandle(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.Frame:
- result = new Frame(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new Frame(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.JSHandle:
- result = new JSHandle(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new JSHandle(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.JsonPipe:
- result = new JsonPipe(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new JsonPipe(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.LocalUtils:
- result = new LocalUtils(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
+ var localUtils = new LocalUtils(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
if (LocalUtils == null)
{
- LocalUtils = result as LocalUtils;
+ LocalUtils = localUtils;
}
- break;
+ return localUtils;
case ChannelOwnerType.Page:
- result = new Page(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new Page(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.Request:
- result = new Request(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new Request(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.Response:
- result = new Response(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new Response(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.Route:
- result = new Route(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new Route(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.Worker:
- result = new Worker(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new Worker(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.WebSocket:
- result = new WebSocket(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new WebSocket(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.WebSocketRoute:
- result = new WebSocketRoute(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
- break;
+ return new WebSocketRoute(parent, guid, initializer?.ToObject(DefaultJsonSerializerOptions));
case ChannelOwnerType.Selectors:
- result = new Selectors(parent, guid);
- break;
+ return new Selectors(parent, guid);
case ChannelOwnerType.SocksSupport:
- result = new SocksSupport(parent, guid);
- break;
+ return new SocksSupport(parent, guid);
case ChannelOwnerType.Stream:
- result = new Stream(parent, guid);
- break;
+ return new Stream(parent, guid);
case ChannelOwnerType.WritableStream:
- result = new WritableStream(parent, guid);
- break;
+ return new WritableStream(parent, guid);
case ChannelOwnerType.Tracing:
- result = new Tracing(parent, guid);
- break;
+ return new Tracing(parent, guid);
case ChannelOwnerType.Electron:
case ChannelOwnerType.Android:
- result = null;
break;
default:
Debug.Fail($"Missing Playwright type binding for '{type}'");
break;
}
- return result;
+ return null;
}
internal void DoClose(Exception cause = null)
@@ -507,7 +480,11 @@ internal async Task WrapApiCallAsync(Func> action, bool isInternal
{
apiBoundaryReached = true;
}
+#if NET
+ var hasCleanMethodName = !methodName.StartsWith('<');
+#else
var hasCleanMethodName = !methodName.StartsWith("<", StringComparison.InvariantCultureIgnoreCase);
+#endif
if (hasCleanMethodName)
{
lastInternalApiName = methodName;
diff --git a/src/Playwright/Transport/Converters/EvaluateArgumentValueConverter.cs b/src/Playwright/Transport/Converters/EvaluateArgumentValueConverter.cs
index aed915e39a..e375acba0c 100644
--- a/src/Playwright/Transport/Converters/EvaluateArgumentValueConverter.cs
+++ b/src/Playwright/Transport/Converters/EvaluateArgumentValueConverter.cs
@@ -30,7 +30,6 @@
using System.Globalization;
using System.Linq;
using System.Numerics;
-using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.RegularExpressions;
using Microsoft.Playwright.Core;
@@ -345,7 +344,7 @@ private static object ParseEvaluateResultToExpando(JsonElement result, IDictiona
if (result.TryGetProperty("e", out var error))
{
- return new Exception(error.GetProperty("s").ToString());
+ return new PlaywrightException(error.GetProperty("s").ToString());
}
if (result.TryGetProperty("r", out var regex))
@@ -399,16 +398,25 @@ internal class VisitorInfo
internal VisitorInfo()
{
Visited = new Dictionary();
- IDGenerator = new ObjectIDGenerator();
+ ObjectToId = new Dictionary