From f8f6f055c3f3da98d4920f4935c9cbca11158053 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Sat, 9 Dec 2023 09:54:45 -0800 Subject: [PATCH 1/4] chore: move channels into impl classes --- src/Playwright/Core/BindingCall.cs | 20 ++++++-- src/Playwright/Core/CDPSession.cs | 14 ++++-- src/Playwright/Core/Dialog.cs | 10 +++- src/Playwright/Core/JsonPipe.cs | 8 +++- src/Playwright/Core/Request.cs | 8 ++-- src/Playwright/Core/Response.cs | 12 +++-- src/Playwright/Core/Route.cs | 30 ++++++++++-- src/Playwright/Core/Selectors.cs | 33 +++++++++---- src/Playwright/Core/Stream.cs | 14 +++++- src/Playwright/Core/Worker.cs | 25 ++++++---- src/Playwright/Core/WritableStream.cs | 10 +++- src/Playwright/Transport/ChannelOwnerBase.cs | 11 +++++ .../Transport/Channels/BindingCallChannel.cs | 23 --------- .../Transport/Channels/CDPChannel.cs | 24 ---------- .../Transport/Channels/DialogChannel.cs | 13 ----- .../Transport/Channels/JsonPipeChannel.cs | 10 ---- .../Transport/Channels/RequestChannel.cs | 9 ---- .../Transport/Channels/ResponseChannel.cs | 21 -------- src/Playwright/Transport/Channels/Root.cs | 16 ------- .../Transport/Channels/RouteChannel.cs | 48 ------------------- .../Transport/Channels/SelectorsChannel.cs | 30 ------------ .../Transport/Channels/StreamChannel.cs | 16 ------- .../Transport/Channels/WorkerChannel.cs | 34 ------------- .../Channels/WritableStreamChannel.cs | 15 ------ src/Playwright/Transport/Connection.cs | 14 ++++-- 25 files changed, 161 insertions(+), 307 deletions(-) diff --git a/src/Playwright/Core/BindingCall.cs b/src/Playwright/Core/BindingCall.cs index 02d0a6c82f..7da41e4000 100644 --- a/src/Playwright/Core/BindingCall.cs +++ b/src/Playwright/Core/BindingCall.cs @@ -27,6 +27,7 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; +using Microsoft.Playwright.Helpers; using Microsoft.Playwright.Transport; using Microsoft.Playwright.Transport.Channels; using Microsoft.Playwright.Transport.Protocol; @@ -96,15 +97,28 @@ internal async Task CallAsync(Delegate binding) } } - await _channel.ResolveAsync(ScriptsHelper.SerializedArgument(result)).ConfigureAwait(false); + await SendMessageToServerAsync("resolve", new Dictionary + { + ["result"] = ScriptsHelper.SerializedArgument(result), + }).ConfigureAwait(false); } catch (TargetInvocationException ex) { - await _channel.RejectAsync(ex.InnerException).ConfigureAwait(false); + await SendMessageToServerAsync( + "reject", + new Dictionary + { + ["error"] = ex.InnerException.ToObject(), + }).ConfigureAwait(false); } catch (Exception ex) { - await _channel.RejectAsync(ex).ConfigureAwait(false); + await SendMessageToServerAsync( + "reject", + new Dictionary + { + ["error"] = ex.ToObject(), + }).ConfigureAwait(false); } } } diff --git a/src/Playwright/Core/CDPSession.cs b/src/Playwright/Core/CDPSession.cs index aca4da9c14..5e73b08883 100644 --- a/src/Playwright/Core/CDPSession.cs +++ b/src/Playwright/Core/CDPSession.cs @@ -58,11 +58,19 @@ internal override void OnMessage(string method, JsonElement? serverParams) } [MethodImpl(MethodImplOptions.NoInlining)] - public Task DetachAsync() => _channel.DetachAsync(); + public Task DetachAsync() => SendMessageToServerAsync("detach"); [MethodImpl(MethodImplOptions.NoInlining)] - public Task SendAsync(string method, Dictionary? args = null) - => _channel.SendAsync(method, args); + public async Task SendAsync(string method, Dictionary? args = null) + { + var newArgs = new Dictionary() { { "method", method } }; + if (args != null) + { + newArgs["params"] = args; + } + var result = await SendMessageToServerAsync("send", newArgs).ConfigureAwait(false); + return result?.GetProperty("result"); + } private void OnCDPEvent(string name, JsonElement? @params) { diff --git a/src/Playwright/Core/Dialog.cs b/src/Playwright/Core/Dialog.cs index 5ceec2af2c..9e15123ae8 100644 --- a/src/Playwright/Core/Dialog.cs +++ b/src/Playwright/Core/Dialog.cs @@ -22,6 +22,7 @@ * SOFTWARE. */ +using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading.Tasks; using Microsoft.Playwright.Transport; @@ -56,8 +57,13 @@ public Dialog(IChannelOwner parent, string guid, DialogInitializer initializer) IChannel IChannelOwner.Channel => _channel; [MethodImpl(MethodImplOptions.NoInlining)] - public Task AcceptAsync(string promptText) => _channel.AcceptAsync(promptText ?? string.Empty); + public Task AcceptAsync(string promptText) => SendMessageToServerAsync( + "accept", + new Dictionary + { + ["promptText"] = promptText ?? string.Empty, + }); [MethodImpl(MethodImplOptions.NoInlining)] - public Task DismissAsync() => _channel.DismissAsync(); + public Task DismissAsync() => SendMessageToServerAsync("dismiss"); } diff --git a/src/Playwright/Core/JsonPipe.cs b/src/Playwright/Core/JsonPipe.cs index 2803634472..0ae32d71e9 100644 --- a/src/Playwright/Core/JsonPipe.cs +++ b/src/Playwright/Core/JsonPipe.cs @@ -23,6 +23,7 @@ */ using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text.Json; using System.Threading.Tasks; @@ -73,8 +74,11 @@ internal override void OnMessage(string method, JsonElement? serverParams) } [MethodImpl(MethodImplOptions.NoInlining)] - public Task CloseAsync() => _channel.CloseAsync(); + public Task CloseAsync() => SendMessageToServerAsync("close"); [MethodImpl(MethodImplOptions.NoInlining)] - public Task SendAsync(object message) => _channel.SendAsync(message); + public Task SendAsync(object message) => SendMessageToServerAsync("send", new Dictionary + { + { "message", message }, + }); } diff --git a/src/Playwright/Core/Request.cs b/src/Playwright/Core/Request.cs index 6a5d26bb37..4aa522f049 100644 --- a/src/Playwright/Core/Request.cs +++ b/src/Playwright/Core/Request.cs @@ -29,6 +29,7 @@ using System.Text.Json; using System.Threading.Tasks; using System.Web; +using Microsoft.Playwright.Helpers; using Microsoft.Playwright.Transport; using Microsoft.Playwright.Transport.Channels; using Microsoft.Playwright.Transport.Protocol; @@ -143,7 +144,7 @@ public byte[] PostDataBuffer internal BrowserContext _context => (BrowserContext)Frame.Page.Context; [MethodImpl(MethodImplOptions.NoInlining)] - public async Task ResponseAsync() => (await _channel.GetResponseAsync().ConfigureAwait(false))?.Object; + public async Task ResponseAsync() => (await SendMessageToServerAsync("response").ConfigureAwait(false))?.Object; [MethodImpl(MethodImplOptions.NoInlining)] public JsonElement? PostDataJSON() @@ -184,7 +185,7 @@ public async Task SizesAsync() throw new PlaywrightException("Unable to fetch resources sizes."); } - return await ((ResponseChannel)res.Channel).SizesAsync().ConfigureAwait(false); + return (await ((Response)res).SendMessageToServerAsync("sizes").ConfigureAwait(false))?.GetProperty("sizes").ToObject(); } [MethodImpl(MethodImplOptions.NoInlining)] @@ -215,7 +216,8 @@ private Task ActualHeadersAsync() private async Task GetRawHeadersTaskAsync() { - return new(await _channel.GetRawRequestHeadersAsync().ConfigureAwait(false)); + var headerList = (await SendMessageToServerAsync("rawRequestHeaders").ConfigureAwait(false))?.GetProperty("headers").ToObject>(); + return new(headerList); } internal void ApplyFallbackOverrides(RouteFallbackOptions overrides) diff --git a/src/Playwright/Core/Response.cs b/src/Playwright/Core/Response.cs index 63b23e80f2..3ffa75e499 100644 --- a/src/Playwright/Core/Response.cs +++ b/src/Playwright/Core/Response.cs @@ -28,6 +28,7 @@ using System.Text; using System.Text.Json; using System.Threading.Tasks; +using Microsoft.Playwright.Helpers; using Microsoft.Playwright.Transport; using Microsoft.Playwright.Transport.Channels; using Microsoft.Playwright.Transport.Protocol; @@ -77,7 +78,7 @@ public async Task> AllHeadersAsync() => (await GetRawHeadersAsync().ConfigureAwait(false)).Headers; [MethodImpl(MethodImplOptions.NoInlining)] - public Task BodyAsync() => _channel.GetBodyAsync(); + public async Task BodyAsync() => (await SendMessageToServerAsync("body").ConfigureAwait(false))?.GetProperty("binary").GetBytesFromBase64(); [MethodImpl(MethodImplOptions.NoInlining)] public async Task FinishedAsync() @@ -114,10 +115,12 @@ public async Task JsonAsync() => JsonSerializer.Deserialize(await BodyAsync().ConfigureAwait(false)); [MethodImpl(MethodImplOptions.NoInlining)] - public Task SecurityDetailsAsync() => _channel.SecurityDetailsAsync(); + public async Task SecurityDetailsAsync() => (await SendMessageToServerAsync("securityDetails").ConfigureAwait(false)) + ?.GetProperty("value").ToObject(_connection.DefaultJsonSerializerOptions); [MethodImpl(MethodImplOptions.NoInlining)] - public Task ServerAddrAsync() => _channel.ServerAddrAsync(); + public async Task ServerAddrAsync() => (await SendMessageToServerAsync("serverAddr").ConfigureAwait(false)) + ?.GetProperty("value").ToObject(_connection.DefaultJsonSerializerOptions); [MethodImpl(MethodImplOptions.NoInlining)] public async Task TextAsync() @@ -143,7 +146,6 @@ private Task GetRawHeadersAsync() private async Task GetRawHeadersTaskAsync() { - var headers = await _channel.GetRawHeadersAsync().ConfigureAwait(false); - return new(headers); + return new((await SendMessageToServerAsync("rawResponseHeaders").ConfigureAwait(false))?.GetProperty("headers").ToObject>()); } } diff --git a/src/Playwright/Core/Route.cs b/src/Playwright/Core/Route.cs index 96bdc1ae83..4811bbf029 100644 --- a/src/Playwright/Core/Route.cs +++ b/src/Playwright/Core/Route.cs @@ -77,7 +77,7 @@ public async Task FulfillAsync(RouteFulfillOptions options = default) options.Path, options.Response).ConfigureAwait(false); normalized["requestUrl"] = _request._initializer.Url; - await RaceWithTargetCloseAsync(_channel.FulfillAsync(normalized)).ConfigureAwait(false); + await RaceWithTargetCloseAsync(SendMessageToServerAsync("fulfill", normalized)).ConfigureAwait(false); ReportHandled(true); } @@ -85,7 +85,13 @@ public async Task FulfillAsync(RouteFulfillOptions options = default) public async Task AbortAsync(string errorCode = RequestAbortErrorCode.Failed) { CheckNotHandled(); - await RaceWithTargetCloseAsync(_channel.AbortAsync(_request._initializer.Url, errorCode)).ConfigureAwait(false); + await RaceWithTargetCloseAsync(SendMessageToServerAsync( + "abort", + new Dictionary + { + ["requestUrl"] = _request._initializer.Url, + ["errorCode"] = string.IsNullOrEmpty(errorCode) ? RequestAbortErrorCode.Failed : errorCode, + })).ConfigureAwait(false); ReportHandled(true); } @@ -102,7 +108,18 @@ internal async Task InnerContinueAsync(bool @internal = false) { var options = _request.FallbackOverridesForContinue(); await _channel.Connection.WrapApiCallAsync( - () => RaceWithTargetCloseAsync(_channel.ContinueAsync(requestUrl: _request._initializer.Url, url: options.Url, method: options.Method, postData: options.PostData, headers: options.Headers, isFallback: @internal)), + () => RaceWithTargetCloseAsync( + SendMessageToServerAsync( + "continue", + new Dictionary + { + ["requestUrl"] = _request._initializer.Url, + ["url"] = options.Url, + ["method"] = options.Method, + ["postData"] = options.PostData != null ? Convert.ToBase64String(options.PostData) : null, + ["headers"] = options.Headers?.Select(kv => new HeaderEntry { Name = kv.Key, Value = kv.Value }).ToArray(), + ["isFallback"] = @internal, + })), @internal).ConfigureAwait(false); } @@ -235,7 +252,12 @@ public Task FallbackAsync(RouteFallbackOptions options = null) internal async Task RedirectNavigationRequestAsync(string url) { CheckNotHandled(); - await RaceWithTargetCloseAsync(_channel.RedirectNavigationRequestAsync(url)).ConfigureAwait(false); + await RaceWithTargetCloseAsync(SendMessageToServerAsync( + "redirectNavigationRequest", + new Dictionary + { + ["url"] = url, + })).ConfigureAwait(false); ReportHandled(true); } diff --git a/src/Playwright/Core/Selectors.cs b/src/Playwright/Core/Selectors.cs index 6161e8b3c6..35d690feb2 100644 --- a/src/Playwright/Core/Selectors.cs +++ b/src/Playwright/Core/Selectors.cs @@ -47,21 +47,21 @@ internal Selectors(IChannelOwner parent, string guid) : base(parent, guid) internal class SelectorsAPI : ISelectors { private readonly HashSet _channels = new(); - private readonly List _registrations = new(); + private readonly List> _registrations = new(); public async Task RegisterAsync(string name, SelectorsRegisterOptions options = default) { options ??= new SelectorsRegisterOptions(); var source = ScriptsHelper.EvaluationScript(options.Script, options.Path); - SelectorsRegisterParams @params = new() + var @params = new Dictionary() { - Name = name, - Source = source, - ContentScript = options?.ContentScript, + ["name"] = name, + ["source"] = source, + ["contentScript"] = options.ContentScript, }; foreach (var channel in _channels) { - await channel._channel.RegisterAsync(@params).ConfigureAwait(false); + await channel.SendMessageToServerAsync("register", @params).ConfigureAwait(false); } _registrations.Add(@params); } @@ -71,7 +71,12 @@ public void SetTestIdAttribute(string attributeName) Locator.SetTestIdAttribute(attributeName); foreach (var channel in _channels) { - channel._channel.SetTestIdAttributeAsync(attributeName).IgnoreException(); + channel.SendMessageToServerAsync( + "setTestIdAttributeName", + new Dictionary + { + ["testIdAttributeName"] = attributeName, + }).IgnoreException(); } } @@ -81,8 +86,11 @@ internal void AddChannel(Selectors channel) foreach (var @params in _registrations) { // This should not fail except for connection closure, but just in case we catch. - channel._channel.RegisterAsync(@params).IgnoreException(); - channel._channel.SetTestIdAttributeAsync(Locator.TestIdAttributeName()).IgnoreException(); + channel.SendMessageToServerAsync("register", @params).IgnoreException(); + channel.SendMessageToServerAsync("setTestIdAttributeName", new Dictionary + { + ["testIdAttributeName"] = Locator.TestIdAttributeName(), + }).IgnoreException(); } } @@ -91,3 +99,10 @@ internal void RemoveChannel(Selectors channel) _channels.Remove(channel); } } + +internal record SelectorsRegisterParams +{ + internal string Name; + internal string Source; + internal bool? ContentScript; +} diff --git a/src/Playwright/Core/Stream.cs b/src/Playwright/Core/Stream.cs index df1d773075..72daf84a08 100644 --- a/src/Playwright/Core/Stream.cs +++ b/src/Playwright/Core/Stream.cs @@ -23,6 +23,7 @@ */ using System; +using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using System.Threading; @@ -48,13 +49,22 @@ internal Stream(IChannelOwner parent, string guid) : base(parent, guid) public StreamImpl StreamImpl => new(this); [MethodImpl(MethodImplOptions.NoInlining)] - public Task ReadAsync(int size) => Channel.ReadAsync(size); + public async Task ReadAsync(int size) + { + var response = await SendMessageToServerAsync( + "read", + new Dictionary + { + ["size"] = size, + }).ConfigureAwait(false); + return response.Value.GetProperty("binary").GetBytesFromBase64(); + } [MethodImpl(MethodImplOptions.NoInlining)] public ValueTask DisposeAsync() => new ValueTask(CloseAsync()); [MethodImpl(MethodImplOptions.NoInlining)] - public Task CloseAsync() => Channel.CloseAsync(); + public Task CloseAsync() => SendMessageToServerAsync("close"); } internal class StreamImpl : System.IO.Stream diff --git a/src/Playwright/Core/Worker.cs b/src/Playwright/Core/Worker.cs index b7f459bf91..70ba0c00e1 100644 --- a/src/Playwright/Core/Worker.cs +++ b/src/Playwright/Core/Worker.cs @@ -23,6 +23,7 @@ */ using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text.Json; using System.Threading.Tasks; @@ -86,18 +87,24 @@ internal void OnClose() [MethodImpl(MethodImplOptions.NoInlining)] public async Task EvaluateAsync(string expression, object arg = null) - => ScriptsHelper.ParseEvaluateResult(await _channel.EvaluateExpressionAsync( - expression, - null, - ScriptsHelper.SerializedArgument(arg)).ConfigureAwait(false)); + => ScriptsHelper.ParseEvaluateResult((await SendMessageToServerAsync( + "evaluateExpression", + new Dictionary + { + ["expression"] = expression, + ["arg"] = ScriptsHelper.SerializedArgument(arg), + }).ConfigureAwait(false)).Value.GetProperty("value")); [MethodImpl(MethodImplOptions.NoInlining)] public async Task EvaluateHandleAsync(string expression, object arg = null) - => await _channel.EvaluateExpressionHandleAsync( - expression, - null, - ScriptsHelper.SerializedArgument(arg)) - .ConfigureAwait(false); + => (await SendMessageToServerAsync( + "evaluateExpressionHandle", + new Dictionary + { + ["expression"] = expression, + ["arg"] = ScriptsHelper.SerializedArgument(arg), + }) + .ConfigureAwait(false)).GetObject("handle", _connection); [MethodImpl(MethodImplOptions.NoInlining)] public async Task WaitForCloseAsync(Func action = default, float? timeout = default) diff --git a/src/Playwright/Core/WritableStream.cs b/src/Playwright/Core/WritableStream.cs index caa6059eba..7498eb0a99 100644 --- a/src/Playwright/Core/WritableStream.cs +++ b/src/Playwright/Core/WritableStream.cs @@ -23,6 +23,7 @@ */ using System; +using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using System.Threading; @@ -48,13 +49,18 @@ internal WritableStream(IChannelOwner parent, string guid) : base(parent, guid) public WritableStreamImpl WritableStreamImpl => new(this); [MethodImpl(MethodImplOptions.NoInlining)] - public Task WriteAsync(string binary) => Channel.WriteAsync(binary); + public Task WriteAsync(string binary) => SendMessageToServerAsync( + "write", + new Dictionary + { + ["binary"] = binary, + }); [MethodImpl(MethodImplOptions.NoInlining)] public ValueTask DisposeAsync() => new ValueTask(CloseAsync()); [MethodImpl(MethodImplOptions.NoInlining)] - public Task CloseAsync() => Channel.CloseAsync(); + public Task CloseAsync() => SendMessageToServerAsync("close"); } internal class WritableStreamImpl : System.IO.Stream diff --git a/src/Playwright/Transport/ChannelOwnerBase.cs b/src/Playwright/Transport/ChannelOwnerBase.cs index 13720b058d..028da4d9fe 100644 --- a/src/Playwright/Transport/ChannelOwnerBase.cs +++ b/src/Playwright/Transport/ChannelOwnerBase.cs @@ -136,4 +136,15 @@ private void UpdateEventSubscription(string eventName, bool enabled) }), true).IgnoreException(); } + + internal Task SendMessageToServerAsync( + string method, + Dictionary args = null, + bool keepNulls = false) + => SendMessageToServerAsync(method, args, keepNulls); + + internal Task SendMessageToServerAsync( + string method, + Dictionary args = null, + bool keepNulls = false) => _connection.SendMessageToServerAsync(this, method, args, keepNulls); } diff --git a/src/Playwright/Transport/Channels/BindingCallChannel.cs b/src/Playwright/Transport/Channels/BindingCallChannel.cs index 7bd56ed35c..3824dad8c8 100644 --- a/src/Playwright/Transport/Channels/BindingCallChannel.cs +++ b/src/Playwright/Transport/Channels/BindingCallChannel.cs @@ -22,12 +22,7 @@ * SOFTWARE. */ -using System; -using System.Collections.Generic; -using System.Text.Json; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Helpers; namespace Microsoft.Playwright.Transport.Channels; @@ -36,22 +31,4 @@ internal class BindingCallChannel : Channel public BindingCallChannel(string guid, Connection connection, BindingCall owner) : base(guid, connection, owner) { } - - internal Task RejectAsync(Exception error) - => Connection.SendMessageToServerAsync( - Object, - "reject", - new Dictionary - { - ["error"] = error.ToObject(), - }); - - internal Task ResolveAsync(object result) - => Connection.SendMessageToServerAsync( - Object, - "resolve", - new Dictionary - { - ["result"] = result, - }); } diff --git a/src/Playwright/Transport/Channels/CDPChannel.cs b/src/Playwright/Transport/Channels/CDPChannel.cs index 549a19a1e9..5ef3f51a15 100644 --- a/src/Playwright/Transport/Channels/CDPChannel.cs +++ b/src/Playwright/Transport/Channels/CDPChannel.cs @@ -21,9 +21,6 @@ * 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; -using System.Threading.Tasks; using Microsoft.Playwright.Core; #nullable enable @@ -35,26 +32,5 @@ internal class CDPChannel : Channel public CDPChannel(string guid, Connection connection, CDPSession owner) : base(guid, connection, owner) { } - - internal Task DetachAsync() - { - return Connection.SendMessageToServerAsync( - Object, - "detach"); - } - - internal async Task SendAsync(string method, Dictionary? args = null) - { - var newArgs = new Dictionary() { { "method", method } }; - if (args != null) - { - newArgs["params"] = args; - } - var result = await Connection.SendMessageToServerAsync( - Object, - "send", - newArgs).ConfigureAwait(false); - return result?.GetProperty("result"); - } } #nullable disable diff --git a/src/Playwright/Transport/Channels/DialogChannel.cs b/src/Playwright/Transport/Channels/DialogChannel.cs index d457f5aaac..4f6f8325fe 100644 --- a/src/Playwright/Transport/Channels/DialogChannel.cs +++ b/src/Playwright/Transport/Channels/DialogChannel.cs @@ -22,8 +22,6 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.Threading.Tasks; using Microsoft.Playwright.Core; namespace Microsoft.Playwright.Transport.Channels; @@ -33,15 +31,4 @@ internal class DialogChannel : Channel public DialogChannel(string guid, Connection connection, Dialog owner) : base(guid, connection, owner) { } - - internal Task AcceptAsync(string promptText) - => Connection.SendMessageToServerAsync( - Object, - "accept", - new Dictionary - { - ["promptText"] = promptText, - }); - - internal Task DismissAsync() => Connection.SendMessageToServerAsync(Object, "dismiss"); } diff --git a/src/Playwright/Transport/Channels/JsonPipeChannel.cs b/src/Playwright/Transport/Channels/JsonPipeChannel.cs index b0c6a1e1bc..9750551390 100644 --- a/src/Playwright/Transport/Channels/JsonPipeChannel.cs +++ b/src/Playwright/Transport/Channels/JsonPipeChannel.cs @@ -22,8 +22,6 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.Threading.Tasks; using Microsoft.Playwright.Core; namespace Microsoft.Playwright.Transport.Channels; @@ -33,12 +31,4 @@ internal class JsonPipeChannel : Channel public JsonPipeChannel(string guid, Connection connection, JsonPipe owner) : base(guid, connection, owner) { } - - internal Task SendAsync(object message) => - Connection.SendMessageToServerAsync(Object, "send", new Dictionary - { - { "message", message }, - }); - - internal Task CloseAsync() => Connection.SendMessageToServerAsync(Object, "close"); } diff --git a/src/Playwright/Transport/Channels/RequestChannel.cs b/src/Playwright/Transport/Channels/RequestChannel.cs index ca2043633f..6a3ee7135e 100644 --- a/src/Playwright/Transport/Channels/RequestChannel.cs +++ b/src/Playwright/Transport/Channels/RequestChannel.cs @@ -22,11 +22,7 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Helpers; -using Microsoft.Playwright.Transport.Protocol; namespace Microsoft.Playwright.Transport.Channels; @@ -35,9 +31,4 @@ internal class RequestChannel : Channel public RequestChannel(string guid, Connection connection, Request owner) : base(guid, connection, owner) { } - - internal Task GetResponseAsync() => Connection.SendMessageToServerAsync(Object, "response"); - - internal async Task> GetRawRequestHeadersAsync() => - (await Connection.SendMessageToServerAsync(Object, "rawRequestHeaders").ConfigureAwait(false))?.GetProperty("headers").ToObject>(); } diff --git a/src/Playwright/Transport/Channels/ResponseChannel.cs b/src/Playwright/Transport/Channels/ResponseChannel.cs index 4bcff78f18..26815ac728 100644 --- a/src/Playwright/Transport/Channels/ResponseChannel.cs +++ b/src/Playwright/Transport/Channels/ResponseChannel.cs @@ -22,11 +22,7 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Helpers; -using Microsoft.Playwright.Transport.Protocol; namespace Microsoft.Playwright.Transport.Channels; @@ -35,21 +31,4 @@ internal class ResponseChannel : Channel public ResponseChannel(string guid, Connection connection, Response owner) : base(guid, connection, owner) { } - - internal async Task GetBodyAsync() - => (await Connection.SendMessageToServerAsync(Object, "body").ConfigureAwait(false))?.GetProperty("binary").GetBytesFromBase64(); - - internal async Task ServerAddrAsync() - => (await Connection.SendMessageToServerAsync(Object, "serverAddr").ConfigureAwait(false)) - ?.GetProperty("value").ToObject(Connection.DefaultJsonSerializerOptions); - - internal async Task SecurityDetailsAsync() - => (await Connection.SendMessageToServerAsync(Object, "securityDetails").ConfigureAwait(false)) - ?.GetProperty("value").ToObject(Connection.DefaultJsonSerializerOptions); - - internal async Task SizesAsync() => - (await Connection.SendMessageToServerAsync(Object, "sizes").ConfigureAwait(false))?.GetProperty("sizes").ToObject(); - - internal async Task> GetRawHeadersAsync() => - (await Connection.SendMessageToServerAsync(Object, "rawResponseHeaders").ConfigureAwait(false))?.GetProperty("headers").ToObject>(); } diff --git a/src/Playwright/Transport/Channels/Root.cs b/src/Playwright/Transport/Channels/Root.cs index 0403ca36b8..fccc19d2e7 100644 --- a/src/Playwright/Transport/Channels/Root.cs +++ b/src/Playwright/Transport/Channels/Root.cs @@ -22,11 +22,6 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.Playwright.Core; -using Microsoft.Playwright.Helpers; - namespace Microsoft.Playwright.Transport.Channels; internal class Root : ChannelOwnerBase @@ -34,15 +29,4 @@ internal class Root : ChannelOwnerBase internal Root(IChannelOwner parent, Connection connection, string guid) : base(parent, connection, guid) { } - - internal async Task InitializeAsync() - { - var args = new Dictionary - { - ["sdkLanguage"] = "csharp", - }; - - var jsonElement = await _connection.SendMessageToServerAsync(this, "initialize", args).ConfigureAwait(false); - return jsonElement.GetObject("playwright", _connection); - } } diff --git a/src/Playwright/Transport/Channels/RouteChannel.cs b/src/Playwright/Transport/Channels/RouteChannel.cs index bdd9fc9728..8366ab7cbe 100644 --- a/src/Playwright/Transport/Channels/RouteChannel.cs +++ b/src/Playwright/Transport/Channels/RouteChannel.cs @@ -22,12 +22,7 @@ * SOFTWARE. */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Transport.Protocol; namespace Microsoft.Playwright.Transport.Channels; @@ -36,47 +31,4 @@ internal class RouteChannel : Channel public RouteChannel(string guid, Connection connection, Route owner) : base(guid, connection, owner) { } - - public Task AbortAsync(string requestUrl, string errorCode) - => Connection.SendMessageToServerAsync( - Object, - "abort", - new Dictionary - { - ["requestUrl"] = requestUrl, - ["errorCode"] = string.IsNullOrEmpty(errorCode) ? RequestAbortErrorCode.Failed : errorCode, - }); - - public Task FulfillAsync(Dictionary args) - => Connection.SendMessageToServerAsync( - Object, - "fulfill", - args); - - public Task ContinueAsync(string requestUrl, string url, string method, byte[] postData, IEnumerable> headers, bool isFallback) - { - var args = new Dictionary - { - ["requestUrl"] = requestUrl, - ["url"] = url, - ["method"] = method, - ["postData"] = postData != null ? Convert.ToBase64String(postData) : null, - ["headers"] = headers?.Select(kv => new HeaderEntry { Name = kv.Key, Value = kv.Value }).ToArray(), - ["isFallback"] = isFallback, - }; - - return Connection.SendMessageToServerAsync( - Object, - "continue", - args); - } - - internal Task RedirectNavigationRequestAsync(string url) => - Connection.SendMessageToServerAsync( - Object, - "redirectNavigationRequest", - new Dictionary - { - ["url"] = url, - }); } diff --git a/src/Playwright/Transport/Channels/SelectorsChannel.cs b/src/Playwright/Transport/Channels/SelectorsChannel.cs index 0b37548d5f..19161abcde 100644 --- a/src/Playwright/Transport/Channels/SelectorsChannel.cs +++ b/src/Playwright/Transport/Channels/SelectorsChannel.cs @@ -22,9 +22,6 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.Text.Json; -using System.Threading.Tasks; using Microsoft.Playwright.Core; namespace Microsoft.Playwright.Transport.Channels; @@ -34,31 +31,4 @@ internal class SelectorsChannel : Channel public SelectorsChannel(string guid, Connection connection, Selectors owner) : base(guid, connection, owner) { } - - internal Task RegisterAsync(SelectorsRegisterParams @params) - => Connection.SendMessageToServerAsync( - Object, - "register", - new Dictionary - { - ["name"] = @params.Name, - ["source"] = @params.Source, - ["contentScript"] = @params.ContentScript, - }); - - internal Task SetTestIdAttributeAsync(string name) - => Connection.SendMessageToServerAsync( - Object, - "setTestIdAttributeName", - new Dictionary - { - ["testIdAttributeName"] = name, - }); -} - -internal record SelectorsRegisterParams -{ - internal string Name; - internal string Source; - internal bool? ContentScript; } diff --git a/src/Playwright/Transport/Channels/StreamChannel.cs b/src/Playwright/Transport/Channels/StreamChannel.cs index ec6c5d33c0..982e499522 100644 --- a/src/Playwright/Transport/Channels/StreamChannel.cs +++ b/src/Playwright/Transport/Channels/StreamChannel.cs @@ -22,8 +22,6 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.Threading.Tasks; using Microsoft.Playwright.Core; namespace Microsoft.Playwright.Transport.Channels; @@ -33,18 +31,4 @@ internal class StreamChannel : Channel public StreamChannel(string guid, Connection connection, Stream owner) : base(guid, connection, owner) { } - - internal async Task ReadAsync(int size) - { - var response = await Connection.SendMessageToServerAsync( - Object, - "read", - new Dictionary - { - ["size"] = size, - }).ConfigureAwait(false); - return response.Value.GetProperty("binary").GetBytesFromBase64(); - } - - internal Task CloseAsync() => Connection.SendMessageToServerAsync(Object, "close"); } diff --git a/src/Playwright/Transport/Channels/WorkerChannel.cs b/src/Playwright/Transport/Channels/WorkerChannel.cs index 1e97a24efb..6e025b52ac 100644 --- a/src/Playwright/Transport/Channels/WorkerChannel.cs +++ b/src/Playwright/Transport/Channels/WorkerChannel.cs @@ -22,11 +22,7 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.Text.Json; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Helpers; namespace Microsoft.Playwright.Transport.Channels; @@ -35,34 +31,4 @@ internal class WorkerChannel : Channel public WorkerChannel(string guid, Connection connection, Worker owner) : base(guid, connection, owner) { } - - internal async Task EvaluateExpressionAsync( - string expression, - bool? isFunction, - object arg) - => (await Connection.SendMessageToServerAsync( - Object, - "evaluateExpression", - new Dictionary - { - ["expression"] = expression, - ["isFunction"] = isFunction, - ["arg"] = arg, - }) - .ConfigureAwait(false)).GetProperty("value"); - - internal async Task EvaluateExpressionHandleAsync( - string expression, - bool? isFunction, - object arg) - => (await Connection.SendMessageToServerAsync( - Object, - "evaluateExpressionHandle", - new Dictionary - { - ["expression"] = expression, - ["isFunction"] = isFunction, - ["arg"] = arg, - }) - .ConfigureAwait(false)).GetObject("handle", Connection); } diff --git a/src/Playwright/Transport/Channels/WritableStreamChannel.cs b/src/Playwright/Transport/Channels/WritableStreamChannel.cs index 55d139090e..fe947b5d3f 100644 --- a/src/Playwright/Transport/Channels/WritableStreamChannel.cs +++ b/src/Playwright/Transport/Channels/WritableStreamChannel.cs @@ -22,8 +22,6 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.Threading.Tasks; using Microsoft.Playwright.Core; namespace Microsoft.Playwright.Transport.Channels; @@ -33,17 +31,4 @@ internal class WritableStreamChannel : Channel public WritableStreamChannel(string guid, Connection connection, WritableStream owner) : base(guid, connection, owner) { } - - internal async Task WriteAsync(string binary) - { - await Connection.SendMessageToServerAsync( - Object, - "write", - new Dictionary - { - ["binary"] = binary, - }).ConfigureAwait(false); - } - - internal Task CloseAsync() => Connection.SendMessageToServerAsync(Object, "close"); } diff --git a/src/Playwright/Transport/Connection.cs b/src/Playwright/Transport/Connection.cs index c79db9055d..e1174ce3e7 100644 --- a/src/Playwright/Transport/Connection.cs +++ b/src/Playwright/Transport/Connection.cs @@ -144,7 +144,7 @@ private async Task InnerSendMessageToServerAsync( { throw _closedError; } - if (@object._wasCollected) + if (@object?._wasCollected == true) { throw new PlaywrightException("The object has been collected to prevent unbounded heap growth."); } @@ -195,7 +195,7 @@ await _queue.EnqueueAsync(() => var message = new MessageRequest { Id = id, - Guid = @object.Guid, + Guid = @object == null ? string.Empty : @object.Guid, Method = method, Params = sanitizedArgs, Metadata = metadata, @@ -238,9 +238,15 @@ internal IChannelOwner GetObject(string guid) internal void MarkAsRemote() => IsRemote = true; - internal Task InitializePlaywrightAsync() + internal async Task InitializePlaywrightAsync() { - return _rootObject.InitializeAsync(); + var args = new Dictionary + { + ["sdkLanguage"] = "csharp", + }; + + var jsonElement = await SendMessageToServerAsync(null, "initialize", args).ConfigureAwait(false); + return jsonElement.GetObject("playwright", this); } internal void Dispatch(PlaywrightServerMessage message) From a367d51bc2323d35c67b2c63af9a7b1e449c7b97 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Sat, 9 Dec 2023 12:18:03 -0800 Subject: [PATCH 2/4] chore: move channels into impl classes --- src/Playwright/Core/APIRequest.cs | 44 +++- src/Playwright/Core/APIRequestContext.cs | 35 ++-- src/Playwright/Core/APIResponse.cs | 17 +- src/Playwright/Core/Artifact.cs | 28 ++- src/Playwright/Core/Browser.cs | 163 +++++++++++---- src/Playwright/Core/BrowserContext.cs | 125 +++++++++--- src/Playwright/Core/BrowserType.cs | 168 +++++++++------- src/Playwright/Core/JSHandle.cs | 52 +++-- src/Playwright/Core/LocalUtils.cs | 84 ++++++-- src/Playwright/Core/Page.cs | 2 +- src/Playwright/Core/Tracing.cs | 59 ++++-- .../Helpers/SetInputFilesHelpers.cs | 6 +- .../Channels/APIRequestContextChannel.cs | 62 ------ .../Transport/Channels/ArtifactChannel.cs | 51 ----- .../Transport/Channels/BrowserChannel.cs | 189 ------------------ .../Channels/BrowserContextChannel.cs | 187 ----------------- .../Transport/Channels/BrowserTypeChannel.cs | 188 ----------------- .../Transport/Channels/JSHandleChannel.cs | 48 ----- .../Transport/Channels/LocalUtilsChannel.cs | 98 --------- .../Transport/Channels/PlaywrightChannel.cs | 47 ----- .../Transport/Channels/TracingChannel.cs | 49 ----- 21 files changed, 568 insertions(+), 1134 deletions(-) diff --git a/src/Playwright/Core/APIRequest.cs b/src/Playwright/Core/APIRequest.cs index a5d7797fa5..342f067df9 100644 --- a/src/Playwright/Core/APIRequest.cs +++ b/src/Playwright/Core/APIRequest.cs @@ -22,7 +22,12 @@ * SOFTWARE. */ +using System.Collections.Generic; +using System.IO; +using System.Text.Json; using System.Threading.Tasks; +using Microsoft.Playwright.Helpers; +using Microsoft.Playwright.Transport.Channels; namespace Microsoft.Playwright.Core; @@ -37,17 +42,34 @@ public APIRequest(PlaywrightImpl playwright) async Task IAPIRequest.NewContextAsync(APIRequestNewContextOptions options) { - var context = await _playwright._channel.NewRequestAsync( - options?.BaseURL, - options?.UserAgent, - options?.IgnoreHTTPSErrors, - options?.ExtraHTTPHeaders, - options?.HttpCredentials, - options?.Proxy, - options?.Timeout, - options?.StorageState, - options?.StorageStatePath) - .ConfigureAwait(false); + var args = new Dictionary() + { + ["baseURL"] = options?.BaseURL, + ["userAgent"] = options?.UserAgent, + ["ignoreHTTPSErrors"] = options?.IgnoreHTTPSErrors, + ["extraHTTPHeaders"] = options?.ExtraHTTPHeaders?.ToProtocol(), + ["httpCredentials"] = options?.HttpCredentials, + ["proxy"] = options?.Proxy, + ["timeout"] = options?.Timeout, + }; + string storageState = options?.StorageState; + if (!string.IsNullOrEmpty(options?.StorageStatePath)) + { + if (!File.Exists(options?.StorageStatePath)) + { + throw new PlaywrightException($"The specified storage state file does not exist: {options?.StorageStatePath}"); + } + + storageState = File.ReadAllText(options?.StorageStatePath); + } + if (!string.IsNullOrEmpty(storageState)) + { + args.Add("storageState", JsonSerializer.Deserialize(storageState, Helpers.JsonExtensions.DefaultJsonSerializerOptions)); + } + + var context = (await _playwright.SendMessageToServerAsync( + "newRequest", + args).ConfigureAwait(false)).Object; context._request = this; return context; } diff --git a/src/Playwright/Core/APIRequestContext.cs b/src/Playwright/Core/APIRequestContext.cs index 3a60651a38..90feac8490 100644 --- a/src/Playwright/Core/APIRequestContext.cs +++ b/src/Playwright/Core/APIRequestContext.cs @@ -54,7 +54,7 @@ public APIRequestContext(IChannelOwner parent, string guid, APIRequestContextIni IChannel IChannelOwner.Channel => _channel; [MethodImpl(MethodImplOptions.NoInlining)] - public ValueTask DisposeAsync() => new(_channel.DisposeAsync()); + public ValueTask DisposeAsync() => new(SendMessageToServerAsync("dispose")); [MethodImpl(MethodImplOptions.NoInlining)] public Task FetchAsync(IRequest request, APIRequestContextOptions options = null) @@ -121,19 +121,24 @@ public async Task FetchAsync(string url, APIRequestContextOptions jsonData = JsonSerializer.Serialize(options.DataObject, _connection.DefaultJsonSerializerOptionsKeepNulls); } - return await _channel.FetchAsync( - url, - queryParams, - options.Method, - options.Headers, - jsonData, - postData, - (FormData)options.Form, - (FormData)options.Multipart, - options.Timeout, - options?.FailOnStatusCode, - options?.IgnoreHTTPSErrors, - options?.MaxRedirects).ConfigureAwait(false); + var message = new Dictionary + { + ["url"] = url, + ["method"] = options?.Method, + ["failOnStatusCode"] = options?.FailOnStatusCode, + ["ignoreHTTPSErrors"] = options?.IgnoreHTTPSErrors, + ["maxRedirects"] = options?.MaxRedirects, + ["timeout"] = options.Timeout, + ["params"] = queryParams?.ToProtocol(), + ["headers"] = options.Headers?.ToProtocol(), + ["jsonData"] = jsonData, + ["postData"] = postData != null ? Convert.ToBase64String(postData) : null, + ["formData"] = ((FormData)options.Form)?.ToProtocol(throwWhenSerializingFilePayloads: true), + ["multipartData"] = ((FormData)options.Multipart)?.ToProtocol(), + }; + + var response = await SendMessageToServerAsync("fetch", message).ConfigureAwait(false); + return new APIResponse(this, response?.GetProperty("response").ToObject()); } private bool IsJsonContentType(IDictionary headers) @@ -193,7 +198,7 @@ private APIRequestContextOptions WithMethod(APIRequestContextOptions options, st public async Task StorageStateAsync(APIRequestContextStorageStateOptions options = null) { string state = JsonSerializer.Serialize( - await _channel.StorageStateAsync().ConfigureAwait(false), + await SendMessageToServerAsync("storageState").ConfigureAwait(false), JsonExtensions.DefaultJsonSerializerOptions); if (!string.IsNullOrEmpty(options?.Path)) diff --git a/src/Playwright/Core/APIResponse.cs b/src/Playwright/Core/APIResponse.cs index 9c6ed84fa6..5e9b12128a 100644 --- a/src/Playwright/Core/APIResponse.cs +++ b/src/Playwright/Core/APIResponse.cs @@ -27,6 +27,7 @@ using System.Linq; using System.Text.Json; using System.Threading.Tasks; +using Microsoft.Playwright.Helpers; namespace Microsoft.Playwright.Core; @@ -61,12 +62,12 @@ public async Task BodyAsync() { try { - var result = await _context._channel.FetchResponseBodyAsync(FetchUid()).ConfigureAwait(false); - if (result == null) + var response = await _context.SendMessageToServerAsync("fetchResponseBody", new Dictionary { ["fetchUid"] = FetchUid() }).ConfigureAwait(false); + if (response?.TryGetProperty("binary", out var binary) == true) { - throw new PlaywrightException("Response has been disposed"); + return Convert.FromBase64String(binary.ToString()); } - return Convert.FromBase64String(result); + throw new PlaywrightException("Response has been disposed"); } catch (Exception e) when (DriverMessages.IsTargetClosedError(e)) { @@ -86,9 +87,13 @@ public async Task TextAsync() internal string FetchUid() => _initializer.FetchUid; - internal Task FetchLogAsync() => _context._channel.FetchResponseLogAsync(FetchUid()); + internal async Task FetchLogAsync() + { + var response = await _context.SendMessageToServerAsync("fetchLog", new Dictionary { ["fetchUid"] = FetchUid() }).ConfigureAwait(false); + return response.Value.GetProperty("log").ToObject(); + } - public ValueTask DisposeAsync() => new(_context._channel.DisposeAPIResponseAsync(FetchUid())); + public ValueTask DisposeAsync() => new(_context.SendMessageToServerAsync("disposeAPIResponse", new Dictionary { ["fetchUid"] = FetchUid() })); public override string ToString() { diff --git a/src/Playwright/Core/Artifact.cs b/src/Playwright/Core/Artifact.cs index 15d2e94c03..269d75b426 100644 --- a/src/Playwright/Core/Artifact.cs +++ b/src/Playwright/Core/Artifact.cs @@ -22,9 +22,12 @@ * SOFTWARE. */ +using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; +using System.Text.Json; using System.Threading.Tasks; +using Microsoft.Playwright.Helpers; using Microsoft.Playwright.Transport; using Microsoft.Playwright.Transport.Channels; using Microsoft.Playwright.Transport.Protocol; @@ -56,7 +59,8 @@ public async Task PathAfterFinishedAsync() { throw new PlaywrightException("Path is not available when connecting remotely. Use SaveAsAsync() to save a local copy."); } - return await _channel.PathAfterFinishedAsync().ConfigureAwait(false); + return (await SendMessageToServerAsync("pathAfterFinished") + .ConfigureAwait(false)).GetString("value", true); } [MethodImpl(MethodImplOptions.NoInlining)] @@ -64,11 +68,17 @@ public async Task SaveAsAsync(string path) { if (!_connection.IsRemote) { - await _channel.SaveAsAsync(path).ConfigureAwait(false); + await SendMessageToServerAsync( + "saveAs", + new Dictionary + { + ["path"] = path, + }).ConfigureAwait(false); return; } - System.IO.Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path))); - var stream = await _channel.SaveAsStreamAsync().ConfigureAwait(false); + Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path))); + var stream = (await SendMessageToServerAsync("saveAsStream") + .ConfigureAwait(false)).GetObject("stream", _connection); await using (stream.ConfigureAwait(false)) { using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write)) @@ -81,13 +91,15 @@ public async Task SaveAsAsync(string path) [MethodImpl(MethodImplOptions.NoInlining)] public async Task CreateReadStreamAsync() { - var stream = await _channel.StreamAsync().ConfigureAwait(false); + var stream = (await SendMessageToServerAsync("stream") + .ConfigureAwait(false))?.GetObject("stream", _connection); return stream.StreamImpl; } - internal Task CancelAsync() => _channel.CancelAsync(); + internal Task CancelAsync() => SendMessageToServerAsync("cancel"); - internal Task FailureAsync() => _channel.FailureAsync(); + internal async Task FailureAsync() => (await SendMessageToServerAsync("failure") + .ConfigureAwait(false)).GetString("error", true); - internal Task DeleteAsync() => _channel.DeleteAsync(); + internal Task DeleteAsync() => SendMessageToServerAsync("delete"); } diff --git a/src/Playwright/Core/Browser.cs b/src/Playwright/Core/Browser.cs index 63fba13eb6..e05885af0b 100644 --- a/src/Playwright/Core/Browser.cs +++ b/src/Playwright/Core/Browser.cs @@ -24,9 +24,13 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Runtime.CompilerServices; using System.Text.Json; +using System.Text.RegularExpressions; using System.Threading.Tasks; +using Microsoft.Playwright.Helpers; using Microsoft.Playwright.Transport; using Microsoft.Playwright.Transport.Channels; using Microsoft.Playwright.Transport.Protocol; @@ -88,7 +92,10 @@ public async Task CloseAsync(BrowserCloseOptions options = default) } else { - await Channel.CloseAsync(options?.Reason).ConfigureAwait(false); + await SendMessageToServerAsync("close", new Dictionary + { + ["reason"] = options?.Reason, + }).ConfigureAwait(false); } await _closedTcs.Task.ConfigureAwait(false); } @@ -102,41 +109,74 @@ public async Task CloseAsync(BrowserCloseOptions options = default) public async Task NewContextAsync(BrowserNewContextOptions options = default) { options ??= new(); - var context = (await Channel.NewContextAsync( - acceptDownloads: options.AcceptDownloads, - bypassCSP: options.BypassCSP, - colorScheme: options.ColorScheme, - reducedMotion: options.ReducedMotion, - deviceScaleFactor: options.DeviceScaleFactor, - extraHTTPHeaders: options.ExtraHTTPHeaders, - geolocation: options.Geolocation, - hasTouch: options.HasTouch, - httpCredentials: options.HttpCredentials, - ignoreHTTPSErrors: options.IgnoreHTTPSErrors, - isMobile: options.IsMobile, - javaScriptEnabled: options.JavaScriptEnabled, - locale: options.Locale, - offline: options.Offline, - permissions: options.Permissions, - proxy: options.Proxy, - recordHarContent: options.RecordHarContent, - recordHarMode: options.RecordHarMode, - recordHarOmitContent: options.RecordHarOmitContent, - recordHarPath: options.RecordHarPath, - recordHarUrlFilter: options.RecordHarUrlFilter, - recordHarUrlFilterString: options.RecordHarUrlFilterString, - recordHarUrlFilterRegex: options.RecordHarUrlFilterRegex, - recordVideo: GetVideoArgs(options.RecordVideoDir, options.RecordVideoSize), - storageState: options.StorageState, - storageStatePath: options.StorageStatePath, - serviceWorkers: options.ServiceWorkers, - timezoneId: options.TimezoneId, - userAgent: options.UserAgent, - viewportSize: options.ViewportSize, - screenSize: options.ScreenSize, - baseUrl: options.BaseURL, - strictSelectors: options.StrictSelectors, - forcedColors: options.ForcedColors).ConfigureAwait(false)).Object; + + var args = new Dictionary + { + ["bypassCSP"] = options.BypassCSP, + ["deviceScaleFactor"] = options.DeviceScaleFactor, + ["serviceWorkers"] = options.ServiceWorkers, + ["geolocation"] = options.Geolocation, + ["hasTouch"] = options.HasTouch, + ["httpCredentials"] = options.HttpCredentials, + ["ignoreHTTPSErrors"] = options.IgnoreHTTPSErrors, + ["isMobile"] = options.IsMobile, + ["javaScriptEnabled"] = options.JavaScriptEnabled, + ["locale"] = options.Locale, + ["offline"] = options.Offline, + ["permissions"] = options.Permissions, + ["proxy"] = options.Proxy, + ["strictSelectors"] = options.StrictSelectors, + ["colorScheme"] = options.ColorScheme == ColorScheme.Null ? "no-override" : options.ColorScheme, + ["reducedMotion"] = options.ReducedMotion == ReducedMotion.Null ? "no-override" : options.ReducedMotion, + ["forcedColors"] = options.ForcedColors == ForcedColors.Null ? "no-override" : options.ForcedColors, + ["extraHTTPHeaders"] = options.ExtraHTTPHeaders?.Select(kv => new HeaderEntry { Name = kv.Key, Value = kv.Value }).ToArray(), + ["recordHar"] = PrepareHarOptions( + recordHarContent: options.RecordHarContent, + recordHarMode: options.RecordHarMode, + recordHarPath: options.RecordHarPath, + recordHarOmitContent: options.RecordHarOmitContent, + recordHarUrlFilter: options.RecordHarUrlFilter, + recordHarUrlFilterString: options.RecordHarUrlFilterString, + recordHarUrlFilterRegex: options.RecordHarUrlFilterRegex), + ["recordVideo"] = GetVideoArgs(options.RecordVideoDir, options.RecordVideoSize), + ["timezoneId"] = options.TimezoneId, + ["userAgent"] = options.UserAgent, + ["baseURL"] = options.BaseURL, + }; + + if (options.AcceptDownloads.HasValue) + { + args.Add("acceptDownloads", options.AcceptDownloads.Value ? "accept" : "deny"); + } + + var storageState = options.StorageState; + if (!string.IsNullOrEmpty(options.StorageStatePath)) + { + if (!File.Exists(options.StorageStatePath)) + { + throw new PlaywrightException($"The specified storage state file does not exist: {options.StorageStatePath}"); + } + + storageState = File.ReadAllText(options.StorageStatePath); + } + + if (!string.IsNullOrEmpty(storageState)) + { + args.Add("storageState", JsonSerializer.Deserialize(storageState, Helpers.JsonExtensions.DefaultJsonSerializerOptions)); + } + + if (options.ViewportSize?.Width == -1) + { + args.Add("noDefaultViewport", true); + } + else + { + args.Add("viewport", options.ViewportSize); + args.Add("screen", options.ScreenSize); + } + + var context = (await SendMessageToServerAsync("newContext", args).ConfigureAwait(false)).Object; + _browserType.DidCreateContext(context, options, null); return context; } @@ -234,5 +274,54 @@ internal void DidClose() [MethodImpl(MethodImplOptions.NoInlining)] public async Task NewBrowserCDPSessionAsync() - => (await Channel.NewBrowserCDPSessionAsync().ConfigureAwait(false)).Object; + => (await SendMessageToServerAsync( + "newBrowserCDPSession").ConfigureAwait(false)).Object; + + internal static Dictionary PrepareHarOptions( + HarContentPolicy? recordHarContent, + HarMode? recordHarMode, + string recordHarPath, + bool? recordHarOmitContent, + string recordHarUrlFilter, + string recordHarUrlFilterString, + Regex recordHarUrlFilterRegex) + { + if (string.IsNullOrEmpty(recordHarPath)) + { + return null; + } + var recordHarArgs = new Dictionary(); + recordHarArgs["path"] = recordHarPath; + if (recordHarContent.HasValue) + { + recordHarArgs["content"] = recordHarContent; + } + else if (recordHarOmitContent == true) + { + recordHarArgs["content"] = HarContentPolicy.Omit; + } + if (!string.IsNullOrEmpty(recordHarUrlFilter)) + { + recordHarArgs["urlGlob"] = recordHarUrlFilter; + } + else if (!string.IsNullOrEmpty(recordHarUrlFilterString)) + { + recordHarArgs["urlGlob"] = recordHarUrlFilterString; + } + else if (recordHarUrlFilterRegex != null) + { + recordHarArgs["urlRegexSource"] = recordHarUrlFilterRegex.ToString(); + recordHarArgs["urlRegexFlags"] = recordHarUrlFilterRegex.Options.GetInlineFlags(); + } + if (recordHarMode.HasValue) + { + recordHarArgs["mode"] = recordHarMode; + } + + if (recordHarArgs.Keys.Count > 0) + { + return recordHarArgs; + } + return null; + } } diff --git a/src/Playwright/Core/BrowserContext.cs b/src/Playwright/Core/BrowserContext.cs index 859ebb67a3..3202711518 100644 --- a/src/Playwright/Core/BrowserContext.cs +++ b/src/Playwright/Core/BrowserContext.cs @@ -260,7 +260,12 @@ internal void OnDialog(IDialog dialog) } [MethodImpl(MethodImplOptions.NoInlining)] - public Task AddCookiesAsync(IEnumerable cookies) => Channel.AddCookiesAsync(cookies); + public Task AddCookiesAsync(IEnumerable cookies) => SendMessageToServerAsync( + "addCookies", + new Dictionary + { + ["cookies"] = cookies, + }); [MethodImpl(MethodImplOptions.NoInlining)] public Task AddInitScriptAsync(string script = null, string scriptPath = null) @@ -270,14 +275,19 @@ public Task AddInitScriptAsync(string script = null, string scriptPath = null) script = ScriptsHelper.EvaluationScript(script, scriptPath); } - return Channel.AddInitScriptAsync(script); + return SendMessageToServerAsync( + "addInitScript", + new Dictionary + { + ["source"] = script, + }); } [MethodImpl(MethodImplOptions.NoInlining)] - public Task ClearCookiesAsync() => Channel.ClearCookiesAsync(); + public Task ClearCookiesAsync() => SendMessageToServerAsync("clearCookies"); [MethodImpl(MethodImplOptions.NoInlining)] - public Task ClearPermissionsAsync() => Channel.ClearPermissionsAsync(); + public Task ClearPermissionsAsync() => SendMessageToServerAsync("clearPermissions"); [MethodImpl(MethodImplOptions.NoInlining)] public async Task CloseAsync(BrowserContextCloseOptions options = default) @@ -293,7 +303,12 @@ await WrapApiCallAsync( { foreach (var harRecorder in _harRecorders) { - Artifact artifact = await Channel.HarExportAsync(harRecorder.Key).ConfigureAwait(false); + Artifact artifact = (await SendMessageToServerAsync( + "harExport", + new Dictionary + { + ["harId"] = harRecorder.Key, + }).ConfigureAwait(false)).GetObject("artifact", _connection); // Server side will compress artifact if content is attach or if file is .zip. var isCompressed = harRecorder.Value.Content == HarContentPolicy.Attach || harRecorder.Value.Path.EndsWith(".zip", StringComparison.Ordinal); var needCompressed = harRecorder.Value.Path.EndsWith(".zip", StringComparison.Ordinal); @@ -310,7 +325,10 @@ await WrapApiCallAsync( } }, true).ConfigureAwait(false); - await Channel.CloseAsync(options?.Reason).ConfigureAwait(false); + await SendMessageToServerAsync("close", new Dictionary + { + ["reason"] = options?.Reason, + }).ConfigureAwait(false); await _closeTcs.Task.ConfigureAwait(false); } @@ -325,7 +343,12 @@ internal void SetOptions(BrowserNewContextOptions contextOptions, string tracesD } [MethodImpl(MethodImplOptions.NoInlining)] - public Task> CookiesAsync(IEnumerable urls = null) => Channel.CookiesAsync(urls); + public async Task> CookiesAsync(IEnumerable urls = null) => (await SendMessageToServerAsync( + "cookies", + new Dictionary + { + ["urls"] = urls?.ToArray() ?? Array.Empty(), + }).ConfigureAwait(false))?.GetProperty("cookies").ToObject>(); [MethodImpl(MethodImplOptions.NoInlining)] public Task ExposeBindingAsync(string name, Action callback, BrowserContextExposeBindingOptions options = default) @@ -393,15 +416,29 @@ public Task ExposeFunctionAsync(string name, Func permissions, BrowserContextGrantPermissionsOptions options = default) - => Channel.GrantPermissionsAsync(permissions, options?.Origin); + => SendMessageToServerAsync("grantPermissions", new Dictionary + { + ["permissions"] = permissions?.ToArray(), + ["origin"] = options?.Origin, + }); [MethodImpl(MethodImplOptions.NoInlining)] public async Task NewCDPSessionAsync(IPage page) - => (await Channel.NewCDPSessionAsync(page as Page).ConfigureAwait(false)).Object; + => (await SendMessageToServerAsync( + "newCDPSession", + new Dictionary + { + ["page"] = new { guid = (page as Page).Guid }, + }).ConfigureAwait(false)).Object; [MethodImpl(MethodImplOptions.NoInlining)] public async Task NewCDPSessionAsync(IFrame frame) - => (await Channel.NewCDPSessionAsync(frame as Frame).ConfigureAwait(false)).Object; + => (await SendMessageToServerAsync( + "newCDPSession", + new Dictionary + { + ["frame"] = new { guid = (frame as Frame).Guid }, + }).ConfigureAwait(false)).Object; [MethodImpl(MethodImplOptions.NoInlining)] public async Task NewPageAsync() @@ -411,7 +448,7 @@ public async Task NewPageAsync() throw new PlaywrightException("Please use Browser.NewContextAsync()"); } - return (await Channel.NewPageAsync().ConfigureAwait(false)).Object; + return (await SendMessageToServerAsync("newPage").ConfigureAwait(false)).Object; } [MethodImpl(MethodImplOptions.NoInlining)] @@ -440,19 +477,34 @@ public Task RouteAsync(Func url, Func handler, Brows [MethodImpl(MethodImplOptions.NoInlining)] public Task SetExtraHTTPHeadersAsync(IEnumerable> headers) - => Channel.SetExtraHTTPHeadersAsync(headers); + => SendMessageToServerAsync( + "setExtraHTTPHeaders", + new Dictionary + { + ["headers"] = headers.Select(kv => new HeaderEntry { Name = kv.Key, Value = kv.Value }), + }); [MethodImpl(MethodImplOptions.NoInlining)] - public Task SetGeolocationAsync(Geolocation geolocation) => Channel.SetGeolocationAsync(geolocation); + public Task SetGeolocationAsync(Geolocation geolocation) => SendMessageToServerAsync( + "setGeolocation", + new Dictionary + { + ["geolocation"] = geolocation, + }); [MethodImpl(MethodImplOptions.NoInlining)] - public Task SetOfflineAsync(bool offline) => Channel.SetOfflineAsync(offline); + public Task SetOfflineAsync(bool offline) => SendMessageToServerAsync( + "setOffline", + new Dictionary + { + ["offline"] = offline, + }); [MethodImpl(MethodImplOptions.NoInlining)] public async Task StorageStateAsync(BrowserContextStorageStateOptions options = default) { string state = JsonSerializer.Serialize( - await Channel.GetStorageStateAsync().ConfigureAwait(false), + await SendMessageToServerAsync("storageState").ConfigureAwait(false), JsonExtensions.DefaultJsonSerializerOptions); if (!string.IsNullOrEmpty(options?.Path)) @@ -543,7 +595,14 @@ public Task RunAndWaitForConsoleMessageAsync(Func action, internal void SetDefaultNavigationTimeoutImpl(float? timeout) { _timeoutSettings.SetDefaultNavigationTimeout(timeout); - WrapApiCallAsync(() => Channel.SetDefaultNavigationTimeoutNoReplyAsync(timeout), true).IgnoreException(); + WrapApiCallAsync( + () => SendMessageToServerAsync( + "setDefaultNavigationTimeoutNoReply", + new Dictionary + { + ["timeout"] = timeout, + }), + true).IgnoreException(); } [MethodImpl(MethodImplOptions.NoInlining)] @@ -552,7 +611,14 @@ internal void SetDefaultNavigationTimeoutImpl(float? timeout) internal void SetDefaultTimeoutImpl(float? timeout) { _timeoutSettings.SetDefaultTimeout(timeout); - WrapApiCallAsync(() => Channel.SetDefaultTimeoutNoReplyAsync(timeout), true).IgnoreException(); + WrapApiCallAsync( + () => SendMessageToServerAsync( + "setDefaultTimeoutNoReply", + new Dictionary + { + ["timeout"] = timeout, + }), + true).IgnoreException(); } internal async Task OnRouteAsync(Route route) @@ -644,7 +710,9 @@ private Task UnrouteAsync(RouteHandler setting) private Task UpdateInterceptionAsync() { var patterns = RouteHandler.PrepareInterceptionPatterns(_routes); - return Channel.SetNetworkInterceptionPatternsAsync(patterns); + return SendMessageToServerAsync( + "setNetworkInterceptionPatterns", + patterns); } internal void OnClose() @@ -698,7 +766,13 @@ private Task ExposeBindingAsync(string name, Delegate callback, bool handle = fa _bindings.Add(name, callback); - return Channel.ExposeBindingAsync(name, handle); + return SendMessageToServerAsync( + "exposeBinding", + new Dictionary + { + ["name"] = name, + ["needsHandle"] = handle, + }); } private HarContentPolicy? RouteFromHarUpdateContentPolicyToHarContentPolicy(RouteFromHarUpdateContentPolicy? policy) @@ -717,14 +791,11 @@ private Task ExposeBindingAsync(string name, Delegate callback, bool handle = fa internal async Task RecordIntoHarAsync(string har, Page page, BrowserContextRouteFromHAROptions options) { var contentPolicy = RouteFromHarUpdateContentPolicyToHarContentPolicy(options?.UpdateContent); - var harId = await Channel.HarStartAsync( - page, - har, - options?.Url, - options?.UrlString, - options?.UrlRegex, - contentPolicy, - options?.UpdateMode).ConfigureAwait(false); + var harId = (await SendMessageToServerAsync("harStart", new Dictionary + { + { "page", page?.Channel }, + { "options", Core.Browser.PrepareHarOptions(contentPolicy ?? HarContentPolicy.Attach, options.UpdateMode ?? HarMode.Minimal, har, null, options.Url, options.UrlString, options.UrlRegex) }, + }).ConfigureAwait(false)).GetString("harId", false); _harRecorders.Add(harId, new() { Path = har, Content = contentPolicy ?? HarContentPolicy.Attach }); } diff --git a/src/Playwright/Core/BrowserType.cs b/src/Playwright/Core/BrowserType.cs index 753f308810..c1b92c5b32 100644 --- a/src/Playwright/Core/BrowserType.cs +++ b/src/Playwright/Core/BrowserType.cs @@ -60,25 +60,29 @@ internal BrowserType(IChannelOwner parent, string guid, BrowserTypeInitializer i public async Task LaunchAsync(BrowserTypeLaunchOptions options = default) { options ??= new BrowserTypeLaunchOptions(); - Browser browser = (await _channel.LaunchAsync( - headless: options.Headless, - channel: options.Channel, - executablePath: options.ExecutablePath, - passedArguments: options.Args, - proxy: options.Proxy, - downloadsPath: options.DownloadsPath, - tracesDir: options.TracesDir, - chromiumSandbox: options.ChromiumSandbox, - firefoxUserPrefs: options.FirefoxUserPrefs, - handleSIGINT: options.HandleSIGINT, - handleSIGTERM: options.HandleSIGTERM, - handleSIGHUP: options.HandleSIGHUP, - timeout: options.Timeout, - env: options.Env, - devtools: options.Devtools, - slowMo: options.SlowMo, - ignoreDefaultArgs: options.IgnoreDefaultArgs, - ignoreAllDefaultArgs: options.IgnoreAllDefaultArgs).ConfigureAwait(false)).Object; + Browser browser = (await SendMessageToServerAsync( + "launch", + new Dictionary + { + { "channel", options.Channel }, + { "executablePath", options.ExecutablePath }, + { "args", options.Args }, + { "ignoreAllDefaultArgs", options.IgnoreAllDefaultArgs }, + { "ignoreDefaultArgs", options.IgnoreDefaultArgs }, + { "handleSIGHUP", options.HandleSIGHUP }, + { "handleSIGINT", options.HandleSIGINT }, + { "handleSIGTERM", options.HandleSIGTERM }, + { "headless", options.Headless }, + { "devtools", options.Devtools }, + { "env", options.Env.ToProtocol() }, + { "proxy", options.Proxy }, + { "downloadsPath", options.DownloadsPath }, + { "tracesDir", options.TracesDir }, + { "firefoxUserPrefs", options.FirefoxUserPrefs }, + { "chromiumSandbox", options.ChromiumSandbox }, + { "slowMo", options.ChromiumSandbox }, + { "timeout", options.Timeout }, + }).ConfigureAwait(false)).Object; DidLaunchBrowser(browser); return browser; } @@ -87,56 +91,74 @@ public async Task LaunchAsync(BrowserTypeLaunchOptions options = defau public async Task LaunchPersistentContextAsync(string userDataDir, BrowserTypeLaunchPersistentContextOptions options = default) { options ??= new BrowserTypeLaunchPersistentContextOptions(); - var context = (await _channel.LaunchPersistentContextAsync( - userDataDir, - headless: options.Headless, - channel: options.Channel, - executablePath: options.ExecutablePath, - args: options.Args, - proxy: options.Proxy, - downloadsPath: options.DownloadsPath, - tracesDir: options.TracesDir, - chromiumSandbox: options.ChromiumSandbox, - firefoxUserPrefs: options.FirefoxUserPrefs, - handleSIGINT: options.HandleSIGINT, - handleSIGTERM: options.HandleSIGTERM, - handleSIGHUP: options.HandleSIGHUP, - timeout: options.Timeout, - env: options.Env, - devtools: options.Devtools, - slowMo: options.SlowMo, - acceptDownloads: options.AcceptDownloads, - ignoreHTTPSErrors: options.IgnoreHTTPSErrors, - bypassCSP: options.BypassCSP, - viewportSize: options.ViewportSize, - screenSize: options.ScreenSize, - userAgent: options.UserAgent, - deviceScaleFactor: options.DeviceScaleFactor, - isMobile: options.IsMobile, - hasTouch: options.HasTouch, - javaScriptEnabled: options.JavaScriptEnabled, - timezoneId: options.TimezoneId, - geolocation: options.Geolocation, - locale: options.Locale, - permissions: options.Permissions, - extraHTTPHeaders: options.ExtraHTTPHeaders, - offline: options.Offline, - httpCredentials: options.HttpCredentials, - colorScheme: options.ColorScheme, - reducedMotion: options.ReducedMotion, - recordHarContent: options.RecordHarContent, - recordHarMode: options.RecordHarMode, - recordHarPath: options.RecordHarPath, - recordHarOmitContent: options.RecordHarOmitContent, - recordHarUrlFilter: options.RecordHarUrlFilter, - recordHarUrlFilterString: options.RecordHarUrlFilterString, - recordHarUrlFilterRegex: options.RecordHarUrlFilterRegex, - recordVideo: Browser.GetVideoArgs(options.RecordVideoDir, options.RecordVideoSize), - serviceWorkers: options.ServiceWorkers, - ignoreDefaultArgs: options.IgnoreDefaultArgs, - ignoreAllDefaultArgs: options.IgnoreAllDefaultArgs, - baseUrl: options.BaseURL, - forcedColors: options.ForcedColors).ConfigureAwait(false)).Object; + var channelArgs = new Dictionary + { + ["userDataDir"] = userDataDir, + ["headless"] = options.Headless, + ["channel"] = options.Channel, + ["executablePath"] = options.ExecutablePath, + ["args"] = options.Args, + ["downloadsPath"] = options.DownloadsPath, + ["tracesDir"] = options.TracesDir, + ["proxy"] = options.Proxy, + ["chromiumSandbox"] = options.ChromiumSandbox, + ["firefoxUserPrefs"] = options.FirefoxUserPrefs, + ["handleSIGINT"] = options.HandleSIGINT, + ["handleSIGTERM"] = options.HandleSIGTERM, + ["handleSIGHUP"] = options.HandleSIGHUP, + ["timeout"] = options.Timeout, + ["env"] = options.Env.ToProtocol(), + ["devtools"] = options.Devtools, + ["slowMo"] = options.SlowMo, + ["ignoreHTTPSErrors"] = options.IgnoreHTTPSErrors, + ["bypassCSP"] = options.BypassCSP, + ["strictSelectors"] = options.StrictSelectors, + ["serviceWorkers"] = options.ServiceWorkers, + ["screensize"] = options.ScreenSize, + ["userAgent"] = options.UserAgent, + ["deviceScaleFactor"] = options.DeviceScaleFactor, + ["isMobile"] = options.IsMobile, + ["hasTouch"] = options.HasTouch, + ["javaScriptEnabled"] = options.JavaScriptEnabled, + ["timezoneId"] = options.TimezoneId, + ["geolocation"] = options.Geolocation, + ["locale"] = options.Locale, + ["permissions"] = options.Permissions, + ["extraHTTPHeaders"] = options.ExtraHTTPHeaders.ToProtocol(), + ["offline"] = options.Offline, + ["httpCredentials"] = options.HttpCredentials, + ["colorScheme"] = options.ColorScheme == ColorScheme.Null ? "no-override" : options.ColorScheme, + ["reducedMotion"] = options.ReducedMotion == ReducedMotion.Null ? "no-override" : options.ReducedMotion, + ["forcedColors"] = options.ForcedColors == ForcedColors.Null ? "no-override" : options.ForcedColors, + ["recordVideo"] = Browser.GetVideoArgs(options.RecordVideoDir, options.RecordVideoSize), + ["ignoreDefaultArgs"] = options.IgnoreDefaultArgs, + ["ignoreAllDefaultArgs"] = options.IgnoreAllDefaultArgs, + ["baseURL"] = options.BaseURL, + ["recordHar"] = Browser.PrepareHarOptions( + recordHarContent: options.RecordHarContent, + recordHarMode: options.RecordHarMode, + recordHarPath: options.RecordHarPath, + recordHarOmitContent: options.RecordHarOmitContent, + recordHarUrlFilter: options.RecordHarUrlFilter, + recordHarUrlFilterString: options.RecordHarUrlFilterString, + recordHarUrlFilterRegex: options.RecordHarUrlFilterRegex), + }; + + if (options.AcceptDownloads.HasValue) + { + channelArgs.Add("acceptDownloads", options.AcceptDownloads.Value ? "accept" : "deny"); + } + + if (options.ViewportSize?.Width == -1) + { + channelArgs.Add("noDefaultViewport", true); + } + else + { + channelArgs.Add("viewport", options.ViewportSize); + } + + var context = (await SendMessageToServerAsync("launchPersistentContext", channelArgs).ConfigureAwait(false)).Object; // TODO: unite with a single browser context options type which is derived from channels DidCreateContext( @@ -254,7 +276,13 @@ public async Task ConnectOverCDPAsync(string endpointURL, BrowserTypeC throw new ArgumentException("Connecting over CDP is only supported in Chromium."); } options ??= new BrowserTypeConnectOverCDPOptions(); - JsonElement result = await _channel.ConnectOverCDPAsync(endpointURL, headers: options.Headers, slowMo: options.SlowMo, timeout: options.Timeout).ConfigureAwait(false); + JsonElement result = await SendMessageToServerAsync("connectOverCDP", new Dictionary + { + { "endpointURL", endpointURL }, + { "headers", options.Headers.ToProtocol() }, + { "slowMo", options.SlowMo }, + { "timeout", options.Timeout }, + }).ConfigureAwait(false); Browser browser = result.GetProperty("browser").ToObject(_channel.Connection.DefaultJsonSerializerOptions); DidLaunchBrowser(browser); if (result.TryGetProperty("defaultContext", out JsonElement defaultContextValue)) diff --git a/src/Playwright/Core/JSHandle.cs b/src/Playwright/Core/JSHandle.cs index 12b4b883a3..ddbca1a245 100644 --- a/src/Playwright/Core/JSHandle.cs +++ b/src/Playwright/Core/JSHandle.cs @@ -26,6 +26,7 @@ using System.Runtime.CompilerServices; using System.Text.Json; using System.Threading.Tasks; +using Microsoft.Playwright.Helpers; using Microsoft.Playwright.Transport; using Microsoft.Playwright.Transport.Channels; using Microsoft.Playwright.Transport.Protocol; @@ -53,33 +54,51 @@ internal JSHandle(IChannelOwner parent, string guid, JSHandleInitializer initial [MethodImpl(MethodImplOptions.NoInlining)] public async Task EvaluateAsync(string expression, object arg = null) - => ScriptsHelper.ParseEvaluateResult(await _channel.EvaluateExpressionAsync( - script: expression, - arg: ScriptsHelper.SerializedArgument(arg)).ConfigureAwait(false)); + => ScriptsHelper.ParseEvaluateResult(await SendMessageToServerAsync( + "evaluateExpression", + new Dictionary + { + ["expression"] = expression, + ["arg"] = ScriptsHelper.SerializedArgument(arg), + }).ConfigureAwait(false)); [MethodImpl(MethodImplOptions.NoInlining)] public async Task EvaluateHandleAsync(string expression, object arg = null) - => (await _channel.EvaluateExpressionHandleAsync( - script: expression, - arg: ScriptsHelper.SerializedArgument(arg)).ConfigureAwait(false))?.Object; + => (await SendMessageToServerAsync( + "evaluateExpressionHandle", + new Dictionary + { + ["expression"] = expression, + ["arg"] = ScriptsHelper.SerializedArgument(arg), + }).ConfigureAwait(false))?.Object; [MethodImpl(MethodImplOptions.NoInlining)] public async Task EvaluateAsync(string expression, object arg = null) - => ScriptsHelper.ParseEvaluateResult(await _channel.EvaluateExpressionAsync( - script: expression, - arg: ScriptsHelper.SerializedArgument(arg)).ConfigureAwait(false)); + => ScriptsHelper.ParseEvaluateResult(await SendMessageToServerAsync( + "evaluateExpression", + new Dictionary + { + ["expression"] = expression, + ["arg"] = ScriptsHelper.SerializedArgument(arg), + }).ConfigureAwait(false)); [MethodImpl(MethodImplOptions.NoInlining)] - public async Task JsonValueAsync() => ScriptsHelper.ParseEvaluateResult(await _channel.JsonValueAsync().ConfigureAwait(false)); + public async Task JsonValueAsync() => ScriptsHelper.ParseEvaluateResult(await SendMessageToServerAsync("jsonValue").ConfigureAwait(false)); [MethodImpl(MethodImplOptions.NoInlining)] - public async Task GetPropertyAsync(string propertyName) => (await _channel.GetPropertyAsync(propertyName).ConfigureAwait(false))?.Object; + public async Task GetPropertyAsync(string propertyName) => (await SendMessageToServerAsync( + "getProperty", + new Dictionary + { + ["name"] = propertyName, + }).ConfigureAwait(false))?.Object; [MethodImpl(MethodImplOptions.NoInlining)] public async Task> GetPropertiesAsync() { var result = new Dictionary(); - var channelResult = await _channel.GetPropertiesAsync().ConfigureAwait(false); + var channelResult = (await SendMessageToServerAsync("getPropertyList").ConfigureAwait(false))? + .GetProperty("properties").ToObject>(_connection.DefaultJsonSerializerOptions); foreach (var kv in channelResult) { @@ -90,7 +109,14 @@ public async Task> GetPropertiesAsync() } [MethodImpl(MethodImplOptions.NoInlining)] - public async ValueTask DisposeAsync() => await _channel.DisposeAsync().ConfigureAwait(false); + public async ValueTask DisposeAsync() => await SendMessageToServerAsync("dispose").ConfigureAwait(false); public override string ToString() => Preview; } + +internal class JSElementProperty +{ + public string Name { get; set; } + + public JSHandleChannel Value { get; set; } +} diff --git a/src/Playwright/Core/LocalUtils.cs b/src/Playwright/Core/LocalUtils.cs index 6852f0f016..b9062f5b8e 100644 --- a/src/Playwright/Core/LocalUtils.cs +++ b/src/Playwright/Core/LocalUtils.cs @@ -22,8 +22,10 @@ * SOFTWARE. */ +using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.Playwright.Helpers; using Microsoft.Playwright.Transport; using Microsoft.Playwright.Transport.Channels; using Microsoft.Playwright.Transport.Protocol; @@ -49,10 +51,23 @@ public LocalUtils(IChannelOwner parent, string guid, LocalUtilsInitializer initi IChannel IChannelOwner.Channel => _channel; internal Task ZipAsync(string zipFile, List entries, string mode, string stacksId, bool includeSources) - => _channel.ZipAsync(zipFile, entries, mode, stacksId, includeSources); - - internal Task<(string HarId, string Error)> HarOpenAsync(string file) - => _channel.HarOpenAsync(file); + => SendMessageToServerAsync("zip", new Dictionary + { + { "zipFile", zipFile }, + { "entries", entries }, + { "mode", mode }, + { "stacksId", stacksId }, + { "includeSources", includeSources }, + }); + + internal async Task<(string HarId, string Error)> HarOpenAsync(string file) + { + var response = await SendMessageToServerAsync("harOpen", new Dictionary + { + { "file", file }, + }).ConfigureAwait(false); + return (response.GetString("harId", true), response.GetString("error", true)); + } internal Task HarLookupAsync( string harId, @@ -61,25 +76,66 @@ internal Task HarLookupAsync( List
headers, byte[] postData, bool isNavigationRequest) - => _channel.HarLookupAsync(harId, url, method, headers, postData, isNavigationRequest); + => SendMessageToServerAsync("harLookup", new Dictionary + { + { "harId", harId }, + { "url", url }, + { "method", method }, + { "headers", headers }, + { "postData", postData != null ? Convert.ToBase64String(postData) : null }, + { "isNavigationRequest", isNavigationRequest }, + }); internal Task HarCloseAsync(string harId) - => _channel.HarCloseAsync(harId); + => SendMessageToServerAsync("HarCloseAsync", new Dictionary + { + { "harId", harId }, + }); internal Task HarUnzipAsync(string zipFile, string harFile) - => _channel.HarUnzipAsync(zipFile, harFile); - - internal Task ConnectAsync(string wsEndpoint = default, IEnumerable> headers = default, float? slowMo = default, float? timeout = default, string exposeNetwork = default) - => _channel.ConnectAsync(wsEndpoint, headers, slowMo, timeout, exposeNetwork); + => SendMessageToServerAsync("harUnzip", new Dictionary + { + { "zipFile", zipFile }, + { "harFile", harFile }, + }); + + internal async Task ConnectAsync(string wsEndpoint = default, IEnumerable> headers = default, float? slowMo = default, float? timeout = default, string exposeNetwork = default) + => (await SendMessageToServerAsync("connect", new Dictionary + { + { "wsEndpoint", wsEndpoint }, + { "headers", headers }, + { "slowMo", slowMo }, + { "timeout", timeout }, + { "exposeNetwork", exposeNetwork }, + }).ConfigureAwait(false)).Value.GetObject("pipe", _connection); internal void AddStackToTracingNoReply(List stack, int id) - => _channel.AddStackToTracingNoReply(stack, id); + => SendMessageToServerAsync("addStackToTracingNoReply", new Dictionary + { + { + "callData", new ClientSideCallMetadata() + { + Id = id, + Stack = stack, + } + }, + }).IgnoreException(); internal Task TraceDiscardedAsync(string stacksId) - => _channel.TraceDiscardedAsync(stacksId); + => SendMessageToServerAsync("traceDiscarded", new Dictionary + { + { "stacksId", stacksId }, + }); - internal Task TracingStartedAsync(string tracesDir, string traceName) - => _channel.TracingStartedAsync(tracesDir, traceName); + internal async Task TracingStartedAsync(string tracesDir, string traceName) + { + var response = await SendMessageToServerAsync("tracingStarted", new Dictionary + { + { "tracesDir", tracesDir }, + { "traceName", traceName }, + }).ConfigureAwait(false); + return response.GetString("stacksId", true); + } } internal class LocalUtilsHarLookupResult diff --git a/src/Playwright/Core/Page.cs b/src/Playwright/Core/Page.cs index 6925351130..09197d13a0 100644 --- a/src/Playwright/Core/Page.cs +++ b/src/Playwright/Core/Page.cs @@ -1103,7 +1103,7 @@ public async Task PauseAsync() _timeoutSettings.SetDefaultTimeout(0); try { - await Task.WhenAny(Context.Channel.PauseAsync(), ClosedOrCrashedTcs.Task).ConfigureAwait(false); + await Task.WhenAny(Context.SendMessageToServerAsync("pause"), ClosedOrCrashedTcs.Task).ConfigureAwait(false); } finally { diff --git a/src/Playwright/Core/Tracing.cs b/src/Playwright/Core/Tracing.cs index 1176e880e0..b6b11c1061 100644 --- a/src/Playwright/Core/Tracing.cs +++ b/src/Playwright/Core/Tracing.cs @@ -22,10 +22,14 @@ * SOFTWARE. */ +using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Text.Json; using System.Threading.Tasks; +using Microsoft.Playwright.Helpers; using Microsoft.Playwright.Transport; using Microsoft.Playwright.Transport.Channels; +using Microsoft.Playwright.Transport.Protocol; namespace Microsoft.Playwright.Core; @@ -54,13 +58,21 @@ public async Task StartAsync( var traceName = await _channel.Connection.WrapApiCallAsync( async () => { - await _channel.TracingStartAsync( - name: options?.Name, - title: options?.Title, - screenshots: options?.Screenshots, - snapshots: options?.Snapshots, - sources: options?.Sources).ConfigureAwait(false); - return await _channel.StartChunkAsync(title: options?.Title, name: options?.Name).ConfigureAwait(false); + await SendMessageToServerAsync( + "tracingStart", + new Dictionary + { + ["name"] = options?.Name, + ["title"] = options?.Title, + ["screenshots"] = options?.Screenshots, + ["snapshots"] = options?.Snapshots, + ["sources"] = options?.Sources, + }).ConfigureAwait(false); + return (await SendMessageToServerAsync("tracingStartChunk", new Dictionary + { + ["title"] = options?.Title, + ["name"] = options?.Name, + }).ConfigureAwait(false))?.GetProperty("traceName").ToString(); }, true).ConfigureAwait(false); await StartCollectingStacksAsync(traceName).ConfigureAwait(false); @@ -69,7 +81,11 @@ await _channel.TracingStartAsync( [MethodImpl(MethodImplOptions.NoInlining)] public async Task StartChunkAsync(TracingStartChunkOptions options = default) { - var traceName = await _channel.StartChunkAsync(title: options?.Title, name: options?.Name).ConfigureAwait(false); + var traceName = (await SendMessageToServerAsync("tracingStartChunk", new Dictionary + { + ["title"] = options?.Title, + ["name"] = options?.Name, + }).ConfigureAwait(false))?.GetProperty("traceName").ToString(); await StartCollectingStacksAsync(traceName).ConfigureAwait(false); } @@ -93,7 +109,7 @@ await _channel.Connection.WrapApiCallAsync( async () => { await StopChunkAsync(new() { Path = options?.Path }).ConfigureAwait(false); - await _channel.TracingStopAsync().ConfigureAwait(false); + await SendMessageToServerAsync("tracingStop").ConfigureAwait(false); }, true).ConfigureAwait(false); } @@ -109,7 +125,7 @@ private async Task DoStopChunkAsync(string filePath) if (string.IsNullOrEmpty(filePath)) { // Not interested in artifacts. - await _channel.TracingStopChunkAsync("discard").ConfigureAwait(false); + await _TracingStopChunkAsync("discard").ConfigureAwait(false); if (!string.IsNullOrEmpty(_stacksId)) { await _channel.Connection.LocalUtils.TraceDiscardedAsync(stacksId: _stacksId).ConfigureAwait(false); @@ -121,12 +137,12 @@ private async Task DoStopChunkAsync(string filePath) if (isLocal) { - var (_, sourceEntries) = await _channel.TracingStopChunkAsync("entries").ConfigureAwait(false); + var (_, sourceEntries) = await _TracingStopChunkAsync("entries").ConfigureAwait(false); await _channel.Connection.LocalUtils.ZipAsync(filePath, sourceEntries, "write", _stacksId, _includeSources).ConfigureAwait(false); return; } - var (artifact, _) = await _channel.TracingStopChunkAsync("archive").ConfigureAwait(false); + var (artifact, _) = await _TracingStopChunkAsync("archive").ConfigureAwait(false); // The artifact may be missing if the browser closed while stopping tracing. if (artifact == null) @@ -144,4 +160,23 @@ private async Task DoStopChunkAsync(string filePath) await _channel.Connection.LocalUtils.ZipAsync(filePath, new(), "append", _stacksId, _includeSources).ConfigureAwait(false); } + + internal async Task<(Artifact Artifact, List Entries)> _TracingStopChunkAsync(string mode) + { + var result = await SendMessageToServerAsync("tracingStopChunk", new Dictionary + { + ["mode"] = mode, + }).ConfigureAwait(false); + + var artifact = result.GetObject("artifact", _connection); + List entries = new(); + if (result.Value.TryGetProperty("entries", out var entriesElement)) + { + foreach (var current in entriesElement.EnumerateArray()) + { + entries.Add(current.Deserialize()); + } + } + return (artifact, entries); + } } diff --git a/src/Playwright/Helpers/SetInputFilesHelpers.cs b/src/Playwright/Helpers/SetInputFilesHelpers.cs index c70d2c1d43..d56e9c2a5b 100644 --- a/src/Playwright/Helpers/SetInputFilesHelpers.cs +++ b/src/Playwright/Helpers/SetInputFilesHelpers.cs @@ -51,7 +51,11 @@ public static async Task ConvertInputFilesAsync(IEnumerable< { var lastModifiedMs = new DateTimeOffset(File.GetLastWriteTime(f)).ToUnixTimeMilliseconds(); #pragma warning disable CA2007 // Upstream bug: https://github.com/dotnet/roslyn-analyzers/issues/5712 - await using var stream = await context.Channel.CreateTempFileAsync(Path.GetFileName(f), lastModifiedMs).ConfigureAwait(false); + await using var stream = (await context.SendMessageToServerAsync("createTempFile", new Dictionary + { + { "name", Path.GetFileName(f) }, + { "lastModifiedMs", lastModifiedMs }, + }).ConfigureAwait(false)).GetObject("writableStream", context._connection); #pragma warning restore CA2007 using var fileStream = File.OpenRead(f); await fileStream.CopyToAsync(stream.WritableStreamImpl).ConfigureAwait(false); diff --git a/src/Playwright/Transport/Channels/APIRequestContextChannel.cs b/src/Playwright/Transport/Channels/APIRequestContextChannel.cs index 2cca0d4214..e7f26eb54e 100644 --- a/src/Playwright/Transport/Channels/APIRequestContextChannel.cs +++ b/src/Playwright/Transport/Channels/APIRequestContextChannel.cs @@ -22,11 +22,7 @@ * SOFTWARE. */ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Helpers; namespace Microsoft.Playwright.Transport.Channels; @@ -35,62 +31,4 @@ internal class APIRequestContextChannel : Channel public APIRequestContextChannel(string guid, Connection connection, APIRequestContext owner) : base(guid, connection, owner) { } - - internal Task DisposeAsync() => Connection.SendMessageToServerAsync(Object, "dispose"); - - internal async Task FetchAsync( - string url, - IEnumerable> parameters, - string method, - IEnumerable> headers, - object jsonData, - byte[] postData, - FormData formData, - FormData multipartData, - float? timeout, - bool? failOnStatusCode, - bool? ignoreHTTPSErrors, - int? maxRedirects) - { - var message = new Dictionary - { - ["url"] = url, - ["method"] = method, - ["failOnStatusCode"] = failOnStatusCode, - ["ignoreHTTPSErrors"] = ignoreHTTPSErrors, - ["maxRedirects"] = maxRedirects, - ["timeout"] = timeout, - ["params"] = parameters?.ToProtocol(), - ["headers"] = headers?.ToProtocol(), - ["jsonData"] = jsonData, - ["postData"] = postData != null ? Convert.ToBase64String(postData) : null, - ["formData"] = formData?.ToProtocol(throwWhenSerializingFilePayloads: true), - ["multipartData"] = multipartData?.ToProtocol(), - }; - - var response = await Connection.SendMessageToServerAsync(Object, "fetch", message).ConfigureAwait(false); - return new Core.APIResponse(Object, response?.GetProperty("response").ToObject()); - } - - internal Task StorageStateAsync() - => Connection.SendMessageToServerAsync(Object, "storageState", null); - - internal async Task FetchResponseBodyAsync(string fetchUid) - { - var response = await Connection.SendMessageToServerAsync(Object, "fetchResponseBody", new Dictionary { ["fetchUid"] = fetchUid }).ConfigureAwait(false); - if (response?.TryGetProperty("binary", out var binary) == true) - { - return binary.ToString(); - } - return null; - } - - internal async Task FetchResponseLogAsync(string fetchUid) - { - var response = await Connection.SendMessageToServerAsync(Object, "fetchLog", new Dictionary { ["fetchUid"] = fetchUid }).ConfigureAwait(false); - return response.Value.GetProperty("log").ToObject(); - } - - internal Task DisposeAPIResponseAsync(string fetchUid) - => Connection.SendMessageToServerAsync(Object, "disposeAPIResponse", new Dictionary { ["fetchUid"] = fetchUid }); } diff --git a/src/Playwright/Transport/Channels/ArtifactChannel.cs b/src/Playwright/Transport/Channels/ArtifactChannel.cs index 843d65ac64..bc8f0a6496 100644 --- a/src/Playwright/Transport/Channels/ArtifactChannel.cs +++ b/src/Playwright/Transport/Channels/ArtifactChannel.cs @@ -22,11 +22,7 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.Text.Json; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Helpers; namespace Microsoft.Playwright.Transport.Channels; @@ -35,51 +31,4 @@ internal class ArtifactChannel : Channel public ArtifactChannel(string guid, Connection connection, Artifact owner) : base(guid, connection, owner) { } - - internal async Task PathAfterFinishedAsync() - => (await Connection.SendMessageToServerAsync( - Object, - "pathAfterFinished", - null) - .ConfigureAwait(false)).GetString("value", true); - - internal Task SaveAsAsync(string path) - => Connection.SendMessageToServerAsync( - Object, - "saveAs", - new Dictionary - { - ["path"] = path, - }); - - internal async Task SaveAsStreamAsync() - => (await Connection.SendMessageToServerAsync( - Object, - "saveAsStream", - null) - .ConfigureAwait(false)).GetObject("stream", Connection); - - internal async Task FailureAsync() - => (await Connection.SendMessageToServerAsync( - Object, - "failure", - null) - .ConfigureAwait(false)).GetString("error", true); - - internal async Task StreamAsync() - => (await Connection.SendMessageToServerAsync( - Object, - "stream", - null) - .ConfigureAwait(false))?.GetObject("stream", Connection); - - internal Task CancelAsync() - => Connection.SendMessageToServerAsync( - Object, - "cancel"); - - internal Task DeleteAsync() - => Connection.SendMessageToServerAsync( - Object, - "delete"); } diff --git a/src/Playwright/Transport/Channels/BrowserChannel.cs b/src/Playwright/Transport/Channels/BrowserChannel.cs index 4e6661fb96..53cb05d091 100644 --- a/src/Playwright/Transport/Channels/BrowserChannel.cs +++ b/src/Playwright/Transport/Channels/BrowserChannel.cs @@ -22,15 +22,7 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.Json; -using System.Text.RegularExpressions; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Helpers; -using Microsoft.Playwright.Transport.Protocol; namespace Microsoft.Playwright.Transport.Channels; @@ -39,185 +31,4 @@ internal class BrowserChannel : Channel public BrowserChannel(string guid, Connection connection, Browser owner) : base(guid, connection, owner) { } - - internal static Dictionary PrepareHarOptions( - HarContentPolicy? recordHarContent, - HarMode? recordHarMode, - string recordHarPath, - bool? recordHarOmitContent, - string recordHarUrlFilter, - string recordHarUrlFilterString, - Regex recordHarUrlFilterRegex) - { - if (string.IsNullOrEmpty(recordHarPath)) - { - return null; - } - var recordHarArgs = new Dictionary(); - recordHarArgs["path"] = recordHarPath; - if (recordHarContent.HasValue) - { - recordHarArgs["content"] = recordHarContent; - } - else if (recordHarOmitContent == true) - { - recordHarArgs["content"] = HarContentPolicy.Omit; - } - if (!string.IsNullOrEmpty(recordHarUrlFilter)) - { - recordHarArgs["urlGlob"] = recordHarUrlFilter; - } - else if (!string.IsNullOrEmpty(recordHarUrlFilterString)) - { - recordHarArgs["urlGlob"] = recordHarUrlFilterString; - } - else if (recordHarUrlFilterRegex != null) - { - recordHarArgs["urlRegexSource"] = recordHarUrlFilterRegex.ToString(); - recordHarArgs["urlRegexFlags"] = recordHarUrlFilterRegex.Options.GetInlineFlags(); - } - if (recordHarMode.HasValue) - { - recordHarArgs["mode"] = recordHarMode; - } - - if (recordHarArgs.Keys.Count > 0) - { - return recordHarArgs; - } - return null; - } - - internal Task NewBrowserCDPSessionAsync() - => Connection.SendMessageToServerAsync( - Object, - "newBrowserCDPSession"); - - internal Task NewContextAsync( - bool? acceptDownloads = null, - bool? bypassCSP = null, - ColorScheme? colorScheme = null, - ReducedMotion? reducedMotion = null, - ForcedColors? forcedColors = null, - float? deviceScaleFactor = null, - IEnumerable> extraHTTPHeaders = null, - Geolocation geolocation = null, - bool? hasTouch = null, - HttpCredentials httpCredentials = null, - bool? ignoreHTTPSErrors = null, - bool? isMobile = null, - bool? javaScriptEnabled = null, - string locale = null, - bool? offline = null, - IEnumerable permissions = null, - Proxy proxy = null, - HarContentPolicy? recordHarContent = default, - HarMode? recordHarMode = default, - string recordHarPath = default, - bool? recordHarOmitContent = default, - string recordHarUrlFilter = default, - string recordHarUrlFilterString = default, - Regex recordHarUrlFilterRegex = default, - Dictionary recordVideo = null, - string storageState = null, - string storageStatePath = null, - ServiceWorkerPolicy? serviceWorkers = default, - string timezoneId = null, - string userAgent = null, - ViewportSize viewportSize = default, - ScreenSize screenSize = default, - string baseUrl = default, - bool? strictSelectors = default) - { - var args = new Dictionary - { - ["bypassCSP"] = bypassCSP, - ["deviceScaleFactor"] = deviceScaleFactor, - ["serviceWorkers"] = serviceWorkers, - ["geolocation"] = geolocation, - ["hasTouch"] = hasTouch, - ["httpCredentials"] = httpCredentials, - ["ignoreHTTPSErrors"] = ignoreHTTPSErrors, - ["isMobile"] = isMobile, - ["javaScriptEnabled"] = javaScriptEnabled, - ["locale"] = locale, - ["offline"] = offline, - ["permissions"] = permissions, - ["proxy"] = proxy, - ["strictSelectors"] = strictSelectors, - ["colorScheme"] = colorScheme == ColorScheme.Null ? "no-override" : colorScheme, - ["reducedMotion"] = reducedMotion == ReducedMotion.Null ? "no-override" : reducedMotion, - ["forcedColors"] = forcedColors == ForcedColors.Null ? "no-override" : forcedColors, - ["extraHTTPHeaders"] = extraHTTPHeaders?.Select(kv => new HeaderEntry { Name = kv.Key, Value = kv.Value }).ToArray(), - ["recordHar"] = PrepareHarOptions( - recordHarContent: recordHarContent, - recordHarMode: recordHarMode, - recordHarPath: recordHarPath, - recordHarOmitContent: recordHarOmitContent, - recordHarUrlFilter: recordHarUrlFilter, - recordHarUrlFilterString: recordHarUrlFilterString, - recordHarUrlFilterRegex: recordHarUrlFilterRegex), - ["recordVideo"] = recordVideo, - ["timezoneId"] = timezoneId, - ["userAgent"] = userAgent, - ["baseURL"] = baseUrl, - }; - - if (acceptDownloads.HasValue) - { - args.Add("acceptDownloads", acceptDownloads.Value ? "accept" : "deny"); - } - - - if (!string.IsNullOrEmpty(storageStatePath)) - { - if (!File.Exists(storageStatePath)) - { - throw new PlaywrightException($"The specified storage state file does not exist: {storageStatePath}"); - } - - storageState = File.ReadAllText(storageStatePath); - } - - if (!string.IsNullOrEmpty(storageState)) - { - args.Add("storageState", JsonSerializer.Deserialize(storageState, Helpers.JsonExtensions.DefaultJsonSerializerOptions)); - } - - if (viewportSize?.Width == -1) - { - args.Add("noDefaultViewport", true); - } - else - { - args.Add("viewport", viewportSize); - args.Add("screen", screenSize); - } - - return Connection.SendMessageToServerAsync( - Object, - "newContext", - args); - } - - internal Task CloseAsync(string reason) => Connection.SendMessageToServerAsync(Object, "close", new Dictionary - { - ["reason"] = reason, - }); - - internal Task StartTracingAsync(IPage page, bool screenshots, string path, IEnumerable categories) - { - var args = new Dictionary - { - ["screenshots"] = screenshots, - ["path"] = path, - ["page"] = page, - ["categories"] = categories, - }; - - return Connection.SendMessageToServerAsync(Object, "crStartTracing", args); - } - - internal async Task StopTracingAsync() - => (await Connection.SendMessageToServerAsync(Object, "crStopTracing").ConfigureAwait(false))?.GetProperty("binary").ToString(); } diff --git a/src/Playwright/Transport/Channels/BrowserContextChannel.cs b/src/Playwright/Transport/Channels/BrowserContextChannel.cs index 9d0a57c926..1059517b13 100644 --- a/src/Playwright/Transport/Channels/BrowserContextChannel.cs +++ b/src/Playwright/Transport/Channels/BrowserContextChannel.cs @@ -22,14 +22,7 @@ * SOFTWARE. */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Helpers; -using Microsoft.Playwright.Transport.Protocol; namespace Microsoft.Playwright.Transport.Channels; @@ -38,184 +31,4 @@ internal class BrowserContextChannel : Channel public BrowserContextChannel(string guid, Connection connection, BrowserContext owner) : base(guid, connection, owner) { } - - internal Task NewCDPSessionAsync(Page page) - => Connection.SendMessageToServerAsync( - Object, - "newCDPSession", - new Dictionary - { - ["page"] = new { guid = page.Guid }, - }); - - internal Task NewCDPSessionAsync(Frame frame) - => Connection.SendMessageToServerAsync( - Object, - "newCDPSession", - new Dictionary - { - ["frame"] = new { guid = frame.Guid }, - }); - - internal Task NewPageAsync() - => Connection.SendMessageToServerAsync( - Object, - "newPage", - null); - - internal Task CloseAsync(string reason) => Connection.SendMessageToServerAsync(Object, "close", new Dictionary - { - ["reason"] = reason, - }); - - internal Task PauseAsync() - => Connection.SendMessageToServerAsync(Object, "pause"); - - internal Task SetDefaultNavigationTimeoutNoReplyAsync(float? timeout) - => Connection.SendMessageToServerAsync( - Object, - "setDefaultNavigationTimeoutNoReply", - new Dictionary - { - ["timeout"] = timeout, - }); - - internal Task SetDefaultTimeoutNoReplyAsync(float? timeout) - => Connection.SendMessageToServerAsync( - Object, - "setDefaultTimeoutNoReply", - new Dictionary - { - ["timeout"] = timeout, - }); - - internal Task ExposeBindingAsync(string name, bool needsHandle) - => Connection.SendMessageToServerAsync( - Object, - "exposeBinding", - new Dictionary - { - ["name"] = name, - ["needsHandle"] = needsHandle, - }); - - internal Task AddInitScriptAsync(string script) - => Connection.SendMessageToServerAsync( - Object, - "addInitScript", - new Dictionary - { - ["source"] = script, - }); - - internal Task SetNetworkInterceptionPatternsAsync(Dictionary args) - => Connection.SendMessageToServerAsync( - Object, - "setNetworkInterceptionPatterns", - args); - - internal Task SetOfflineAsync(bool offline) - => Connection.SendMessageToServerAsync( - Object, - "setOffline", - new Dictionary - { - ["offline"] = offline, - }); - - internal async Task> CookiesAsync(IEnumerable urls) - { - return (await Connection.SendMessageToServerAsync( - Object, - "cookies", - new Dictionary - { - ["urls"] = urls?.ToArray() ?? Array.Empty(), - }).ConfigureAwait(false))?.GetProperty("cookies").ToObject>(); - } - - internal Task AddCookiesAsync(IEnumerable cookies) - => Connection.SendMessageToServerAsync( - Object, - "addCookies", - new Dictionary - { - ["cookies"] = cookies, - }); - - internal Task GrantPermissionsAsync(IEnumerable permissions, string origin) - { - var args = new Dictionary - { - ["permissions"] = permissions?.ToArray(), - ["origin"] = origin, - }; - return Connection.SendMessageToServerAsync(Object, "grantPermissions", args); - } - - internal Task ClearPermissionsAsync() => Connection.SendMessageToServerAsync(Object, "clearPermissions"); - - internal Task SetGeolocationAsync(Geolocation geolocation) - => Connection.SendMessageToServerAsync( - Object, - "setGeolocation", - new Dictionary - { - ["geolocation"] = geolocation, - }); - - internal Task ClearCookiesAsync() => Connection.SendMessageToServerAsync(Object, "clearCookies"); - - internal Task SetExtraHTTPHeadersAsync(IEnumerable> headers) - => Connection.SendMessageToServerAsync( - Object, - "setExtraHTTPHeaders", - new Dictionary - { - ["headers"] = headers.Select(kv => new HeaderEntry { Name = kv.Key, Value = kv.Value }), - }); - - internal Task GetStorageStateAsync() - => Connection.SendMessageToServerAsync(Object, "storageState", null); - - internal async Task HarExportAsync(string harId) - { - var result = await Connection.SendMessageToServerAsync( - Object, - "harExport", - new Dictionary - { - ["harId"] = harId, - }).ConfigureAwait(false); - return result.GetObject("artifact", Connection); - } - - internal async Task HarStartAsync( - Page page, - string path, - string recordHarUrlFilter, - string recordHarUrlFilterString, - Regex recordHarUrlFilterRegex, - HarContentPolicy? harContentPolicy, - HarMode? harMode) - { - var args = new Dictionary - { - { "page", page?.Channel }, - { "options", BrowserChannel.PrepareHarOptions(harContentPolicy ?? HarContentPolicy.Attach, harMode ?? HarMode.Minimal, path, null, recordHarUrlFilter, recordHarUrlFilterString, recordHarUrlFilterRegex) }, - }; - var result = await Connection.SendMessageToServerAsync(Object, "harStart", args).ConfigureAwait(false); - return result.GetString("harId", false); - } - - internal async Task CreateTempFileAsync(string name, long lastModifiedMs) - { - var args = new Dictionary - { - { "name", name }, - { "lastModifiedMs", lastModifiedMs }, - }; - var result = await Connection.SendMessageToServerAsync(Object, "createTempFile", args).ConfigureAwait(false); - return result.GetObject("writableStream", Connection); - } } diff --git a/src/Playwright/Transport/Channels/BrowserTypeChannel.cs b/src/Playwright/Transport/Channels/BrowserTypeChannel.cs index d82430f998..bcf3e13fc0 100644 --- a/src/Playwright/Transport/Channels/BrowserTypeChannel.cs +++ b/src/Playwright/Transport/Channels/BrowserTypeChannel.cs @@ -22,12 +22,6 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.Text.Json; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.Playwright.Helpers; - namespace Microsoft.Playwright.Transport.Channels; internal class BrowserTypeChannel : Channel @@ -35,186 +29,4 @@ internal class BrowserTypeChannel : Channel public BrowserTypeChannel(string guid, Connection connection, Core.BrowserType owner) : base(guid, connection, owner) { } - - public Task LaunchAsync( - bool? headless = default, - string channel = default, - string executablePath = default, - IEnumerable passedArguments = default, - Proxy proxy = default, - string downloadsPath = default, - string tracesDir = default, - bool? chromiumSandbox = default, - IEnumerable> firefoxUserPrefs = default, - bool? handleSIGINT = default, - bool? handleSIGTERM = default, - bool? handleSIGHUP = default, - float? timeout = default, - IEnumerable> env = default, - bool? devtools = default, - float? slowMo = default, - IEnumerable ignoreDefaultArgs = default, - bool? ignoreAllDefaultArgs = default) - { - var args = new Dictionary - { - { "channel", channel }, - { "executablePath", executablePath }, - { "args", passedArguments }, - { "ignoreAllDefaultArgs", ignoreAllDefaultArgs }, - { "ignoreDefaultArgs", ignoreDefaultArgs }, - { "handleSIGHUP", handleSIGHUP }, - { "handleSIGINT", handleSIGINT }, - { "handleSIGTERM", handleSIGTERM }, - { "headless", headless }, - { "devtools", devtools }, - { "env", env.ToProtocol() }, - { "proxy", proxy }, - { "downloadsPath", downloadsPath }, - { "tracesDir", tracesDir }, - { "firefoxUserPrefs", firefoxUserPrefs }, - { "chromiumSandbox", chromiumSandbox }, - { "slowMo", slowMo }, - { "timeout", timeout }, - }; - - return Connection.SendMessageToServerAsync( - Object, - "launch", - args); - } - - internal Task LaunchPersistentContextAsync( - string userDataDir, - bool? headless = default, - string channel = default, - string executablePath = default, - IEnumerable args = default, - Proxy proxy = default, - string downloadsPath = default, - string tracesDir = default, - bool? chromiumSandbox = default, - IEnumerable> firefoxUserPrefs = default, - bool? handleSIGINT = default, - bool? handleSIGTERM = default, - bool? handleSIGHUP = default, - float? timeout = default, - IEnumerable> env = default, - bool? devtools = default, - float? slowMo = default, - bool? acceptDownloads = default, - bool? ignoreHTTPSErrors = default, - bool? bypassCSP = default, - ViewportSize viewportSize = default, - ScreenSize screenSize = default, - string userAgent = default, - float? deviceScaleFactor = default, - bool? isMobile = default, - bool? hasTouch = default, - bool? javaScriptEnabled = default, - string timezoneId = default, - Geolocation geolocation = default, - string locale = default, - IEnumerable permissions = default, - IEnumerable> extraHTTPHeaders = default, - bool? offline = default, - HttpCredentials httpCredentials = default, - ColorScheme? colorScheme = default, - ReducedMotion? reducedMotion = default, - ForcedColors? forcedColors = default, - HarContentPolicy? recordHarContent = default, - HarMode? recordHarMode = default, - string recordHarPath = default, - bool? recordHarOmitContent = default, - string recordHarUrlFilter = default, - string recordHarUrlFilterString = default, - Regex recordHarUrlFilterRegex = default, - Dictionary recordVideo = default, - ServiceWorkerPolicy? serviceWorkers = default, - IEnumerable ignoreDefaultArgs = default, - bool? ignoreAllDefaultArgs = default, - string baseUrl = default, - bool? strictSelectors = default) - { - var channelArgs = new Dictionary - { - ["userDataDir"] = userDataDir, - ["headless"] = headless, - ["channel"] = channel, - ["executablePath"] = executablePath, - ["args"] = args, - ["downloadsPath"] = downloadsPath, - ["tracesDir"] = tracesDir, - ["proxy"] = proxy, - ["chromiumSandbox"] = chromiumSandbox, - ["firefoxUserPrefs"] = firefoxUserPrefs, - ["handleSIGINT"] = handleSIGINT, - ["handleSIGTERM"] = handleSIGTERM, - ["handleSIGHUP"] = handleSIGHUP, - ["timeout"] = timeout, - ["env"] = env.ToProtocol(), - ["devtools"] = devtools, - ["slowMo"] = slowMo, - ["ignoreHTTPSErrors"] = ignoreHTTPSErrors, - ["bypassCSP"] = bypassCSP, - ["strictSelectors"] = strictSelectors, - ["serviceWorkers"] = serviceWorkers, - ["screensize"] = screenSize, - ["userAgent"] = userAgent, - ["deviceScaleFactor"] = deviceScaleFactor, - ["isMobile"] = isMobile, - ["hasTouch"] = hasTouch, - ["javaScriptEnabled"] = javaScriptEnabled, - ["timezoneId"] = timezoneId, - ["geolocation"] = geolocation, - ["locale"] = locale, - ["permissions"] = permissions, - ["extraHTTPHeaders"] = extraHTTPHeaders.ToProtocol(), - ["offline"] = offline, - ["httpCredentials"] = httpCredentials, - ["colorScheme"] = colorScheme == ColorScheme.Null ? "no-override" : colorScheme, - ["reducedMotion"] = reducedMotion == ReducedMotion.Null ? "no-override" : reducedMotion, - ["forcedColors"] = forcedColors == ForcedColors.Null ? "no-override" : forcedColors, - ["recordVideo"] = recordVideo, - ["ignoreDefaultArgs"] = ignoreDefaultArgs, - ["ignoreAllDefaultArgs"] = ignoreAllDefaultArgs, - ["baseURL"] = baseUrl, - ["recordHar"] = BrowserChannel.PrepareHarOptions( - recordHarContent: recordHarContent, - recordHarMode: recordHarMode, - recordHarPath: recordHarPath, - recordHarOmitContent: recordHarOmitContent, - recordHarUrlFilter: recordHarUrlFilter, - recordHarUrlFilterString: recordHarUrlFilterString, - recordHarUrlFilterRegex: recordHarUrlFilterRegex), - }; - - if (acceptDownloads.HasValue) - { - channelArgs.Add("acceptDownloads", acceptDownloads.Value ? "accept" : "deny"); - } - - if (viewportSize?.Width == -1) - { - channelArgs.Add("noDefaultViewport", true); - } - else - { - channelArgs.Add("viewport", viewportSize); - } - - return Connection.SendMessageToServerAsync(Object, "launchPersistentContext", channelArgs); - } - - internal Task ConnectOverCDPAsync(string endpointURL, IEnumerable> headers = default, float? slowMo = default, float? timeout = default) - { - var channelArgs = new Dictionary - { - { "endpointURL", endpointURL }, - { "headers", headers.ToProtocol() }, - { "slowMo", slowMo }, - { "timeout", timeout }, - }; - return Connection.SendMessageToServerAsync(Object, "connectOverCDP", channelArgs); - } } diff --git a/src/Playwright/Transport/Channels/JSHandleChannel.cs b/src/Playwright/Transport/Channels/JSHandleChannel.cs index 118be748fc..cce86cec0f 100644 --- a/src/Playwright/Transport/Channels/JSHandleChannel.cs +++ b/src/Playwright/Transport/Channels/JSHandleChannel.cs @@ -22,11 +22,7 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.Text.Json; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Helpers; namespace Microsoft.Playwright.Transport.Channels; @@ -35,48 +31,4 @@ internal class JSHandleChannel : Channel public JSHandleChannel(string guid, Connection connection, JSHandle owner) : base(guid, connection, owner) { } - - internal Task EvaluateExpressionAsync(string script, object arg) - => Connection.SendMessageToServerAsync( - Object, - "evaluateExpression", - new Dictionary - { - ["expression"] = script, - ["arg"] = arg, - }); - - internal Task EvaluateExpressionHandleAsync(string script, object arg) - => Connection.SendMessageToServerAsync( - Object, - "evaluateExpressionHandle", - new Dictionary - { - ["expression"] = script, - ["arg"] = arg, - }); - - internal Task JsonValueAsync() => Connection.SendMessageToServerAsync(Object, "jsonValue"); - - internal Task DisposeAsync() => Connection.SendMessageToServerAsync(Object, "dispose"); - - internal Task GetPropertyAsync(string propertyName) - => Connection.SendMessageToServerAsync( - Object, - "getProperty", - new Dictionary - { - ["name"] = propertyName, - }); - - internal async Task> GetPropertiesAsync() - => (await Connection.SendMessageToServerAsync(Object, "getPropertyList").ConfigureAwait(false))? - .GetProperty("properties").ToObject>(Connection.DefaultJsonSerializerOptions); - - internal class JSElementProperty - { - public string Name { get; set; } - - public JSHandleChannel Value { get; set; } - } } diff --git a/src/Playwright/Transport/Channels/LocalUtilsChannel.cs b/src/Playwright/Transport/Channels/LocalUtilsChannel.cs index fa917635dc..7cd10a43be 100644 --- a/src/Playwright/Transport/Channels/LocalUtilsChannel.cs +++ b/src/Playwright/Transport/Channels/LocalUtilsChannel.cs @@ -22,12 +22,7 @@ * SOFTWARE. */ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Helpers; -using Microsoft.Playwright.Transport.Protocol; namespace Microsoft.Playwright.Transport.Channels; @@ -36,97 +31,4 @@ internal class LocalUtilsChannel : Channel public LocalUtilsChannel(string guid, Connection connection, LocalUtils owner) : base(guid, connection, owner) { } - - internal Task ZipAsync(string zipFile, List entries, string mode, string stacksId, bool includeSources) => - Connection.SendMessageToServerAsync(Object, "zip", new Dictionary - { - { "zipFile", zipFile }, - { "entries", entries }, - { "mode", mode }, - { "stacksId", stacksId }, - { "includeSources", includeSources }, - }); - - internal async Task<(string HarId, string Error)> HarOpenAsync(string file) - { - var response = await Connection.SendMessageToServerAsync(Object, "harOpen", new Dictionary - { - { "file", file }, - }).ConfigureAwait(false); - return (response.GetString("harId", true), response.GetString("error", true)); - } - - internal async Task HarLookupAsync( - string harId, - string url, - string method, - List
headers, - byte[] postData, - bool isNavigationRequest) - { - var response = await Connection.SendMessageToServerAsync(Object, "harLookup", new Dictionary - { - { "harId", harId }, - { "url", url }, - { "method", method }, - { "headers", headers }, - { "postData", postData != null ? Convert.ToBase64String(postData) : null }, - { "isNavigationRequest", isNavigationRequest }, - }).ConfigureAwait(false); - return response; - } - - internal Task HarCloseAsync(string harId) => - Connection.SendMessageToServerAsync(Object, "HarCloseAsync", new Dictionary - { - { "harId", harId }, - }); - - internal Task HarUnzipAsync(string zipFile, string harFile) => - Connection.SendMessageToServerAsync(Object, "harUnzip", new Dictionary - { - { "zipFile", zipFile }, - { "harFile", harFile }, - }); - - internal async Task ConnectAsync(string wsEndpoint, IEnumerable> headers, float? slowMo, float? timeout, string exposeNetwork) - { - var args = new Dictionary - { - { "wsEndpoint", wsEndpoint }, - { "headers", headers }, - { "slowMo", slowMo }, - { "timeout", timeout }, - { "exposeNetwork", exposeNetwork }, - }; - return (await Connection.SendMessageToServerAsync(Object, "connect", args).ConfigureAwait(false)).Value.GetObject("pipe", Connection); - } - - internal void AddStackToTracingNoReply(List frames, int id) - => Connection.SendMessageToServerAsync(Object, "addStackToTracingNoReply", new Dictionary - { - { - "callData", new ClientSideCallMetadata() - { - Id = id, - Stack = frames, - } - }, - }).IgnoreException(); - - internal Task TraceDiscardedAsync(string stacksId) - => Connection.SendMessageToServerAsync(Object, "traceDiscarded", new Dictionary - { - { "stacksId", stacksId }, - }); - - internal async Task TracingStartedAsync(string tracesDir, string traceName) - { - var response = await Connection.SendMessageToServerAsync(Object, "tracingStarted", new Dictionary - { - { "tracesDir", tracesDir }, - { "traceName", traceName }, - }).ConfigureAwait(false); - return response.GetString("stacksId", true); - } } diff --git a/src/Playwright/Transport/Channels/PlaywrightChannel.cs b/src/Playwright/Transport/Channels/PlaywrightChannel.cs index ca50a602a4..763dac68fc 100644 --- a/src/Playwright/Transport/Channels/PlaywrightChannel.cs +++ b/src/Playwright/Transport/Channels/PlaywrightChannel.cs @@ -22,12 +22,7 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.IO; -using System.Text.Json; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Helpers; namespace Microsoft.Playwright.Transport.Channels; @@ -36,46 +31,4 @@ internal class PlaywrightChannel : Channel public PlaywrightChannel(string guid, Connection connection, PlaywrightImpl owner) : base(guid, connection, owner) { } - - internal async Task NewRequestAsync( - string baseURL, - string userAgent, - bool? ignoreHTTPSErrors, - IEnumerable> extraHTTPHeaders, - HttpCredentials httpCredentials = null, - Proxy proxy = null, - float? timeout = null, - string storageState = null, - string storageStatePath = null) - { - var args = new Dictionary() - { - ["baseURL"] = baseURL, - ["userAgent"] = userAgent, - ["ignoreHTTPSErrors"] = ignoreHTTPSErrors, - ["extraHTTPHeaders"] = extraHTTPHeaders?.ToProtocol(), - ["httpCredentials"] = httpCredentials, - ["proxy"] = proxy, - ["timeout"] = timeout, - }; - if (!string.IsNullOrEmpty(storageStatePath)) - { - if (!File.Exists(storageStatePath)) - { - throw new PlaywrightException($"The specified storage state file does not exist: {storageStatePath}"); - } - - storageState = File.ReadAllText(storageStatePath); - } - if (!string.IsNullOrEmpty(storageState)) - { - args.Add("storageState", JsonSerializer.Deserialize(storageState, Helpers.JsonExtensions.DefaultJsonSerializerOptions)); - } - - var response = await Connection.SendMessageToServerAsync( - Object, - "newRequest", - args).ConfigureAwait(false); - return response.Object; - } } diff --git a/src/Playwright/Transport/Channels/TracingChannel.cs b/src/Playwright/Transport/Channels/TracingChannel.cs index 49917a4048..c149c6369e 100644 --- a/src/Playwright/Transport/Channels/TracingChannel.cs +++ b/src/Playwright/Transport/Channels/TracingChannel.cs @@ -22,12 +22,7 @@ * SOFTWARE. */ -using System.Collections.Generic; -using System.Text.Json; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Helpers; -using Microsoft.Playwright.Transport.Protocol; namespace Microsoft.Playwright.Transport.Channels; @@ -36,48 +31,4 @@ internal class TracingChannel : Channel public TracingChannel(string guid, Connection connection, Tracing owner) : base(guid, connection, owner) { } - - internal Task TracingStartAsync(string name, string title, bool? screenshots, bool? snapshots, bool? sources) - => Connection.SendMessageToServerAsync( - Object, - "tracingStart", - new Dictionary - { - ["name"] = name, - ["title"] = title, - ["screenshots"] = screenshots, - ["snapshots"] = snapshots, - ["sources"] = sources, - }); - - internal Task TracingStopAsync() - => Connection.SendMessageToServerAsync( - Object, - "tracingStop"); - - internal async Task StartChunkAsync(string title = null, string name = null) - => (await Connection.SendMessageToServerAsync(Object, "tracingStartChunk", new Dictionary - { - ["title"] = title, - ["name"] = name, - }).ConfigureAwait(false))?.GetProperty("traceName").ToString(); - - internal async Task<(Artifact Artifact, List Entries)> TracingStopChunkAsync(string mode) - { - var result = await Connection.SendMessageToServerAsync(Object, "tracingStopChunk", new Dictionary - { - ["mode"] = mode, - }).ConfigureAwait(false); - - var artifact = result.GetObject("artifact", Connection); - List entries = new(); - if (result.Value.TryGetProperty("entries", out var entriesElement)) - { - foreach (var current in entriesElement.EnumerateArray()) - { - entries.Add(current.Deserialize()); - } - } - return (artifact, entries); - } } From 9ab4d90e46cd8b1ab9426db766b5c30c1cb4a862 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Sat, 9 Dec 2023 12:40:12 -0800 Subject: [PATCH 3/4] more --- src/Playwright/Core/Accessibility.cs | 13 +- src/Playwright/Core/Keyboard.cs | 41 ++- src/Playwright/Core/Mouse.cs | 56 ++- src/Playwright/Core/Page.cs | 136 +++++--- src/Playwright/Core/Touchscreen.cs | 10 +- .../Transport/Channels/PageChannel.cs | 324 ------------------ 6 files changed, 203 insertions(+), 377 deletions(-) diff --git a/src/Playwright/Core/Accessibility.cs b/src/Playwright/Core/Accessibility.cs index a9ba4df3af..474cc36280 100644 --- a/src/Playwright/Core/Accessibility.cs +++ b/src/Playwright/Core/Accessibility.cs @@ -22,6 +22,7 @@ * SOFTWARE. */ +using System.Collections.Generic; using System.Text.Json; using System.Threading.Tasks; using Microsoft.Playwright.Transport.Channels; @@ -37,9 +38,17 @@ public Accessibility(PageChannel channel) _channel = channel; } - public Task SnapshotAsync(AccessibilitySnapshotOptions options = default) + public async Task SnapshotAsync(AccessibilitySnapshotOptions options = default) { options ??= new(); - return _channel.AccessibilitySnapshotAsync(options.InterestingOnly, (options.Root as ElementHandle)?.ElementChannel); + if ((await _channel.Object.SendMessageToServerAsync("accessibilitySnapshot", new Dictionary + { + ["interestingOnly"] = options?.InterestingOnly, + ["root"] = (options.Root as ElementHandle)?.ElementChannel, + }).ConfigureAwait(false)).Value.TryGetProperty("rootAXNode", out var jsonElement)) + { + return jsonElement; + } + return null; } } diff --git a/src/Playwright/Core/Keyboard.cs b/src/Playwright/Core/Keyboard.cs index ac2c4bd14d..ddbb027f5d 100644 --- a/src/Playwright/Core/Keyboard.cs +++ b/src/Playwright/Core/Keyboard.cs @@ -22,6 +22,7 @@ * SOFTWARE. */ +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Playwright.Transport.Channels; @@ -36,15 +37,45 @@ public Keyboard(PageChannel channel) _channel = channel; } - public Task DownAsync(string key) => _channel.KeyboardDownAsync(key); + public Task DownAsync(string key) + => _channel.Object.SendMessageToServerAsync( + "keyboardDown", + new Dictionary + { + ["key"] = key, + }); - public Task UpAsync(string key) => _channel.KeyboardUpAsync(key); + public Task UpAsync(string key) + => _channel.Object.SendMessageToServerAsync( + "keyboardUp", + new Dictionary + { + ["key"] = key, + }); public Task PressAsync(string key, KeyboardPressOptions options = default) - => _channel.PressAsync(key, options?.Delay); + => _channel.Object.SendMessageToServerAsync( + "keyboardPress", + new Dictionary + { + ["key"] = key, + ["delay"] = options?.Delay, + }); public Task TypeAsync(string text, KeyboardTypeOptions options = default) - => _channel.TypeAsync(text, options?.Delay); + => _channel.Object.SendMessageToServerAsync( + "keyboardType", + new Dictionary + { + ["text"] = text, + ["delay"] = options?.Delay, + }); - public Task InsertTextAsync(string text) => _channel.InsertTextAsync(text); + public Task InsertTextAsync(string text) + => _channel.Object.SendMessageToServerAsync( + "keyboardInsertText", + new Dictionary + { + ["text"] = text, + }); } diff --git a/src/Playwright/Core/Mouse.cs b/src/Playwright/Core/Mouse.cs index 90d43a4b1c..5ce2a1a20a 100644 --- a/src/Playwright/Core/Mouse.cs +++ b/src/Playwright/Core/Mouse.cs @@ -22,6 +22,7 @@ * SOFTWARE. */ +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Playwright.Transport.Channels; @@ -37,20 +38,63 @@ public Mouse(PageChannel channel) } public Task ClickAsync(float x, float y, MouseClickOptions options = default) - => _channel.MouseClickAsync(x, y, delay: options?.Delay, button: options?.Button, clickCount: options?.ClickCount); + => _channel.Object.SendMessageToServerAsync( + "mouseClick", + new Dictionary + { + ["x"] = x, + ["y"] = y, + ["delay"] = options?.Delay, + ["button"] = options?.Button, + ["clickCount"] = options?.ClickCount, + }); public Task DblClickAsync(float x, float y, MouseDblClickOptions options = default) - => _channel.MouseClickAsync(x, y, delay: options?.Delay, button: options?.Button, 2); + => _channel.Object.SendMessageToServerAsync( + "mouseClick", + new Dictionary + { + ["x"] = x, + ["y"] = y, + ["delay"] = options?.Delay, + ["button"] = options?.Button, + ["clickCount"] = 2, + }); public Task DownAsync(MouseDownOptions options = default) - => _channel.MouseDownAsync(button: options?.Button, clickCount: options?.ClickCount); + => _channel.Object.SendMessageToServerAsync( + "mouseDown", + new Dictionary + { + ["button"] = options?.Button, + ["clickCount"] = options?.ClickCount, + }); public Task MoveAsync(float x, float y, MouseMoveOptions options = default) - => _channel.MouseMoveAsync(x, y, steps: options?.Steps); + => _channel.Object.SendMessageToServerAsync( + "mouseMove", + new Dictionary + { + ["x"] = x, + ["y"] = y, + ["steps"] = options?.Steps, + }); public Task UpAsync(MouseUpOptions options = default) - => _channel.MouseUpAsync(button: options?.Button, clickCount: options?.ClickCount); + => _channel.Object.SendMessageToServerAsync( + "mouseUp", + new Dictionary + { + ["button"] = options?.Button, + ["clickCount"] = options?.ClickCount, + }); public Task WheelAsync(float deltaX, float deltaY) - => _channel.MouseWheelAsync(deltaX, deltaY); + => _channel.Object.SendMessageToServerAsync( + "mouseWheel", + new Dictionary + { + ["deltaX"] = deltaX, + ["deltaY"] = deltaY, + }); } diff --git a/src/Playwright/Core/Page.cs b/src/Playwright/Core/Page.cs index 09197d13a0..24af6dac04 100644 --- a/src/Playwright/Core/Page.cs +++ b/src/Playwright/Core/Page.cs @@ -301,7 +301,7 @@ public IFrame Frame(string name) public Task TitleAsync() => MainFrame.TitleAsync(); [MethodImpl(MethodImplOptions.NoInlining)] - public Task BringToFrontAsync() => _channel.BringToFrontAsync(); + public Task BringToFrontAsync() => SendMessageToServerAsync("bringToFront"); [MethodImpl(MethodImplOptions.NoInlining)] public Task OpenerAsync() => Task.FromResult(Opener?.IsClosed == false ? Opener : null); @@ -316,7 +316,7 @@ public Task EmulateMediaAsync(PageEmulateMediaOptions options = default) ["reducedMotion"] = options?.ReducedMotion == ReducedMotion.Null ? "no-override" : options?.ReducedMotion, ["forcedColors"] = options?.ForcedColors == ForcedColors.Null ? "no-override" : options?.ForcedColors, }; - return _channel.EmulateMediaAsync(args); + return SendMessageToServerAsync("emulateMedia", args); } [MethodImpl(MethodImplOptions.NoInlining)] @@ -510,7 +510,12 @@ public async Task CloseAsync(PageCloseOptions options = default) _closeReason = options?.Reason; try { - await _channel.CloseAsync(options?.RunBeforeUnload ?? false).ConfigureAwait(false); + await SendMessageToServerAsync( + "close", + new Dictionary + { + ["runBeforeUnload"] = options?.RunBeforeUnload ?? false, + }).ConfigureAwait(false); if (OwnedContext != null) { await OwnedContext.CloseAsync().ConfigureAwait(false); @@ -681,19 +686,25 @@ public async Task ScreenshotAsync(PageScreenshotOptions options = defaul options.Type = ElementHandle.DetermineScreenshotType(options.Path); } - byte[] result = await _channel.ScreenshotAsync( - path: options.Path, - fullPage: options.FullPage, - clip: options.Clip, - omitBackground: options.OmitBackground, - type: options.Type, - quality: options.Quality, - mask: options.Mask, - maskColor: options.MaskColor, - animations: options.Animations, - caret: options.Caret, - scale: options.Scale, - timeout: options.Timeout).ConfigureAwait(false); + var result = (await SendMessageToServerAsync("screenshot", new Dictionary + { + ["fullPage"] = options.FullPage, + ["omitBackground"] = options.OmitBackground, + ["clip"] = options.Clip, + ["path"] = options.Path, + ["type"] = options.Type, + ["timeout"] = options.Timeout, + ["animations"] = options.Animations, + ["caret"] = options.Caret, + ["scale"] = options.Scale, + ["quality"] = options.Quality, + ["maskColor"] = options.MaskColor, + ["mask"] = options.Mask?.Select(locator => new Dictionary + { + ["frame"] = ((Locator)locator)._frame._channel, + ["selector"] = ((Locator)locator)._selector, + }).ToArray(), + }).ConfigureAwait(false))?.GetProperty("binary").GetBytesFromBase64(); if (!string.IsNullOrEmpty(options.Path)) { @@ -713,7 +724,12 @@ public Task SetContentAsync(string html, PageSetContentOptions options = default [MethodImpl(MethodImplOptions.NoInlining)] public Task SetExtraHTTPHeadersAsync(IEnumerable> headers) - => _channel.SetExtraHTTPHeadersAsync(headers); + => SendMessageToServerAsync( + "setExtraHTTPHeaders", + new Dictionary + { + ["headers"] = headers.Select(kv => new HeaderEntry { Name = kv.Key, Value = kv.Value }), + }); [MethodImpl(MethodImplOptions.NoInlining)] public Task QuerySelectorAsync(string selector) => MainFrame.QuerySelectorAsync(selector); @@ -779,15 +795,27 @@ public Task DblClickAsync(string selector, PageDblClickOptions options = default [MethodImpl(MethodImplOptions.NoInlining)] public async Task GoBackAsync(PageGoBackOptions options = default) - => (await _channel.GoBackAsync(options?.Timeout, options?.WaitUntil).ConfigureAwait(false))?.Object; + => (await SendMessageToServerAsync("goBack", new Dictionary + { + ["timeout"] = options?.Timeout, + ["waitUntil"] = options?.WaitUntil, + }).ConfigureAwait(false))?.Object; [MethodImpl(MethodImplOptions.NoInlining)] public async Task GoForwardAsync(PageGoForwardOptions options = default) - => (await _channel.GoForwardAsync(options?.Timeout, options?.WaitUntil).ConfigureAwait(false))?.Object; + => (await SendMessageToServerAsync("goForward", new Dictionary + { + ["timeout"] = options?.Timeout, + ["waitUntil"] = options?.WaitUntil, + }).ConfigureAwait(false))?.Object; [MethodImpl(MethodImplOptions.NoInlining)] public async Task ReloadAsync(PageReloadOptions options = default) - => (await _channel.ReloadAsync(options?.Timeout, options?.WaitUntil).ConfigureAwait(false))?.Object; + => (await SendMessageToServerAsync("reload", new Dictionary + { + ["timeout"] = options?.Timeout, + ["waitUntil"] = options?.WaitUntil, + }).ConfigureAwait(false))?.Object; [MethodImpl(MethodImplOptions.NoInlining)] public Task ExposeBindingAsync(string name, Action callback, PageExposeBindingOptions options = default) @@ -861,19 +889,21 @@ public async Task PdfAsync(PagePdfOptions options = default) throw new NotSupportedException("This browser doesn't support this action."); } - byte[] result = await _channel.PdfAsync( - scale: options?.Scale, - displayHeaderFooter: options?.DisplayHeaderFooter, - headerTemplate: options?.HeaderTemplate, - footerTemplate: options?.FooterTemplate, - printBackground: options?.PrintBackground, - landscape: options?.Landscape, - pageRanges: options?.PageRanges, - format: options?.Format, - width: options?.Width, - height: options?.Height, - margin: options?.Margin, - preferCSSPageSize: options?.PreferCSSPageSize).ConfigureAwait(false); + byte[] result = (await SendMessageToServerAsync("pdf", new Dictionary + { + ["scale"] = options.Scale, + ["displayHeaderFooter"] = options.DisplayHeaderFooter, + ["printBackground"] = options.PrintBackground, + ["landscape"] = options.Landscape, + ["preferCSSPageSize"] = options.PreferCSSPageSize, + ["pageRanges"] = options.PageRanges, + ["headerTemplate"] = options.HeaderTemplate, + ["footerTemplate"] = options.FooterTemplate, + ["margin"] = options.Margin, + ["width"] = options.Width, + ["format"] = options.Format, + ["height"] = options.Height, + }).ConfigureAwait(false))?.GetProperty("pdf").GetBytesFromBase64(); if (!string.IsNullOrEmpty(options?.Path)) { @@ -886,7 +916,12 @@ public async Task PdfAsync(PagePdfOptions options = default) [MethodImpl(MethodImplOptions.NoInlining)] public Task AddInitScriptAsync(string script, string scriptPath) - => _channel.AddInitScriptAsync(ScriptsHelper.EvaluationScript(script, scriptPath)); + => SendMessageToServerAsync( + "addInitScript", + new Dictionary + { + ["source"] = ScriptsHelper.EvaluationScript(script, scriptPath), + }); [MethodImpl(MethodImplOptions.NoInlining)] public Task RouteAsync(string url, Func handler, PageRouteOptions options = null) @@ -944,7 +979,12 @@ public Task WaitForLoadStateAsync(LoadState? state = default, PageWaitForLoadSta public Task SetViewportSizeAsync(int width, int height) { ViewportSize = new() { Width = width, Height = height }; - return _channel.SetViewportSizeAsync(ViewportSize); + return SendMessageToServerAsync( + "setViewportSize", + new Dictionary + { + ["viewportSize"] = ViewportSize, + }); } [MethodImpl(MethodImplOptions.NoInlining)] @@ -1116,14 +1156,26 @@ public async Task PauseAsync() public void SetDefaultNavigationTimeout(float timeout) { _timeoutSettings.SetDefaultNavigationTimeout(timeout); - WrapApiCallAsync(() => Channel.SetDefaultNavigationTimeoutNoReplyAsync(timeout), true).IgnoreException(); + WrapApiCallAsync( + () => SendMessageToServerAsync( + "setDefaultNavigationTimeoutNoReply", + new Dictionary + { + ["timeout"] = timeout, + }), + true).IgnoreException(); } [MethodImpl(MethodImplOptions.NoInlining)] public void SetDefaultTimeout(float timeout) { _timeoutSettings.SetDefaultTimeout(timeout); - WrapApiCallAsync(() => Channel.SetDefaultTimeoutNoReplyAsync(timeout), true).IgnoreException(); + WrapApiCallAsync( + () => SendMessageToServerAsync("setDefaultTimeoutNoReply", new Dictionary + { + ["timeout"] = timeout, + }), + true).IgnoreException(); } [MethodImpl(MethodImplOptions.NoInlining)] @@ -1209,7 +1261,7 @@ private Task UnrouteAsync(RouteHandler setting) private Task UpdateInterceptionAsync() { var patterns = RouteHandler.PrepareInterceptionPatterns(_routes); - return Channel.SetNetworkInterceptionPatternsAsync(patterns); + return SendMessageToServerAsync("setNetworkInterceptionPatterns", patterns); } internal void OnClose() @@ -1291,7 +1343,13 @@ private Task InnerExposeBindingAsync(string name, Delegate callback, bool handle Bindings.Add(name, callback); - return _channel.ExposeBindingAsync(name, handle); + return SendMessageToServerAsync( + "exposeBinding", + new Dictionary + { + ["name"] = name, + ["needsHandle"] = handle, + }); } private Video ForceVideo() => _video ??= new(this, _channel.Connection); diff --git a/src/Playwright/Core/Touchscreen.cs b/src/Playwright/Core/Touchscreen.cs index 8540156224..8708185ce8 100644 --- a/src/Playwright/Core/Touchscreen.cs +++ b/src/Playwright/Core/Touchscreen.cs @@ -21,6 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Playwright.Transport.Channels; @@ -35,5 +36,12 @@ public Touchscreen(PageChannel channel) _channel = channel; } - public Task TapAsync(float x, float y) => _channel.TouchscreenTapAsync(x, y); + public Task TapAsync(float x, float y) + => _channel.Object.SendMessageToServerAsync( + "touchscreenTap", + new Dictionary + { + ["x"] = x, + ["y"] = y, + }); } diff --git a/src/Playwright/Transport/Channels/PageChannel.cs b/src/Playwright/Transport/Channels/PageChannel.cs index ab7ac38c64..bb5b444de9 100644 --- a/src/Playwright/Transport/Channels/PageChannel.cs +++ b/src/Playwright/Transport/Channels/PageChannel.cs @@ -22,12 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -using System.Collections.Generic; -using System.Linq; -using System.Text.Json; -using System.Threading.Tasks; using Microsoft.Playwright.Core; -using Microsoft.Playwright.Transport.Protocol; namespace Microsoft.Playwright.Transport.Channels; @@ -36,323 +31,4 @@ internal class PageChannel : Channel public PageChannel(string guid, Connection connection, Page owner) : base(guid, connection, owner) { } - - internal Task SetDefaultTimeoutNoReplyAsync(float timeout) - => Connection.SendMessageToServerAsync( - Object, - "setDefaultTimeoutNoReply", - new Dictionary - { - ["timeout"] = timeout, - }); - - internal Task SetDefaultNavigationTimeoutNoReplyAsync(float timeout) - => Connection.SendMessageToServerAsync( - Object, - "setDefaultNavigationTimeoutNoReply", - new Dictionary - { - ["timeout"] = timeout, - }); - - internal Task CloseAsync(bool runBeforeUnload) - => Connection.SendMessageToServerAsync( - Object, - "close", - new Dictionary - { - ["runBeforeUnload"] = runBeforeUnload, - }); - - internal Task ExposeBindingAsync(string name, bool needsHandle) - => Connection.SendMessageToServerAsync( - Object, - "exposeBinding", - new Dictionary - { - ["name"] = name, - ["needsHandle"] = needsHandle, - }); - - internal Task AddInitScriptAsync(string script) - => Connection.SendMessageToServerAsync( - Object, - "addInitScript", - new Dictionary - { - ["source"] = script, - }); - - internal Task BringToFrontAsync() => Connection.SendMessageToServerAsync(Object, "bringToFront"); - - internal Task GoBackAsync(float? timeout, WaitUntilState? waitUntil) - { - var args = new Dictionary - { - ["timeout"] = timeout, - ["waitUntil"] = waitUntil, - }; - return Connection.SendMessageToServerAsync(Object, "goBack", args); - } - - internal Task GoForwardAsync(float? timeout, WaitUntilState? waitUntil) - { - var args = new Dictionary - { - ["timeout"] = timeout, - ["waitUntil"] = waitUntil, - }; - return Connection.SendMessageToServerAsync(Object, "goForward", args); - } - - internal Task ReloadAsync(float? timeout, WaitUntilState? waitUntil) - { - var args = new Dictionary - { - ["timeout"] = timeout, - ["waitUntil"] = waitUntil, - }; - return Connection.SendMessageToServerAsync(Object, "reload", args); - } - - internal Task SetNetworkInterceptionPatternsAsync(Dictionary args) - => Connection.SendMessageToServerAsync( - Object, - "setNetworkInterceptionPatterns", - args); - - internal async Task AccessibilitySnapshotAsync(bool? interestingOnly, IChannel root) - { - var args = new Dictionary - { - ["interestingOnly"] = interestingOnly, - ["root"] = root, - }; - - if ((await Connection.SendMessageToServerAsync(Object, "accessibilitySnapshot", args).ConfigureAwait(false)).Value.TryGetProperty("rootAXNode", out var jsonElement)) - { - return jsonElement; - } - - return null; - } - - internal Task SetViewportSizeAsync(PageViewportSizeResult viewport) - => Connection.SendMessageToServerAsync( - Object, - "setViewportSize", - new Dictionary - { - ["viewportSize"] = viewport, - }); - - internal Task KeyboardDownAsync(string key) - => Connection.SendMessageToServerAsync( - Object, - "keyboardDown", - new Dictionary - { - ["key"] = key, - }); - - internal Task EmulateMediaAsync(Dictionary args) - => Connection.SendMessageToServerAsync(Object, "emulateMedia", args); - - internal Task KeyboardUpAsync(string key) - => Connection.SendMessageToServerAsync( - Object, - "keyboardUp", - new Dictionary - { - ["key"] = key, - }); - - internal Task TypeAsync(string text, float? delay) - => Connection.SendMessageToServerAsync( - Object, - "keyboardType", - new Dictionary - { - ["text"] = text, - ["delay"] = delay, - }); - - internal Task PressAsync(string key, float? delay) - => Connection.SendMessageToServerAsync( - Object, - "keyboardPress", - new Dictionary - { - ["key"] = key, - ["delay"] = delay, - }); - - internal Task InsertTextAsync(string text) - => Connection.SendMessageToServerAsync( - Object, - "keyboardInsertText", - new Dictionary - { - ["text"] = text, - }); - - internal Task MouseDownAsync(MouseButton? button, int? clickCount) - => Connection.SendMessageToServerAsync( - Object, - "mouseDown", - new Dictionary - { - ["button"] = button, - ["clickCount"] = clickCount, - }); - - internal Task MouseMoveAsync(float x, float y, int? steps) - => Connection.SendMessageToServerAsync( - Object, - "mouseMove", - new Dictionary - { - ["x"] = x, - ["y"] = y, - ["steps"] = steps, - }); - - internal Task MouseUpAsync(MouseButton? button, int? clickCount) - => Connection.SendMessageToServerAsync( - Object, - "mouseUp", - new Dictionary - { - ["button"] = button, - ["clickCount"] = clickCount, - }); - - internal Task MouseClickAsync(float x, float y, float? delay, MouseButton? button, int? clickCount) - => Connection.SendMessageToServerAsync( - Object, - "mouseClick", - new Dictionary - { - ["x"] = x, - ["y"] = y, - ["delay"] = delay, - ["button"] = button, - ["clickCount"] = clickCount, - }); - - internal Task MouseWheelAsync(float deltaX, float deltaY) - => Connection.SendMessageToServerAsync( - Object, - "mouseWheel", - new Dictionary - { - ["deltaX"] = deltaX, - ["deltaY"] = deltaY, - }); - - internal Task TouchscreenTapAsync(float x, float y) - => Connection.SendMessageToServerAsync( - Object, - "touchscreenTap", - new Dictionary - { - ["x"] = x, - ["y"] = y, - }); - - internal Task SetExtraHTTPHeadersAsync(IEnumerable> headers) - => Connection.SendMessageToServerAsync( - Object, - "setExtraHTTPHeaders", - new Dictionary - { - ["headers"] = headers.Select(kv => new HeaderEntry { Name = kv.Key, Value = kv.Value }), - }); - - internal async Task ScreenshotAsync( - string path, - bool? fullPage, - Clip clip, - bool? omitBackground, - ScreenshotType? type, - int? quality, - IEnumerable mask, - string maskColor, - ScreenshotAnimations? animations, - ScreenshotCaret? caret, - ScreenshotScale? scale, - float? timeout) - { - var args = new Dictionary - { - ["fullPage"] = fullPage, - ["omitBackground"] = omitBackground, - ["clip"] = clip, - ["path"] = path, - ["type"] = type, - ["timeout"] = timeout, - ["animations"] = animations, - ["caret"] = caret, - ["scale"] = scale, - ["quality"] = quality, - ["maskColor"] = maskColor, - ["mask"] = mask?.Select(locator => new Dictionary - { - ["frame"] = ((Locator)locator)._frame._channel, - ["selector"] = ((Locator)locator)._selector, - }).ToArray(), - }; - return (await Connection.SendMessageToServerAsync(Object, "screenshot", args).ConfigureAwait(false))?.GetProperty("binary").GetBytesFromBase64(); - } - - internal Task StartCSSCoverageAsync(bool resetOnNavigation) - => Connection.SendMessageToServerAsync( - Object, - "crStartCSSCoverage", - new Dictionary - { - ["resetOnNavigation"] = resetOnNavigation, - }); - - internal Task StartJSCoverageAsync(bool resetOnNavigation, bool reportAnonymousScripts) - => Connection.SendMessageToServerAsync( - Object, - "crStartJSCoverage", - new Dictionary - { - ["resetOnNavigation"] = resetOnNavigation, - ["reportAnonymousScripts"] = reportAnonymousScripts, - }); - - internal async Task PdfAsync( - float? scale, - bool? displayHeaderFooter, - string headerTemplate, - string footerTemplate, - bool? printBackground, - bool? landscape, - string pageRanges, - string format, - string width, - string height, - Margin margin, - bool? preferCSSPageSize) - { - var args = new Dictionary - { - ["scale"] = scale, - ["displayHeaderFooter"] = displayHeaderFooter, - ["printBackground"] = printBackground, - ["landscape"] = landscape, - ["preferCSSPageSize"] = preferCSSPageSize, - ["pageRanges"] = pageRanges, - ["headerTemplate"] = headerTemplate, - ["footerTemplate"] = footerTemplate, - ["margin"] = margin, - ["width"] = width, - ["format"] = format, - ["height"] = height, - }; - return (await Connection.SendMessageToServerAsync(Object, "pdf", args).ConfigureAwait(false))?.GetProperty("pdf").GetBytesFromBase64(); - } } From cd8634382285329358bd70c5a5e25535f8d3f770 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Sat, 9 Dec 2023 14:51:51 -0800 Subject: [PATCH 4/4] chore: move channels into impl classes 2 --- src/Playwright/Core/ElementHandle.cs | 382 ++++++---- src/Playwright/Core/Frame.cs | 612 ++++++++++----- src/Playwright/Core/Locator.cs | 33 +- .../Channels/ElementHandleChannel.cs | 401 ---------- .../Transport/Channels/FrameChannel.cs | 716 ------------------ 5 files changed, 710 insertions(+), 1434 deletions(-) diff --git a/src/Playwright/Core/ElementHandle.cs b/src/Playwright/Core/ElementHandle.cs index b346d2f901..5a138d2134 100644 --- a/src/Playwright/Core/ElementHandle.cs +++ b/src/Playwright/Core/ElementHandle.cs @@ -60,24 +60,40 @@ internal override void OnMessage(string method, JsonElement? serverParams) } public async Task WaitForSelectorAsync(string selector, ElementHandleWaitForSelectorOptions options = default) - => (await _channel.WaitForSelectorAsync( - selector: selector, - state: options?.State, - timeout: options?.Timeout, - strict: options?.Strict).ConfigureAwait(false))?.Object; + => (await SendMessageToServerAsync( + "waitForSelector", + new Dictionary + { + ["selector"] = selector, + ["timeout"] = options?.Timeout, + ["state"] = options?.State, + ["strict"] = options?.Strict, + }).ConfigureAwait(false)).Object; public Task WaitForElementStateAsync(ElementState state, ElementHandleWaitForElementStateOptions options = default) - => _channel.WaitForElementStateAsync(state, timeout: options?.Timeout); + => SendMessageToServerAsync("waitForElementState", new Dictionary + { + ["state"] = state, + ["timeout"] = options?.Timeout, + }); public Task PressAsync(string key, ElementHandlePressOptions options = default) - => _channel.PressAsync( - key, - delay: options?.Delay, - timeout: options?.Timeout, - noWaitAfter: options?.NoWaitAfter); + => SendMessageToServerAsync("press", new Dictionary + { + ["key"] = key, + ["delay"] = options?.Delay, + ["timeout"] = options?.Timeout, + ["noWaitAfter"] = options?.NoWaitAfter, + }); public Task TypeAsync(string text, ElementHandleTypeOptions options = default) - => _channel.TypeAsync(text, delay: options?.Delay, timeout: options?.Timeout, noWaitAfter: options?.NoWaitAfter); + => SendMessageToServerAsync("type", new Dictionary + { + ["text"] = text, + ["delay"] = options?.Delay, + ["timeout"] = options?.Timeout, + ["noWaitAfter"] = options?.NoWaitAfter, + }); public async Task ScreenshotAsync(ElementHandleScreenshotOptions options = default) { @@ -87,17 +103,28 @@ public async Task ScreenshotAsync(ElementHandleScreenshotOptions options options.Type = DetermineScreenshotType(options.Path); } - byte[] result = await _channel.ScreenshotAsync( - options.Path, - options.OmitBackground, - options.Type, - options.Quality, - options.Mask, - options.MaskColor, - options.Animations, - options.Caret, - options.Scale, - options.Timeout).ConfigureAwait(false); + var args = new Dictionary + { + ["type"] = options.Type, + ["omitBackground"] = options.OmitBackground, + ["path"] = options.Path, + ["timeout"] = options.Timeout, + ["animations"] = options.Animations, + ["caret"] = options.Caret, + ["scale"] = options.Scale, + ["quality"] = options.Quality, + ["maskColor"] = options.MaskColor, + }; + if (options.Mask != null) + { + args["mask"] = options.Mask.Select(locator => new Dictionary + { + ["frame"] = ((Locator)locator)._frame._channel, + ["selector"] = ((Locator)locator)._selector, + }).ToArray(); + } + + var result = (await SendMessageToServerAsync("screenshot", args).ConfigureAwait(false))?.GetProperty("binary").GetBytesFromBase64(); if (!string.IsNullOrEmpty(options.Path)) { @@ -109,52 +136,71 @@ public async Task ScreenshotAsync(ElementHandleScreenshotOptions options } public Task FillAsync(string value, ElementHandleFillOptions options = default) - => _channel.FillAsync( - value, - noWaitAfter: options?.NoWaitAfter, - force: options?.Force, - timeout: options?.Timeout); + => SendMessageToServerAsync("fill", new Dictionary + { + ["value"] = value, + ["timeout"] = options?.Timeout, + ["force"] = options?.Force, + ["noWaitAfter"] = options?.NoWaitAfter, + }); - public async Task