diff --git a/dotnet/src/webdriver/BiDi/BiDi.cs b/dotnet/src/webdriver/BiDi/BiDi.cs index db53571e8ad8c..34a9452dec144 100644 --- a/dotnet/src/webdriver/BiDi/BiDi.cs +++ b/dotnet/src/webdriver/BiDi/BiDi.cs @@ -1,9 +1,10 @@ using System; -using System.Collections.Generic; using System.Threading.Tasks; using OpenQA.Selenium.BiDi.Communication; using OpenQA.Selenium.BiDi.Communication.Transport; +#nullable enable + namespace OpenQA.Selenium.BiDi; public class BiDi : IAsyncDisposable @@ -38,11 +39,11 @@ internal BiDi(string url) } internal Modules.Session.SessionModule SessionModule => _sessionModule.Value; - internal Modules.BrowsingContext.BrowsingContextModule BrowsingContextModule => _browsingContextModule.Value; + internal Modules.BrowsingContext.BrowsingContextModule BrowsingContext => _browsingContextModule.Value; public Modules.Browser.BrowserModule Browser => _browserModule.Value; public Modules.Network.NetworkModule Network => _networkModule.Value; internal Modules.Input.InputModule InputModule => _inputModule.Value; - internal Modules.Script.ScriptModule ScriptModule => _scriptModule.Value; + public Modules.Script.ScriptModule Script => _scriptModule.Value; public Modules.Log.LogModule Log => _logModule.Value; public Modules.Storage.StorageModule Storage => _storageModule.Value; @@ -60,16 +61,6 @@ public static async Task ConnectAsync(string url) return bidi; } - public Task CreateContextAsync(Modules.BrowsingContext.ContextType type, Modules.BrowsingContext.CreateOptions? options = null) - { - return BrowsingContextModule.CreateAsync(type, options); - } - - public Task> GetTreeAsync(Modules.BrowsingContext.GetTreeOptions? options = null) - { - return BrowsingContextModule.GetTreeAsync(options); - } - public Task EndAsync(Modules.Session.EndOptions? options = null) { return SessionModule.EndAsync(options); @@ -81,44 +72,4 @@ public async ValueTask DisposeAsync() _transport?.Dispose(); } - - public Task OnContextCreatedAsync(Func handler, BrowsingContextsSubscriptionOptions? options = null) - { - return BrowsingContextModule.OnContextCreatedAsync(handler, options); - } - - public Task OnContextCreatedAsync(Action handler, BrowsingContextsSubscriptionOptions? options = null) - { - return BrowsingContextModule.OnContextCreatedAsync(handler, options); - } - - public Task OnContextDestroyedAsync(Func handler, BrowsingContextsSubscriptionOptions? options = null) - { - return BrowsingContextModule.OnContextDestroyedAsync(handler, options); - } - - public Task OnContextDestroyedAsync(Action handler, BrowsingContextsSubscriptionOptions? options = null) - { - return BrowsingContextModule.OnContextDestroyedAsync(handler, options); - } - - public Task OnUserPromptOpenedAsync(Func handler, BrowsingContextsSubscriptionOptions? options = null) - { - return BrowsingContextModule.OnUserPromptOpenedAsync(handler, options); - } - - public Task OnUserPromptOpenedAsync(Action handler, BrowsingContextsSubscriptionOptions? options = null) - { - return BrowsingContextModule.OnUserPromptOpenedAsync(handler, options); - } - - public Task OnUserPromptClosedAsync(Func handler, BrowsingContextsSubscriptionOptions? options = null) - { - return BrowsingContextModule.OnUserPromptClosedAsync(handler, options); - } - - public Task OnUserPromptClosedAsync(Action handler, BrowsingContextsSubscriptionOptions? options = null) - { - return BrowsingContextModule.OnUserPromptClosedAsync(handler, options); - } } diff --git a/dotnet/src/webdriver/BiDi/BiDiException.cs b/dotnet/src/webdriver/BiDi/BiDiException.cs index 7f2ddd5b59cbc..6959645111b01 100644 --- a/dotnet/src/webdriver/BiDi/BiDiException.cs +++ b/dotnet/src/webdriver/BiDi/BiDiException.cs @@ -1,5 +1,7 @@ using System; +#nullable enable + namespace OpenQA.Selenium.BiDi; public class BiDiException : Exception diff --git a/dotnet/src/webdriver/BiDi/Communication/Broker.cs b/dotnet/src/webdriver/BiDi/Communication/Broker.cs index 82549d1d5c5b1..5f8a0983846c9 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Broker.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Broker.cs @@ -10,6 +10,8 @@ using System.Threading; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication; public class Broker : IAsyncDisposable @@ -34,7 +36,7 @@ public class Broker : IAsyncDisposable private readonly JsonSerializerOptions _jsonSerializerOptions; - public Broker(BiDi bidi, ITransport transport) + internal Broker(BiDi bidi, ITransport transport) { _bidi = bidi; _transport = transport; @@ -51,7 +53,7 @@ public Broker(BiDi bidi, ITransport transport) new NavigationConverter(), new InterceptConverter(_bidi), new RequestConverter(_bidi), - new ChannelConverter(_bidi), + new ChannelConverter(), new HandleConverter(_bidi), new InternalIdConverter(_bidi), new PreloadScriptConverter(_bidi), @@ -59,6 +61,7 @@ public Broker(BiDi bidi, ITransport transport) new RealmTypeConverter(), new DateTimeOffsetConverter(), new PrintPageRangeConverter(), + new InputOriginConverter(), new JsonStringEnumConverter(JsonNamingPolicy.CamelCase), // https://github.com/dotnet/runtime/issues/72604 @@ -68,6 +71,13 @@ public Broker(BiDi bidi, ITransport transport) new Json.Converters.Polymorphic.RealmInfoConverter(), new Json.Converters.Polymorphic.LogEntryConverter(), // + + // Enumerable + new Json.Converters.Enumerable.GetCookiesResultConverter(), + new Json.Converters.Enumerable.LocateNodesResultConverter(), + new Json.Converters.Enumerable.InputSourceActionsConverter(), + new Json.Converters.Enumerable.GetUserContextsResultConverter(), + new Json.Converters.Enumerable.GetRealmsResultConverter(), } }; } diff --git a/dotnet/src/webdriver/BiDi/Communication/Command.cs b/dotnet/src/webdriver/BiDi/Communication/Command.cs index bfa7113512068..729b319cc03ec 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Command.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Command.cs @@ -1,5 +1,7 @@ using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication; [JsonPolymorphic(TypeDiscriminatorPropertyName = "method")] diff --git a/dotnet/src/webdriver/BiDi/Communication/CommandOptions.cs b/dotnet/src/webdriver/BiDi/Communication/CommandOptions.cs index 93cc63fc2ebfc..ffb6616ae9cef 100644 --- a/dotnet/src/webdriver/BiDi/Communication/CommandOptions.cs +++ b/dotnet/src/webdriver/BiDi/Communication/CommandOptions.cs @@ -1,5 +1,7 @@ using System; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication; public record CommandOptions diff --git a/dotnet/src/webdriver/BiDi/Communication/EventHandler.cs b/dotnet/src/webdriver/BiDi/Communication/EventHandler.cs index 4aab8620e3f2b..ce5444eb0d9fd 100644 --- a/dotnet/src/webdriver/BiDi/Communication/EventHandler.cs +++ b/dotnet/src/webdriver/BiDi/Communication/EventHandler.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication; public abstract class EventHandler(string eventName, Type eventArgsType, IEnumerable? contexts = null) diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/BrowserUserContextConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/BrowserUserContextConverter.cs index 7997f7c0f1541..3d478cf5d9f69 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/BrowserUserContextConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/BrowserUserContextConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class BrowserUserContextConverter : JsonConverter diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/BrowsingContextConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/BrowsingContextConverter.cs index 2718700f3ffac..8c1a928ef19ad 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/BrowsingContextConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/BrowsingContextConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class BrowsingContextConverter : JsonConverter diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/ChannelConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/ChannelConverter.cs index c2a7da0accffd..ac35a22fcc2c4 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/ChannelConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/ChannelConverter.cs @@ -3,22 +3,17 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class ChannelConverter : JsonConverter { - private readonly BiDi _bidi; - - public ChannelConverter(BiDi bidi) - { - _bidi = bidi; - } - public override Channel? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var id = reader.GetString(); - return new Channel(_bidi, id!); + return new Channel(id!); } public override void Write(Utf8JsonWriter writer, Channel value, JsonSerializerOptions options) diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/DateTimeOffsetConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/DateTimeOffsetConverter.cs index 9d87f0f17342e..ff9b6258d3a69 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/DateTimeOffsetConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/DateTimeOffsetConverter.cs @@ -2,6 +2,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class DateTimeOffsetConverter : JsonConverter diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetCookiesResultConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetCookiesResultConverter.cs new file mode 100644 index 0000000000000..bd92fa36eb119 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetCookiesResultConverter.cs @@ -0,0 +1,26 @@ +using OpenQA.Selenium.BiDi.Modules.Storage; +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +#nullable enable + +namespace OpenQA.Selenium.BiDi.Communication.Json.Converters.Enumerable; + +internal class GetCookiesResultConverter : JsonConverter +{ + public override GetCookiesResult Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var doc = JsonDocument.ParseValue(ref reader); + var cookies = doc.RootElement.GetProperty("cookies").Deserialize>(options); + var partitionKey = doc.RootElement.GetProperty("partitionKey").Deserialize(options); + + return new GetCookiesResult(cookies!, partitionKey!); + } + + public override void Write(Utf8JsonWriter writer, GetCookiesResult value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetRealmsResultConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetRealmsResultConverter.cs new file mode 100644 index 0000000000000..34c5a979c02c6 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetRealmsResultConverter.cs @@ -0,0 +1,25 @@ +using OpenQA.Selenium.BiDi.Modules.Script; +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +#nullable enable + +namespace OpenQA.Selenium.BiDi.Communication.Json.Converters.Enumerable; + +internal class GetRealmsResultConverter : JsonConverter +{ + public override GetRealmsResult Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var doc = JsonDocument.ParseValue(ref reader); + var realms = doc.RootElement.GetProperty("realms").Deserialize>(options); + + return new GetRealmsResult(realms!); + } + + public override void Write(Utf8JsonWriter writer, GetRealmsResult value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetUserContextsResultConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetUserContextsResultConverter.cs new file mode 100644 index 0000000000000..123c415c9bcd1 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetUserContextsResultConverter.cs @@ -0,0 +1,25 @@ +using OpenQA.Selenium.BiDi.Modules.Browser; +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +#nullable enable + +namespace OpenQA.Selenium.BiDi.Communication.Json.Converters.Enumerable; + +internal class GetUserContextsResultConverter : JsonConverter +{ + public override GetUserContextsResult Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var doc = JsonDocument.ParseValue(ref reader); + var userContexts = doc.RootElement.GetProperty("userContexts").Deserialize>(options); + + return new GetUserContextsResult(userContexts!); + } + + public override void Write(Utf8JsonWriter writer, GetUserContextsResult value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/InputSourceActionsConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/InputSourceActionsConverter.cs new file mode 100644 index 0000000000000..4e4c72c91fbe9 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/InputSourceActionsConverter.cs @@ -0,0 +1,61 @@ +using OpenQA.Selenium.BiDi.Modules.Input; +using System; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; + +#nullable enable + +namespace OpenQA.Selenium.BiDi.Communication.Json.Converters.Enumerable; + +internal class InputSourceActionsConverter : JsonConverter +{ + public override SourceActions Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + + public override void Write(Utf8JsonWriter writer, SourceActions value, JsonSerializerOptions options) + { + writer.WriteStartObject(); + + writer.WriteString("id", value.Id); + + switch (value) + { + case KeyActions keys: + writer.WriteString("type", "key"); + writer.WritePropertyName("actions"); + JsonSerializer.Serialize(writer, keys.Actions.Select(a => a as IKeySourceAction), options); + + break; + case PointerActions pointers: + writer.WriteString("type", "pointer"); + if (pointers.Options is not null) + { + writer.WritePropertyName("parameters"); + JsonSerializer.Serialize(writer, pointers.Options, options); + } + + writer.WritePropertyName("actions"); + JsonSerializer.Serialize(writer, pointers.Actions.Select(a => a as IPointerSourceAction), options); + + break; + case WheelActions wheels: + writer.WriteString("type", "wheel"); + writer.WritePropertyName("actions"); + JsonSerializer.Serialize(writer, wheels.Actions.Select(a => a as IWheelSourceAction), options); + + break; + case NoneActions none: + writer.WriteString("type", "none"); + writer.WritePropertyName("actions"); + JsonSerializer.Serialize(writer, none.Actions.Select(a => a as INoneSourceAction), options); + + break; + } + + writer.WriteEndObject(); + } +} + diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/LocateNodesResultConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/LocateNodesResultConverter.cs new file mode 100644 index 0000000000000..307433c7be023 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/LocateNodesResultConverter.cs @@ -0,0 +1,26 @@ +using OpenQA.Selenium.BiDi.Modules.BrowsingContext; +using OpenQA.Selenium.BiDi.Modules.Script; +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +#nullable enable + +namespace OpenQA.Selenium.BiDi.Communication.Json.Converters.Enumerable; + +internal class LocateNodesResultConverter : JsonConverter +{ + public override LocateNodesResult Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var doc = JsonDocument.ParseValue(ref reader); + var nodes = doc.RootElement.GetProperty("nodes").Deserialize>(options); + + return new LocateNodesResult(nodes!); + } + + public override void Write(Utf8JsonWriter writer, LocateNodesResult value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/HandleConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/HandleConverter.cs index 71e0ed6e5ae51..2117bb72fa519 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/HandleConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/HandleConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class HandleConverter : JsonConverter diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/InputOriginConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/InputOriginConverter.cs new file mode 100644 index 0000000000000..c544362ccccd8 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/InputOriginConverter.cs @@ -0,0 +1,36 @@ +using OpenQA.Selenium.BiDi.Modules.Input; +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +#nullable enable + +namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; + +internal class InputOriginConverter : JsonConverter +{ + public override Origin Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + + public override void Write(Utf8JsonWriter writer, Origin value, JsonSerializerOptions options) + { + if (value is Origin.Viewport) + { + writer.WriteStringValue("viewport"); + } + else if (value is Origin.Pointer) + { + writer.WriteStringValue("pointer"); + } + else if (value is Origin.Element element) + { + writer.WriteStartObject(); + writer.WriteString("type", "element"); + writer.WritePropertyName("element"); + JsonSerializer.Serialize(writer, element.SharedReference, options); + writer.WriteEndObject(); + } + } +} diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/InterceptConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/InterceptConverter.cs index 3a207a89116c2..3fd062b22fae3 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/InterceptConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/InterceptConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class InterceptConverter : JsonConverter diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/InternalIdConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/InternalIdConverter.cs index 9271a1877be71..7edcaa7543464 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/InternalIdConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/InternalIdConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class InternalIdConverter : JsonConverter diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/NavigationConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/NavigationConverter.cs index 040e7fb723919..e61d300f18f56 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/NavigationConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/NavigationConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class NavigationConverter : JsonConverter diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/EvaluateResultConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/EvaluateResultConverter.cs index c349d82f90f04..ac0fd1a7bbfcc 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/EvaluateResultConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/EvaluateResultConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters.Polymorphic; // https://github.com/dotnet/runtime/issues/72604 @@ -14,8 +16,8 @@ internal class EvaluateResultConverter : JsonConverter return jsonDocument.RootElement.GetProperty("type").ToString() switch { - "success" => jsonDocument.Deserialize(options), - "exception" => jsonDocument.Deserialize(options), + "success" => jsonDocument.Deserialize(options), + "exception" => jsonDocument.Deserialize(options), _ => null, }; } diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/LogEntryConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/LogEntryConverter.cs index ada10ab054a50..e5ccbac46f326 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/LogEntryConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/LogEntryConverter.cs @@ -3,24 +3,26 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters.Polymorphic; // https://github.com/dotnet/runtime/issues/72604 -internal class LogEntryConverter : JsonConverter +internal class LogEntryConverter : JsonConverter { - public override BaseLogEntry? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override Modules.Log.Entry? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var jsonDocument = JsonDocument.ParseValue(ref reader); return jsonDocument.RootElement.GetProperty("type").ToString() switch { - "console" => jsonDocument.Deserialize(options), - "javascript" => jsonDocument.Deserialize(options), + "console" => jsonDocument.Deserialize(options), + "javascript" => jsonDocument.Deserialize(options), _ => null, }; } - public override void Write(Utf8JsonWriter writer, BaseLogEntry value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, Modules.Log.Entry value, JsonSerializerOptions options) { throw new NotImplementedException(); } diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/MessageConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/MessageConverter.cs index 6164dcc04690d..b9d86ae634902 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/MessageConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/MessageConverter.cs @@ -2,6 +2,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters.Polymorphic; // https://github.com/dotnet/runtime/issues/72604 diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/RealmInfoConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/RealmInfoConverter.cs index b3d061783dfae..9824377ca47ac 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/RealmInfoConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/RealmInfoConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters.Polymorphic; // https://github.com/dotnet/runtime/issues/72604 @@ -14,14 +16,14 @@ internal class RealmInfoConverter : JsonConverter return jsonDocument.RootElement.GetProperty("type").ToString() switch { - "window" => jsonDocument.Deserialize(options), - "dedicated-worker" => jsonDocument.Deserialize(options), - "shared-worker" => jsonDocument.Deserialize(options), - "service-worker" => jsonDocument.Deserialize(options), - "worker" => jsonDocument.Deserialize(options), - "paint-worklet" => jsonDocument.Deserialize(options), - "audio-worklet" => jsonDocument.Deserialize(options), - "worklet" => jsonDocument.Deserialize(options), + "window" => jsonDocument.Deserialize(options), + "dedicated-worker" => jsonDocument.Deserialize(options), + "shared-worker" => jsonDocument.Deserialize(options), + "service-worker" => jsonDocument.Deserialize(options), + "worker" => jsonDocument.Deserialize(options), + "paint-worklet" => jsonDocument.Deserialize(options), + "audio-worklet" => jsonDocument.Deserialize(options), + "worklet" => jsonDocument.Deserialize(options), _ => null, }; } diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/RemoteValueConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/RemoteValueConverter.cs index 1d3b08211b348..3f19d2a18c56c 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/RemoteValueConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/RemoteValueConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters.Polymorphic; // https://github.com/dotnet/runtime/issues/72604 @@ -12,31 +14,38 @@ internal class RemoteValueConverter : JsonConverter { var jsonDocument = JsonDocument.ParseValue(ref reader); + if (jsonDocument.RootElement.ValueKind == JsonValueKind.String) + { + return new RemoteValue.String(jsonDocument.RootElement.GetString()!); + } + return jsonDocument.RootElement.GetProperty("type").ToString() switch { - "number" => jsonDocument.Deserialize(options), - "string" => jsonDocument.Deserialize(options), - "null" => jsonDocument.Deserialize(options), - "undefined" => jsonDocument.Deserialize(options), - "symbol" => jsonDocument.Deserialize(options), - "object" => jsonDocument.Deserialize(options), - "function" => jsonDocument.Deserialize(options), - "regexp" => jsonDocument.Deserialize(options), - "date" => jsonDocument.Deserialize(options), - "map" => jsonDocument.Deserialize(options), - "set" => jsonDocument.Deserialize(options), - "weakmap" => jsonDocument.Deserialize(options), - "weakset" => jsonDocument.Deserialize(options), - "generator" => jsonDocument.Deserialize(options), - "error" => jsonDocument.Deserialize(options), - "proxy" => jsonDocument.Deserialize(options), - "promise" => jsonDocument.Deserialize(options), - "typedarray" => jsonDocument.Deserialize(options), - "arraybuffer" => jsonDocument.Deserialize(options), - "nodelist" => jsonDocument.Deserialize(options), - "htmlcollection" => jsonDocument.Deserialize(options), - "node" => jsonDocument.Deserialize(options), - "window" => jsonDocument.Deserialize(options), + "number" => jsonDocument.Deserialize(options), + "boolean" => jsonDocument.Deserialize(options), + "string" => jsonDocument.Deserialize(options), + "null" => jsonDocument.Deserialize(options), + "undefined" => jsonDocument.Deserialize(options), + "symbol" => jsonDocument.Deserialize(options), + "array" => jsonDocument.Deserialize(options), + "object" => jsonDocument.Deserialize(options), + "function" => jsonDocument.Deserialize(options), + "regexp" => jsonDocument.Deserialize(options), + "date" => jsonDocument.Deserialize(options), + "map" => jsonDocument.Deserialize(options), + "set" => jsonDocument.Deserialize(options), + "weakmap" => jsonDocument.Deserialize(options), + "weakset" => jsonDocument.Deserialize(options), + "generator" => jsonDocument.Deserialize(options), + "error" => jsonDocument.Deserialize(options), + "proxy" => jsonDocument.Deserialize(options), + "promise" => jsonDocument.Deserialize(options), + "typedarray" => jsonDocument.Deserialize(options), + "arraybuffer" => jsonDocument.Deserialize(options), + "nodelist" => jsonDocument.Deserialize(options), + "htmlcollection" => jsonDocument.Deserialize(options), + "node" => jsonDocument.Deserialize(options), + "window" => jsonDocument.Deserialize(options), _ => null, }; } diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/PreloadScriptConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/PreloadScriptConverter.cs index 53dba4b424388..4b68ce22c52ff 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/PreloadScriptConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/PreloadScriptConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class PreloadScriptConverter : JsonConverter diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/PrintPageRangeConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/PrintPageRangeConverter.cs index afd375d078a59..76ffd9b34ad4e 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/PrintPageRangeConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/PrintPageRangeConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class PrintPageRangeConverter : JsonConverter diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RealmConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RealmConverter.cs index ab2baedc6fd28..60cde6d1152db 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RealmConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RealmConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class RealmConverter : JsonConverter diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RealmTypeConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RealmTypeConverter.cs index f92966b1a3f1f..048250fd526d5 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RealmTypeConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RealmTypeConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class RealmTypeConverter : JsonConverter @@ -27,6 +29,19 @@ public override RealmType Read(ref Utf8JsonReader reader, Type typeToConvert, Js public override void Write(Utf8JsonWriter writer, RealmType value, JsonSerializerOptions options) { - throw new NotImplementedException(); + var str = value switch + { + RealmType.Window => "window", + RealmType.DedicatedWorker => "dedicated-worker", + RealmType.SharedWorker => "shared-worker", + RealmType.ServiceWorker => "service-worker", + RealmType.Worker => "worker", + RealmType.PaintWorker => "paint-worker", + RealmType.AudioWorker => "audio-worker", + RealmType.Worklet => "worklet", + _ => throw new JsonException($"Unrecognized '{value}' value of {typeof(RealmType)}."), + }; + + writer.WriteStringValue(str); } } diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RequestConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RequestConverter.cs index 7a15a569faa06..0524246d6b3b3 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RequestConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/RequestConverter.cs @@ -3,6 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class RequestConverter : JsonConverter diff --git a/dotnet/src/webdriver/BiDi/Communication/Message.cs b/dotnet/src/webdriver/BiDi/Communication/Message.cs index 75925ed4d7592..c00a2777a33f4 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Message.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Message.cs @@ -1,5 +1,7 @@ using System.Text.Json; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication; // https://github.com/dotnet/runtime/issues/72604 diff --git a/dotnet/src/webdriver/BiDi/Communication/Transport/ITransport.cs b/dotnet/src/webdriver/BiDi/Communication/Transport/ITransport.cs index 404d62734f9d2..3ed6d2e32a4cf 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Transport/ITransport.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Transport/ITransport.cs @@ -3,9 +3,11 @@ using System.Threading; using System; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Transport; -public interface ITransport : IDisposable +interface ITransport : IDisposable { Task ConnectAsync(CancellationToken cancellationToken); diff --git a/dotnet/src/webdriver/BiDi/Communication/Transport/WebSocketTransport.cs b/dotnet/src/webdriver/BiDi/Communication/Transport/WebSocketTransport.cs index 52cd5c0ffa7f2..76384f51b1261 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Transport/WebSocketTransport.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Transport/WebSocketTransport.cs @@ -7,9 +7,11 @@ using System.Text; using OpenQA.Selenium.Internal.Logging; +#nullable enable + namespace OpenQA.Selenium.BiDi.Communication.Transport; -public class WebSocketTransport(Uri _uri) : ITransport, IDisposable +class WebSocketTransport(Uri _uri) : ITransport, IDisposable { private readonly static ILogger _logger = Log.GetLogger(); @@ -59,7 +61,7 @@ public async Task SendAsJsonAsync(Command command, JsonSerializerOptions jsonSer { if (_logger.IsEnabled(LogEventLevel.Trace)) { - _logger.Trace($"BiDi SND >> {buffer.Length} > {Encoding.UTF8.GetString(buffer)}"); + _logger.Trace($"BiDi SND >> {Encoding.UTF8.GetString(buffer)}"); } await _webSocket.SendAsync(new ArraySegment(buffer), WebSocketMessageType.Text, true, cancellationToken).ConfigureAwait(false); diff --git a/dotnet/src/webdriver/BiDi/EventArgs.cs b/dotnet/src/webdriver/BiDi/EventArgs.cs index 01d5cd3280acf..30361ca95e6cb 100644 --- a/dotnet/src/webdriver/BiDi/EventArgs.cs +++ b/dotnet/src/webdriver/BiDi/EventArgs.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Modules.BrowsingContext; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi; public abstract record EventArgs(BiDi BiDi) diff --git a/dotnet/src/webdriver/BiDi/Modules/Browser/BrowserModule.cs b/dotnet/src/webdriver/BiDi/Modules/Browser/BrowserModule.cs index e42982b773d8c..ba7fb0496dd6d 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Browser/BrowserModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Browser/BrowserModule.cs @@ -2,6 +2,8 @@ using System.Threading.Tasks; using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Browser; public sealed class BrowserModule(Broker broker) : Module(broker) @@ -16,11 +18,9 @@ public async Task CreateUserContextAsync(CreateUserContextOptio return await Broker.ExecuteCommandAsync(new CreateUserContextCommand(), options).ConfigureAwait(false); } - public async Task> GetUserContextsAsync(GetUserContextsOptions? options = null) + public async Task GetUserContextsAsync(GetUserContextsOptions? options = null) { - var result = await Broker.ExecuteCommandAsync(new GetUserContextsCommand(), options).ConfigureAwait(false); - - return result.UserContexts; + return await Broker.ExecuteCommandAsync(new GetUserContextsCommand(), options).ConfigureAwait(false); } public async Task RemoveUserContextAsync(UserContext userContext, RemoveUserContextOptions? options = null) diff --git a/dotnet/src/webdriver/BiDi/Modules/Browser/CloseCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Browser/CloseCommand.cs index 345a3c5a22935..59f9db7374929 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Browser/CloseCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Browser/CloseCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Browser; internal class CloseCommand() : Command(CommandParameters.Empty); diff --git a/dotnet/src/webdriver/BiDi/Modules/Browser/CreateUserContextCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Browser/CreateUserContextCommand.cs index 9b84d1ee11532..ce44e5ae2f367 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Browser/CreateUserContextCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Browser/CreateUserContextCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Browser; internal class CreateUserContextCommand() : Command(CommandParameters.Empty); diff --git a/dotnet/src/webdriver/BiDi/Modules/Browser/GetUserContextsCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Browser/GetUserContextsCommand.cs index 5a1a0a211cf1c..161a1bf286f1e 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Browser/GetUserContextsCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Browser/GetUserContextsCommand.cs @@ -1,10 +1,29 @@ using OpenQA.Selenium.BiDi.Communication; +using System.Collections; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Browser; internal class GetUserContextsCommand() : Command(CommandParameters.Empty); public record GetUserContextsOptions : CommandOptions; -public record GetUserContextsResult(IReadOnlyList UserContexts); +public record GetUserContextsResult : IReadOnlyList +{ + private readonly IReadOnlyList _userContexts; + + internal GetUserContextsResult(IReadOnlyList userContexts) + { + _userContexts = userContexts; + } + + public UserContextInfo this[int index] => _userContexts[index]; + + public int Count => _userContexts.Count; + + public IEnumerator GetEnumerator() => _userContexts.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => (_userContexts as IEnumerable).GetEnumerator(); +} diff --git a/dotnet/src/webdriver/BiDi/Modules/Browser/RemoveUserContextCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Browser/RemoveUserContextCommand.cs index b937ad48ffc80..7877eb0f710ff 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Browser/RemoveUserContextCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Browser/RemoveUserContextCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Browser; internal class RemoveUserContextCommand(RemoveUserContextCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Browser/UserContext.cs b/dotnet/src/webdriver/BiDi/Modules/Browser/UserContext.cs index 5e8bcd712062a..a2e689d494aaa 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Browser/UserContext.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Browser/UserContext.cs @@ -1,6 +1,8 @@ using System; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Browser; public class UserContext : IAsyncDisposable @@ -13,7 +15,7 @@ internal UserContext(BiDi bidi, string id) Id = id; } - public string Id { get; } + internal string Id { get; } public Task RemoveAsync() { @@ -24,4 +26,16 @@ public async ValueTask DisposeAsync() { await RemoveAsync().ConfigureAwait(false); } + + public override bool Equals(object? obj) + { + if (obj is UserContext userContextObj) return userContextObj.Id == Id; + + return false; + } + + public override int GetHashCode() + { + return Id.GetHashCode(); + } } diff --git a/dotnet/src/webdriver/BiDi/Modules/Browser/UserContextInfo.cs b/dotnet/src/webdriver/BiDi/Modules/Browser/UserContextInfo.cs index 7f4949b49a2fa..99b7e59a486b2 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Browser/UserContextInfo.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Browser/UserContextInfo.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Browser; public record UserContextInfo(UserContext UserContext); diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/ActivateCommand.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/ActivateCommand.cs index f05354060e89a..4934e51b815bd 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/ActivateCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/ActivateCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; internal class ActivateCommand(ActivateCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContext.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContext.cs index 80c7b7d49fb70..e83f671ae227e 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContext.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContext.cs @@ -2,6 +2,8 @@ using System.Threading.Tasks; using System; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; public class BrowsingContext @@ -13,7 +15,7 @@ internal BrowsingContext(BiDi bidi, string id) _logModule = new Lazy(() => new BrowsingContextLogModule(this, BiDi.Log)); _networkModule = new Lazy(() => new BrowsingContextNetworkModule(this, BiDi.Network)); - _scriptModule = new Lazy(() => new BrowsingContextScriptModule(this, BiDi.ScriptModule)); + _scriptModule = new Lazy(() => new BrowsingContextScriptModule(this, BiDi.Script)); _storageModule = new Lazy(() => new BrowsingContextStorageModule(this, BiDi.Storage)); _inputModule = new Lazy(() => new BrowsingContextInputModule(this, BiDi.InputModule)); } @@ -40,37 +42,37 @@ internal BrowsingContext(BiDi bidi, string id) public Task NavigateAsync(string url, NavigateOptions? options = null) { - return BiDi.BrowsingContextModule.NavigateAsync(this, url, options); + return BiDi.BrowsingContext.NavigateAsync(this, url, options); } public Task ReloadAsync(ReloadOptions? options = null) { - return BiDi.BrowsingContextModule.ReloadAsync(this, options); + return BiDi.BrowsingContext.ReloadAsync(this, options); } public Task ActivateAsync(ActivateOptions? options = null) { - return BiDi.BrowsingContextModule.ActivateAsync(this, options); + return BiDi.BrowsingContext.ActivateAsync(this, options); } - public Task> LocateNodesAsync(Locator locator, LocateNodesOptions? options = null) + public Task LocateNodesAsync(Locator locator, LocateNodesOptions? options = null) { - return BiDi.BrowsingContextModule.LocateNodesAsync(this, locator, options); + return BiDi.BrowsingContext.LocateNodesAsync(this, locator, options); } public Task CaptureScreenshotAsync(CaptureScreenshotOptions? options = null) { - return BiDi.BrowsingContextModule.CaptureScreenshotAsync(this, options); + return BiDi.BrowsingContext.CaptureScreenshotAsync(this, options); } public Task CloseAsync(CloseOptions? options = null) { - return BiDi.BrowsingContextModule.CloseAsync(this, options); + return BiDi.BrowsingContext.CloseAsync(this, options); } public Task TraverseHistoryAsync(int delta, TraverseHistoryOptions? options = null) { - return BiDi.BrowsingContextModule.TraverseHistoryAsync(this, delta, options); + return BiDi.BrowsingContext.TraverseHistoryAsync(this, delta, options); } public Task NavigateBackAsync(TraverseHistoryOptions? options = null) @@ -85,17 +87,17 @@ public Task NavigateForwardAsync(TraverseHistoryOptions? options = null) public Task SetViewportAsync(SetViewportOptions? options = null) { - return BiDi.BrowsingContextModule.SetViewportAsync(this, options); + return BiDi.BrowsingContext.SetViewportAsync(this, options); } public Task PrintAsync(PrintOptions? options = null) { - return BiDi.BrowsingContextModule.PrintAsync(this, options); + return BiDi.BrowsingContext.PrintAsync(this, options); } public Task HandleUserPromptAsync(HandleUserPromptOptions? options = null) { - return BiDi.BrowsingContextModule.HandleUserPromptAsync(this, options); + return BiDi.BrowsingContext.HandleUserPromptAsync(this, options); } public Task> GetTreeAsync(BrowsingContextGetTreeOptions? options = null) @@ -105,77 +107,77 @@ public Task> GetTreeAsync(BrowsingContextGetT Root = this }; - return BiDi.BrowsingContextModule.GetTreeAsync(getTreeOptions); + return BiDi.BrowsingContext.GetTreeAsync(getTreeOptions); } public Task OnNavigationStartedAsync(Func handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnNavigationStartedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnNavigationStartedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public Task OnNavigationStartedAsync(Action handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnNavigationStartedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnNavigationStartedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public Task OnFragmentNavigatedAsync(Func handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnFragmentNavigatedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnFragmentNavigatedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public Task OnFragmentNavigatedAsync(Action handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnFragmentNavigatedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnFragmentNavigatedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public Task OnDomContentLoadedAsync(Func handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnDomContentLoadedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnDomContentLoadedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public Task OnLoadAsync(Action handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnLoadAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnLoadAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public Task OnLoadAsync(Func handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnLoadAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnLoadAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public Task OnDownloadWillBeginAsync(Action handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnDownloadWillBeginAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnDownloadWillBeginAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public Task OnDownloadWillBeginAsync(Func handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnDownloadWillBeginAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnDownloadWillBeginAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public Task OnNavigationAbortedAsync(Action handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnNavigationAbortedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnNavigationAbortedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public Task OnNavigationAbortedAsync(Func handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnNavigationAbortedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnNavigationAbortedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public Task OnNavigationFailedAsync(Action handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnNavigationFailedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnNavigationFailedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public Task OnNavigationFailedAsync(Func handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnNavigationFailedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnNavigationFailedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public Task OnDomContentLoadedAsync(Action handler, SubscriptionOptions? options = null) { - return BiDi.BrowsingContextModule.OnDomContentLoadedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); + return BiDi.BrowsingContext.OnDomContentLoadedAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [this] }); } public override bool Equals(object? obj) diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextInfo.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextInfo.cs index 52f2edeb972e0..f2303915feb90 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextInfo.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextInfo.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; // TODO: Split it to separate class with just info and event args diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextInputModule.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextInputModule.cs index ceae616cb2378..919758b14ba79 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextInputModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextInputModule.cs @@ -2,16 +2,19 @@ using OpenQA.Selenium.BiDi.Modules.Input; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; public class BrowsingContextInputModule(BrowsingContext context, InputModule inputModule) { public Task PerformActionsAsync(IEnumerable actions, PerformActionsOptions? options = null) { - options ??= new(); - - options.Actions = actions; + return inputModule.PerformActionsAsync(context, actions, options); + } - return inputModule.PerformActionsAsync(context, options); + public Task ReleaseActionsAsync(ReleaseActionsOptions? options = null) + { + return inputModule.ReleaseActionsAsync(context, options); } } diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextLogModule.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextLogModule.cs index 03187efd7265c..a085bb07de630 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextLogModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextLogModule.cs @@ -2,11 +2,13 @@ using System.Threading.Tasks; using System; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; public class BrowsingContextLogModule(BrowsingContext context, LogModule logModule) { - public Task OnEntryAddedAsync(Func handler, SubscriptionOptions options = null) + public Task OnEntryAddedAsync(Func handler, SubscriptionOptions? options = null) { return logModule.OnEntryAddedAsync(async args => { @@ -17,7 +19,7 @@ public Task OnEntryAddedAsync(Func handler, Su }, options); } - public Task OnEntryAddedAsync(Action handler, SubscriptionOptions options = null) + public Task OnEntryAddedAsync(Action handler, SubscriptionOptions? options = null) { return logModule.OnEntryAddedAsync(args => { diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextModule.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextModule.cs index fe7a1d3f36343..690df63f7ab2d 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextModule.cs @@ -3,6 +3,8 @@ using System.Threading.Tasks; using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; public class BrowsingContextModule(Broker broker) : Module(broker) @@ -42,7 +44,7 @@ public async Task ActivateAsync(BrowsingContext context, ActivateOptions? option await Broker.ExecuteCommandAsync(new ActivateCommand(@params), options).ConfigureAwait(false); } - public async Task> LocateNodesAsync(BrowsingContext context, Locator locator, LocateNodesOptions? options = null) + public async Task LocateNodesAsync(BrowsingContext context, Locator locator, LocateNodesOptions? options = null) { var @params = new LocateNodesCommandParameters(context, locator); @@ -53,9 +55,7 @@ public async Task ActivateAsync(BrowsingContext context, ActivateOptions? option @params.StartNodes = options.StartNodes; } - var result = await Broker.ExecuteCommandAsync(new LocateNodesCommand(@params), options).ConfigureAwait(false); - - return result.Nodes; + return await Broker.ExecuteCommandAsync(new LocateNodesCommand(@params), options).ConfigureAwait(false); } public async Task CaptureScreenshotAsync(BrowsingContext context, CaptureScreenshotOptions? options = null) diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextNetworkModule.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextNetworkModule.cs index 4b4d805eb3041..e25f255f423c7 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextNetworkModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextNetworkModule.cs @@ -2,6 +2,8 @@ using System; using OpenQA.Selenium.BiDi.Modules.Network; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; public class BrowsingContextNetworkModule(BrowsingContext context, NetworkModule networkModule) @@ -34,7 +36,7 @@ public async Task InterceptResponseAsync(Func InterceptAuthenticationAsync(Func handler, BrowsingContextAddInterceptOptions? interceptOptions = null, SubscriptionOptions? options = null) + public async Task InterceptAuthAsync(Func handler, BrowsingContextAddInterceptOptions? interceptOptions = null, SubscriptionOptions? options = null) { AddInterceptOptions addInterceptOptions = new(interceptOptions) { @@ -88,7 +90,12 @@ public Task OnFetchErrorAsync(Action handler, return networkModule.OnFetchErrorAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [context] }); } - internal Task OnAuthRequiredAsync(Func handler, SubscriptionOptions? options = null) + public Task OnAuthRequiredAsync(Func handler, SubscriptionOptions? options = null) + { + return networkModule.OnAuthRequiredAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [context] }); + } + + public Task OnAuthRequiredAsync(Action handler, SubscriptionOptions? options = null) { return networkModule.OnAuthRequiredAsync(handler, new BrowsingContextsSubscriptionOptions(options) { Contexts = [context] }); } diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextScriptModule.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextScriptModule.cs index d2756ecc503cc..f6f8b77e43c55 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextScriptModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextScriptModule.cs @@ -2,6 +2,8 @@ using OpenQA.Selenium.BiDi.Modules.Script; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; public class BrowsingContextScriptModule(BrowsingContext context, ScriptModule scriptModule) @@ -25,9 +27,9 @@ public async Task> GetRealmsAsync(GetRealmsOptions? opt return await scriptModule.GetRealmsAsync(options).ConfigureAwait(false); } - public Task EvaluateAsync(string expression, bool awaitPromise, EvaluateOptions? options = null, ContextTargetOptions? targetOptions = null) + public Task EvaluateAsync(string expression, bool awaitPromise, EvaluateOptions? options = null, ContextTargetOptions? targetOptions = null) { - var contextTarget = new ContextTarget(context); + var contextTarget = new Target.Context(context); if (targetOptions is not null) { @@ -37,16 +39,16 @@ public Task EvaluateAsync(string expression, bool awaitPromise, Eva return scriptModule.EvaluateAsync(expression, awaitPromise, contextTarget, options); } - public async Task EvaluateAsync(string expression, bool awaitPromise, EvaluateOptions? options = null) + public async Task EvaluateAsync(string expression, bool awaitPromise, EvaluateOptions? options = null, ContextTargetOptions? targetOptions = null) { - var remoteValue = await EvaluateAsync(expression, awaitPromise, options).ConfigureAwait(false); + var result = await EvaluateAsync(expression, awaitPromise, options, targetOptions).ConfigureAwait(false); - return remoteValue.ConvertTo(); + return result.Result.ConvertTo(); } - public Task CallFunctionAsync(string functionDeclaration, bool awaitPromise, CallFunctionOptions? options = null, ContextTargetOptions? targetOptions = null) + public Task CallFunctionAsync(string functionDeclaration, bool awaitPromise, CallFunctionOptions? options = null, ContextTargetOptions? targetOptions = null) { - var contextTarget = new ContextTarget(context); + var contextTarget = new Target.Context(context); if (targetOptions is not null) { @@ -55,4 +57,11 @@ public Task CallFunctionAsync(string functionDeclaration, bool awai return scriptModule.CallFunctionAsync(functionDeclaration, awaitPromise, contextTarget, options); } + + public async Task CallFunctionAsync(string functionDeclaration, bool awaitPromise, CallFunctionOptions? options = null, ContextTargetOptions? targetOptions = null) + { + var result = await CallFunctionAsync(functionDeclaration, awaitPromise, options, targetOptions).ConfigureAwait(false); + + return result.Result.ConvertTo(); + } } diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextStorageModule.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextStorageModule.cs index 810f1ab0b32db..d89343d1ab0f9 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextStorageModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextStorageModule.cs @@ -1,6 +1,8 @@ using System.Threading.Tasks; using OpenQA.Selenium.BiDi.Modules.Storage; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; public class BrowsingContextStorageModule(BrowsingContext context, StorageModule storageModule) @@ -9,7 +11,7 @@ public Task GetCookiesAsync(GetCookiesOptions? options = null) { options ??= new(); - options.Partition = new BrowsingContextPartitionDescriptor(context); + options.Partition = new PartitionDescriptor.Context(context); return storageModule.GetCookiesAsync(options); } @@ -18,7 +20,7 @@ public async Task DeleteCookiesAsync(DeleteCookiesOptions? options { options ??= new(); - options.Partition = new BrowsingContextPartitionDescriptor(context); + options.Partition = new PartitionDescriptor.Context(context); var res = await storageModule.DeleteCookiesAsync(options).ConfigureAwait(false); @@ -29,7 +31,7 @@ public async Task SetCookieAsync(PartialCookie cookie, SetCookieOp { options ??= new(); - options.Partition = new BrowsingContextPartitionDescriptor(context); + options.Partition = new PartitionDescriptor.Context(context); var res = await storageModule.SetCookieAsync(cookie, options).ConfigureAwait(false); diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/CaptureScreenshotCommand.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/CaptureScreenshotCommand.cs index 69ea01b0e70d8..df5f203c1d3fc 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/CaptureScreenshotCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/CaptureScreenshotCommand.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Communication; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; internal class CaptureScreenshotCommand(CaptureScreenshotCommandParameters @params) : Command(@params); @@ -35,13 +37,14 @@ public record struct ImageFormat(string Type) } [JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -[JsonDerivedType(typeof(BoxClipRectangle), "box")] -[JsonDerivedType(typeof(ElementClipRectangle), "element")] -public abstract record ClipRectangle; - -public record BoxClipRectangle(double X, double Y, double Width, double Height) : ClipRectangle; +[JsonDerivedType(typeof(Box), "box")] +[JsonDerivedType(typeof(Element), "element")] +public abstract record ClipRectangle +{ + public record Box(double X, double Y, double Width, double Height) : ClipRectangle; -public record ElementClipRectangle(Script.SharedReference Element) : ClipRectangle; + public record Element([property: JsonPropertyName("element")] Script.SharedReference SharedReference) : ClipRectangle; +} public record CaptureScreenshotResult(string Data) { diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/CloseCommand.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/CloseCommand.cs index ac531a28699ac..e3f3279a97955 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/CloseCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/CloseCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; internal class CloseCommand(CloseCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/CreateCommand.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/CreateCommand.cs index 86a81bcada46a..a70f89726c364 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/CreateCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/CreateCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; internal class CreateCommand(CreateCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/GetTreeCommand.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/GetTreeCommand.cs index fe6a38c1fe0bc..eb03c29856266 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/GetTreeCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/GetTreeCommand.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Communication; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; internal class GetTreeCommand(GetTreeCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/HandleUserPromptCommand.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/HandleUserPromptCommand.cs index 2dd2888d19a87..a566ef6edf963 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/HandleUserPromptCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/HandleUserPromptCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; class HandleUserPromptCommand(HandleUserPromptCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/LocateNodesCommand.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/LocateNodesCommand.cs index 2dce843e557a3..d32188ae7cce3 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/LocateNodesCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/LocateNodesCommand.cs @@ -1,6 +1,9 @@ using OpenQA.Selenium.BiDi.Communication; +using System.Collections; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; internal class LocateNodesCommand(LocateNodesCommandParameters @params) : Command(@params); @@ -23,4 +26,20 @@ public record LocateNodesOptions : CommandOptions public IEnumerable? StartNodes { get; set; } } -public record LocateNodesResult(IReadOnlyList Nodes); +public record LocateNodesResult : IReadOnlyList +{ + private readonly IReadOnlyList _nodes; + + internal LocateNodesResult(IReadOnlyList nodes) + { + _nodes = nodes; + } + + public Script.RemoteValue.Node this[int index] => _nodes[index]; + + public int Count => _nodes.Count; + + public IEnumerator GetEnumerator() => _nodes.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => (_nodes as IEnumerable).GetEnumerator(); +} diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/Locator.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/Locator.cs index d931019afd446..d22215f5f6d92 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/Locator.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/Locator.cs @@ -1,43 +1,37 @@ using System.Text.Json.Serialization; -using static OpenQA.Selenium.BiDi.Modules.BrowsingContext.AccessibilityLocator; + +#nullable enable namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; [JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -[JsonDerivedType(typeof(AccessibilityLocator), "accessibility")] -[JsonDerivedType(typeof(CssLocator), "css")] -[JsonDerivedType(typeof(InnerTextLocator), "innerText")] -[JsonDerivedType(typeof(XPathLocator), "xpath")] +[JsonDerivedType(typeof(Accessibility), "accessibility")] +[JsonDerivedType(typeof(Css), "css")] +[JsonDerivedType(typeof(InnerText), "innerText")] +[JsonDerivedType(typeof(XPath), "xpath")] public abstract record Locator { - public static CssLocator Css(string value) - => new(value); - - public static InnerTextLocator InnerText(string value, bool? ignoreCase = null, MatchType? matchType = null, long? maxDepth = null) - => new(value) { IgnoreCase = ignoreCase, MatchType = matchType, MaxDepth = maxDepth }; - - public static XPathLocator XPath(string value) - => new(value); -} - -public record AccessibilityLocator(AccessibilityValue Value) : Locator -{ - public record AccessibilityValue + public record Accessibility(Accessibility.AccessibilityValue Value) : Locator { - public string? Name { get; set; } - public string? Role { get; set; } + public record AccessibilityValue + { + public string? Name { get; set; } + public string? Role { get; set; } + } } -} -public record CssLocator(string Value) : Locator; + public record Css(string Value) : Locator; -public record InnerTextLocator(string Value) : Locator -{ - public bool? IgnoreCase { get; set; } + public record InnerText(string Value) : Locator + { + public bool? IgnoreCase { get; set; } - public MatchType? MatchType { get; set; } + public MatchType? MatchType { get; set; } - public long? MaxDepth { get; set; } + public long? MaxDepth { get; set; } + } + + public record XPath(string Value) : Locator; } public enum MatchType @@ -45,5 +39,3 @@ public enum MatchType Full, Partial } - -public record XPathLocator(string Value) : Locator; diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/NavigateCommand.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/NavigateCommand.cs index 401c0ec2093d4..7481a6141e430 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/NavigateCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/NavigateCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; internal class NavigateCommand(NavigateCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/Navigation.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/Navigation.cs index 0b56229ade1de..3ce169d0f40c6 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/Navigation.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/Navigation.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; public record Navigation(string Id); diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/NavigationInfo.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/NavigationInfo.cs index fe7a83399bf11..e934e3030d305 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/NavigationInfo.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/NavigationInfo.cs @@ -1,5 +1,7 @@ using System; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; public record NavigationInfo(BiDi BiDi, BrowsingContext Context, Navigation Navigation, DateTimeOffset Timestamp, string Url) diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/PrintCommand.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/PrintCommand.cs index 66c270c12dd97..70fa6bcdd1f2a 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/PrintCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/PrintCommand.cs @@ -2,6 +2,8 @@ using System; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; internal class PrintCommand(PrintCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/ReloadCommand.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/ReloadCommand.cs index fea265ce15200..1dd805fd0a00b 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/ReloadCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/ReloadCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; internal class ReloadCommand(ReloadCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/SetViewportCommand.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/SetViewportCommand.cs index 0ed6e869e85a7..a43cb30157e15 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/SetViewportCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/SetViewportCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; internal class SetViewportCommand(SetViewportCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/TraverseHistoryCommand.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/TraverseHistoryCommand.cs index 65797e0164cd0..b8c78b2601adb 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/TraverseHistoryCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/TraverseHistoryCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; internal class TraverseHistoryCommand(TraverseHistoryCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/UserPromptClosedEventArgs.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/UserPromptClosedEventArgs.cs index fa59f7262fcc2..c7123e89f76be 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/UserPromptClosedEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/UserPromptClosedEventArgs.cs @@ -1,5 +1,7 @@ using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; public record UserPromptClosedEventArgs(BiDi BiDi, BrowsingContext Context, bool Accepted) diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/UserPromptOpenedEventArgs.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/UserPromptOpenedEventArgs.cs index 8e6658bd79523..03dd37be8cbeb 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/UserPromptOpenedEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/UserPromptOpenedEventArgs.cs @@ -1,5 +1,7 @@ using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; public record UserPromptOpenedEventArgs(BiDi BiDi, BrowsingContext Context, UserPromptType Type, string Message) diff --git a/dotnet/src/webdriver/BiDi/Modules/Input/InputModule.cs b/dotnet/src/webdriver/BiDi/Modules/Input/InputModule.cs index a31b0371dfb4a..53f913132c758 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Input/InputModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Input/InputModule.cs @@ -1,18 +1,16 @@ using OpenQA.Selenium.BiDi.Communication; +using System.Collections.Generic; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Input; public sealed class InputModule(Broker broker) : Module(broker) { - public async Task PerformActionsAsync(BrowsingContext.BrowsingContext context, PerformActionsOptions? options = null) + public async Task PerformActionsAsync(BrowsingContext.BrowsingContext context, IEnumerable actions, PerformActionsOptions? options = null) { - var @params = new PerformActionsCommandParameters(context); - - if (options is not null) - { - @params.Actions = options.Actions; - } + var @params = new PerformActionsCommandParameters(context, actions); await Broker.ExecuteCommandAsync(new PerformActionsCommand(@params), options).ConfigureAwait(false); } @@ -21,6 +19,6 @@ public async Task ReleaseActionsAsync(BrowsingContext.BrowsingContext context, R { var @params = new ReleaseActionsCommandParameters(context); - await Broker.ExecuteCommandAsync(new ReleaseActionsCommand(@params), options); + await Broker.ExecuteCommandAsync(new ReleaseActionsCommand(@params), options).ConfigureAwait(false); } } diff --git a/dotnet/src/webdriver/BiDi/Modules/Input/Key.cs b/dotnet/src/webdriver/BiDi/Modules/Input/Key.cs new file mode 100644 index 0000000000000..a7d99ffca3ac9 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Modules/Input/Key.cs @@ -0,0 +1,8 @@ +//namespace OpenQA.Selenium.BiDi.Modules.Input; + +//partial record Key +//{ +// public const char Shift = '\uE008'; + +// public const char Pause = '\uE00B'; +//} diff --git a/dotnet/src/webdriver/BiDi/Modules/Input/Origin.cs b/dotnet/src/webdriver/BiDi/Modules/Input/Origin.cs new file mode 100644 index 0000000000000..5cc909cd6aabe --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Modules/Input/Origin.cs @@ -0,0 +1,17 @@ +using System.Text.Json.Serialization; + +#nullable enable + +namespace OpenQA.Selenium.BiDi.Modules.Input; + +public abstract record Origin +{ + public record Viewport() : Origin; + + public record Pointer() : Origin; + + public record Element([property: JsonPropertyName("element")] Script.SharedReference SharedReference) : Origin + { + public string Type { get; } = "element"; + } +} diff --git a/dotnet/src/webdriver/BiDi/Modules/Input/PerformActionsCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Input/PerformActionsCommand.cs index 0a719c7513ce7..878b576417fba 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Input/PerformActionsCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Input/PerformActionsCommand.cs @@ -1,74 +1,12 @@ using OpenQA.Selenium.BiDi.Communication; -using System; using System.Collections.Generic; -using System.Text.Json.Serialization; + +#nullable enable namespace OpenQA.Selenium.BiDi.Modules.Input; internal class PerformActionsCommand(PerformActionsCommandParameters @params) : Command(@params); -internal record PerformActionsCommandParameters(BrowsingContext.BrowsingContext Context) : CommandParameters -{ - public IEnumerable? Actions { get; set; } -} - -public record PerformActionsOptions : CommandOptions -{ - public IEnumerable? Actions { get; set; } = []; -} - -[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -[JsonDerivedType(typeof(KeySourceActions), "key")] -public abstract record SourceActions -{ - public static KeySourceActions Press(string text) - { - var keySourceActions = new KeySourceActions(); - - foreach (var character in text) - { - keySourceActions.Actions.AddRange([ - new KeyDownAction(character.ToString()), - new KeyUpAction(character.ToString()) - ]); - } - - return keySourceActions; - } -} - -public record KeySourceActions : SourceActions -{ - public string Id { get; set; } = Guid.NewGuid().ToString(); - - public List Actions { get; set; } = []; - - public new KeySourceActions Press(string text) - { - Actions.AddRange(SourceActions.Press(text).Actions); - - return this; - } - - public KeySourceActions Pause(long? duration = null) - { - Actions.Add(new KeyPauseAction { Duration = duration }); - - return this; - } -} - -[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -[JsonDerivedType(typeof(KeyPauseAction), "pause")] -[JsonDerivedType(typeof(KeyDownAction), "keyDown")] -[JsonDerivedType(typeof(KeyUpAction), "keyUp")] -public abstract record KeySourceAction; - -public record KeyPauseAction : KeySourceAction -{ - public long? Duration { get; set; } -} - -public record KeyDownAction(string Value) : KeySourceAction; +internal record PerformActionsCommandParameters(BrowsingContext.BrowsingContext Context, IEnumerable Actions) : CommandParameters; -public record KeyUpAction(string Value) : KeySourceAction; +public record PerformActionsOptions : CommandOptions; diff --git a/dotnet/src/webdriver/BiDi/Modules/Input/ReleaseActionsCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Input/ReleaseActionsCommand.cs index 0ee6d6345d21b..2331e1bec6c49 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Input/ReleaseActionsCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Input/ReleaseActionsCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Input; internal class ReleaseActionsCommand(ReleaseActionsCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Input/SequentialSourceActions.cs b/dotnet/src/webdriver/BiDi/Modules/Input/SequentialSourceActions.cs new file mode 100644 index 0000000000000..dfdbc3f69a331 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Modules/Input/SequentialSourceActions.cs @@ -0,0 +1,161 @@ +//using System.Collections; +//using System.Collections.Generic; +//using System.Linq; + +//namespace OpenQA.Selenium.BiDi.Modules.Input; + +//public interface ISequentialSourceActions : IEnumerable +//{ +// ISequentialSourceActions Pause(int duration); + +// ISequentialSourceActions Type(string text); +// ISequentialSourceActions KeyDown(char key); +// ISequentialSourceActions KeyUp(char key); + +// ISequentialSourceActions PointerDown(int button, PointerDownOptions? options = null); +// ISequentialSourceActions PointerUp(int button); +// ISequentialSourceActions PointerMove(int x, int y, PointerMoveOptions? options = null); +//} + +//public record SequentialSourceActions : ISequentialSourceActions +//{ +// private readonly KeyActions _keyActions = []; +// private readonly PointerActions _pointerActions = []; +// private readonly WheelActions _wheelActions = []; +// private readonly WheelActions _noneActions = []; + +// public ISequentialSourceActions Pause(int duration) +// { +// _noneActions.Add(new Pause { Duration = duration }); + +// return Normalized(); +// } + +// public ISequentialSourceActions Type(string text) +// { +// _keyActions.Type(text); + +// return Normalized(); +// } + +// public ISequentialSourceActions KeyDown(char key) +// { +// _keyActions.Add(new Key.Down(key)); + +// return Normalized(); +// } + +// public ISequentialSourceActions KeyUp(char key) +// { +// _keyActions.Add(new Key.Up(key)); + +// return Normalized(); +// } + +// public ISequentialSourceActions PointerDown(int button, PointerDownOptions? options = null) +// { +// _pointerActions.Add(new Pointer.Down(button) +// { +// Width = options?.Width, +// Height = options?.Height, +// Pressure = options?.Pressure, +// TangentialPressure = options?.TangentialPressure, +// Twist = options?.Twist, +// AltitudeAngle = options?.AltitudeAngle, +// AzimuthAngle = options?.AzimuthAngle +// }); + +// return Normalized(); +// } + +// public ISequentialSourceActions PointerUp(int button) +// { +// _pointerActions.Add(new Pointer.Up(button)); + +// return Normalized(); +// } + +// public ISequentialSourceActions PointerMove(int x, int y, PointerMoveOptions? options = null) +// { +// _pointerActions.Add(new Pointer.Move(x, y) +// { +// Duration = options?.Duration, +// Origin = options?.Origin, +// Width = options?.Width, +// Height = options?.Height, +// Pressure = options?.Pressure, +// TangentialPressure = options?.TangentialPressure, +// Twist = options?.Twist, +// AltitudeAngle = options?.AltitudeAngle, +// AzimuthAngle = options?.AzimuthAngle +// }); + +// return Normalized(); +// } + +// private SequentialSourceActions Normalized() +// { +// var max = new[] { _keyActions.Count(), _pointerActions.Count(), _wheelActions.Count(), _noneActions.Count() }.Max(); + +// for (int i = _keyActions.Count(); i < max; i++) +// { +// _keyActions.Add(new Pause()); +// } + +// for (int i = _pointerActions.Count(); i < max; i++) +// { +// _pointerActions.Add(new Pause()); +// } + +// for (int i = _wheelActions.Count(); i < max; i++) +// { +// _wheelActions.Add(new Pause()); +// } + +// for (int i = _noneActions.Count(); i < max; i++) +// { +// _noneActions.Add(new Pause()); +// } + +// return this; +// } + +// public IEnumerator GetEnumerator() +// { +// var sourceActions = new List +// { +// _keyActions, +// _pointerActions, +// _wheelActions, +// _noneActions +// }; +// return sourceActions.GetEnumerator(); +// } + +// IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +//} + +//public record PointerDownOptions : IPointerCommonProperties +//{ +// public int? Width { get; set; } +// public int? Height { get; set; } +// public double? Pressure { get; set; } +// public double? TangentialPressure { get; set; } +// public int? Twist { get; set; } +// public double? AltitudeAngle { get; set; } +// public double? AzimuthAngle { get; set; } +//} + +//public record PointerMoveOptions : IPointerCommonProperties +//{ +// public int? Duration { get; set; } +// public Origin? Origin { get; set; } + +// public int? Width { get; set; } +// public int? Height { get; set; } +// public double? Pressure { get; set; } +// public double? TangentialPressure { get; set; } +// public int? Twist { get; set; } +// public double? AltitudeAngle { get; set; } +// public double? AzimuthAngle { get; set; } +//} diff --git a/dotnet/src/webdriver/BiDi/Modules/Input/SourceActions.cs b/dotnet/src/webdriver/BiDi/Modules/Input/SourceActions.cs new file mode 100644 index 0000000000000..a9b7ed3f7001f --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Modules/Input/SourceActions.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text.Json.Serialization; + +#nullable enable + +namespace OpenQA.Selenium.BiDi.Modules.Input; + +public abstract record SourceActions +{ + public string Id { get; } = Guid.NewGuid().ToString(); +} + +public interface ISourceAction; + +public record SourceActions : SourceActions, IEnumerable where T : ISourceAction +{ + public IList Actions { get; set; } = []; + + public IEnumerator GetEnumerator() => Actions.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => Actions.GetEnumerator(); + + public void Add(ISourceAction action) => Actions.Add(action); +} + +[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] +[JsonDerivedType(typeof(Pause), "pause")] +[JsonDerivedType(typeof(Key.Down), "keyDown")] +[JsonDerivedType(typeof(Key.Up), "keyUp")] +public interface IKeySourceAction : ISourceAction; + +public record KeyActions : SourceActions +{ + public KeyActions Type(string text) + { + foreach (var character in text) + { + Add(new Key.Down(character)); + Add(new Key.Up(character)); + } + + return this; + } +} + +[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] +[JsonDerivedType(typeof(Pause), "pause")] +[JsonDerivedType(typeof(Pointer.Down), "pointerDown")] +[JsonDerivedType(typeof(Pointer.Up), "pointerUp")] +[JsonDerivedType(typeof(Pointer.Move), "pointerMove")] +public interface IPointerSourceAction : ISourceAction; + +public record PointerActions : SourceActions +{ + public PointerParameters? Options { get; set; } +} + +[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] +[JsonDerivedType(typeof(Pause), "pause")] +[JsonDerivedType(typeof(Wheel.Scroll), "scroll")] +public interface IWheelSourceAction : ISourceAction; + +public record WheelActions : SourceActions; + +[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] +[JsonDerivedType(typeof(Pause), "pause")] +public interface INoneSourceAction : ISourceAction; + +public record NoneActions : SourceActions; + +public abstract partial record Key : IKeySourceAction +{ + public record Down(char Value) : Key; + + public record Up(char Value) : Key; +} + +public abstract record Pointer : IPointerSourceAction +{ + public record Down(int Button) : Pointer, IPointerCommonProperties + { + public int? Width { get; set; } + public int? Height { get; set; } + public double? Pressure { get; set; } + public double? TangentialPressure { get; set; } + public int? Twist { get; set; } + public double? AltitudeAngle { get; set; } + public double? AzimuthAngle { get; set; } + } + + public record Up(int Button) : Pointer; + + public record Move(int X, int Y) : Pointer, IPointerCommonProperties + { + public int? Duration { get; set; } + + public Origin? Origin { get; set; } + + public int? Width { get; set; } + public int? Height { get; set; } + public double? Pressure { get; set; } + public double? TangentialPressure { get; set; } + public int? Twist { get; set; } + public double? AltitudeAngle { get; set; } + public double? AzimuthAngle { get; set; } + } +} + +public abstract record Wheel : IWheelSourceAction +{ + public record Scroll(int X, int Y, int DeltaX, int DeltaY) : Wheel + { + public int? Duration { get; set; } + + public Origin? Origin { get; set; } + } +} + +public abstract record None : INoneSourceAction; + +public record Pause : ISourceAction, IKeySourceAction, IPointerSourceAction, IWheelSourceAction, INoneSourceAction +{ + public long? Duration { get; set; } +} + +public record PointerParameters +{ + public PointerType? PointerType { get; set; } +} + +public enum PointerType +{ + Mouse, + Pen, + Touch +} + +public interface IPointerCommonProperties +{ + public int? Width { get; set; } + + public int? Height { get; set; } + + public double? Pressure { get; set; } + + public double? TangentialPressure { get; set; } + + public int? Twist { get; set; } + + public double? AltitudeAngle { get; set; } + + public double? AzimuthAngle { get; set; } +} diff --git a/dotnet/src/webdriver/BiDi/Modules/Log/Entry.cs b/dotnet/src/webdriver/BiDi/Modules/Log/Entry.cs new file mode 100644 index 0000000000000..dba3714e27403 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Modules/Log/Entry.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; + +#nullable enable + +namespace OpenQA.Selenium.BiDi.Modules.Log; + +// https://github.com/dotnet/runtime/issues/72604 +//[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] +//[JsonDerivedType(typeof(Console), "console")] +//[JsonDerivedType(typeof(Javascript), "javascript")] +public abstract record Entry(BiDi BiDi, Level Level, Script.Source Source, string Text, DateTimeOffset Timestamp) + : EventArgs(BiDi) +{ + public Script.StackTrace? StackTrace { get; set; } + + public record Console(BiDi BiDi, Level Level, Script.Source Source, string Text, DateTimeOffset Timestamp, string Method, IReadOnlyList Args) + : Entry(BiDi, Level, Source, Text, Timestamp); + + public record Javascript(BiDi BiDi, Level Level, Script.Source Source, string Text, DateTimeOffset Timestamp) + : Entry(BiDi, Level, Source, Text, Timestamp); +} + +public enum Level +{ + Debug, + Info, + Warn, + Error +} diff --git a/dotnet/src/webdriver/BiDi/Modules/Log/LogEntry.cs b/dotnet/src/webdriver/BiDi/Modules/Log/LogEntry.cs deleted file mode 100644 index f210c126a8859..0000000000000 --- a/dotnet/src/webdriver/BiDi/Modules/Log/LogEntry.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace OpenQA.Selenium.BiDi.Modules.Log; - -// https://github.com/dotnet/runtime/issues/72604 -//[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -//[JsonDerivedType(typeof(ConsoleLogEntry), "console")] -//[JsonDerivedType(typeof(JavascriptLogEntry), "javascript")] -public abstract record BaseLogEntry(BiDi BiDi, Level Level, Script.Source Source, string Text, DateTimeOffset Timestamp) - : EventArgs(BiDi); - -public record ConsoleLogEntry(BiDi BiDi, Level Level, Script.Source Source, string Text, DateTimeOffset Timestamp, string Method, IReadOnlyList Args) - : BaseLogEntry(BiDi, Level, Source, Text, Timestamp); - -public record JavascriptLogEntry(BiDi BiDi, Level Level, Script.Source Source, string Text, DateTimeOffset Timestamp) - : BaseLogEntry(BiDi, Level, Source, Text, Timestamp); - -public enum Level -{ - Debug, - Info, - Warn, - Error -} diff --git a/dotnet/src/webdriver/BiDi/Modules/Log/LogModule.cs b/dotnet/src/webdriver/BiDi/Modules/Log/LogModule.cs index 7bf84d530126a..aeb09a08754bd 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Log/LogModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Log/LogModule.cs @@ -2,16 +2,18 @@ using System; using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Log; public sealed class LogModule(Broker broker) : Module(broker) { - public async Task OnEntryAddedAsync(Func handler, SubscriptionOptions? options = null) + public async Task OnEntryAddedAsync(Func handler, SubscriptionOptions? options = null) { return await Broker.SubscribeAsync("log.entryAdded", handler, options).ConfigureAwait(false); } - public async Task OnEntryAddedAsync(Action handler, SubscriptionOptions? options = null) + public async Task OnEntryAddedAsync(Action handler, SubscriptionOptions? options = null) { return await Broker.SubscribeAsync("log.entryAdded", handler, options).ConfigureAwait(false); } diff --git a/dotnet/src/webdriver/BiDi/Modules/Module.cs b/dotnet/src/webdriver/BiDi/Modules/Module.cs index a6ac7d1719c43..a7c2491349750 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Module.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Module.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules; public abstract class Module(Broker broker) diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/AddInterceptCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Network/AddInterceptCommand.cs index 4856193d512d9..219f3640ca466 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/AddInterceptCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/AddInterceptCommand.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; internal class AddInterceptCommand(AddInterceptCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/AuthChallenge.cs b/dotnet/src/webdriver/BiDi/Modules/Network/AuthChallenge.cs index b304cbacf3f1e..f85da002f189e 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/AuthChallenge.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/AuthChallenge.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record AuthChallenge(string Scheme, string Realm); diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/AuthCredentials.cs b/dotnet/src/webdriver/BiDi/Modules/Network/AuthCredentials.cs index 384360e660f44..8f78b5465f969 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/AuthCredentials.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/AuthCredentials.cs @@ -1,12 +1,14 @@ using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; [JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -[JsonDerivedType(typeof(BasicAuthCredentials), "password")] +[JsonDerivedType(typeof(Basic), "password")] public abstract record AuthCredentials { - public static BasicAuthCredentials Basic(string username, string password) => new(username, password); + public record Basic(string Username, string Password) : AuthCredentials; } -public record BasicAuthCredentials(string Username, string Password) : AuthCredentials; + diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/AuthRequiredEventArgs.cs b/dotnet/src/webdriver/BiDi/Modules/Network/AuthRequiredEventArgs.cs index 6e3e8626e8b5f..dca341b07b4da 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/AuthRequiredEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/AuthRequiredEventArgs.cs @@ -1,5 +1,7 @@ using System; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record AuthRequiredEventArgs(BiDi BiDi, BrowsingContext.BrowsingContext Context, bool IsBlocked, BrowsingContext.Navigation Navigation, long RedirectCount, RequestData Request, DateTimeOffset Timestamp, ResponseData Response) : diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/BaseParametersEventArgs.cs b/dotnet/src/webdriver/BiDi/Modules/Network/BaseParametersEventArgs.cs index d632e433e137d..e8e721d033ca5 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/BaseParametersEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/BaseParametersEventArgs.cs @@ -2,6 +2,8 @@ using System.Text.Json.Serialization; using System; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public abstract record BaseParametersEventArgs(BiDi BiDi, BrowsingContext.BrowsingContext Context, bool IsBlocked, BrowsingContext.Navigation Navigation, long RedirectCount, RequestData Request, DateTimeOffset Timestamp) diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/BeforeRequestSentEventArgs.cs b/dotnet/src/webdriver/BiDi/Modules/Network/BeforeRequestSentEventArgs.cs index 0ca4994bd7bae..53f4b85aa3669 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/BeforeRequestSentEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/BeforeRequestSentEventArgs.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Modules.BrowsingContext; using System; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record BeforeRequestSentEventArgs(BiDi BiDi, BrowsingContext.BrowsingContext Context, bool IsBlocked, Navigation Navigation, long RedirectCount, RequestData Request, DateTimeOffset Timestamp, Initiator Initiator) diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/BytesValue.cs b/dotnet/src/webdriver/BiDi/Modules/Network/BytesValue.cs index 02b982422d4c7..6c5d88a930d66 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/BytesValue.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/BytesValue.cs @@ -1,15 +1,17 @@ using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; [JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -[JsonDerivedType(typeof(StringValue), "string")] -[JsonDerivedType(typeof(Base64Value), "base64")] +[JsonDerivedType(typeof(String), "string")] +[JsonDerivedType(typeof(Base64), "base64")] public abstract record BytesValue { - public static implicit operator BytesValue(string value) => new StringValue(value); -} + public static implicit operator BytesValue(string value) => new String(value); -public record StringValue(string Value) : BytesValue; + public record String(string Value) : BytesValue; -public record Base64Value(string Value) : BytesValue; + public record Base64(string Value) : BytesValue; +} diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/ContinueRequestCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Network/ContinueRequestCommand.cs index bdf572ece2c08..447dfa41baa70 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/ContinueRequestCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/ContinueRequestCommand.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Communication; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; internal class ContinueRequestCommand(ContinueRequestCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/ContinueResponseCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Network/ContinueResponseCommand.cs index 6762035e94e38..ba2e4e60a1bed 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/ContinueResponseCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/ContinueResponseCommand.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Communication; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; internal class ContinueResponseCommand(ContinueResponseCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/ContinueWithAuthCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Network/ContinueWithAuthCommand.cs index 4c6553181da92..c486066015ec4 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/ContinueWithAuthCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/ContinueWithAuthCommand.cs @@ -1,21 +1,24 @@ using OpenQA.Selenium.BiDi.Communication; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; internal class ContinueWithAuthCommand(ContinueWithAuthParameters @params) : Command(@params); [JsonPolymorphic(TypeDiscriminatorPropertyName = "action")] -[JsonDerivedType(typeof(ContinueWithAuthCredentials), "provideCredentials")] -[JsonDerivedType(typeof(ContinueWithDefaultAuth), "default")] -[JsonDerivedType(typeof(ContinueWithCancelledAuth), "cancel")] -internal abstract record ContinueWithAuthParameters(Request Request) : CommandParameters; - -internal record ContinueWithAuthCredentials(Request Request, AuthCredentials Credentials) : ContinueWithAuthParameters(Request); +[JsonDerivedType(typeof(Credentials), "provideCredentials")] +[JsonDerivedType(typeof(Default), "default")] +[JsonDerivedType(typeof(Cancel), "cancel")] +internal abstract record ContinueWithAuthParameters(Request Request) : CommandParameters +{ + internal record Credentials(Request Request, [property: JsonPropertyName("credentials")] AuthCredentials AuthCredentials) : ContinueWithAuthParameters(Request); -internal record ContinueWithDefaultAuth(Request Request) : ContinueWithAuthParameters(Request); + internal record Default(Request Request) : ContinueWithAuthParameters(Request); -internal record ContinueWithCancelledAuth(Request Request) : ContinueWithAuthParameters(Request); + internal record Cancel(Request Request) : ContinueWithAuthParameters(Request); +} public record ContinueWithAuthOptions : CommandOptions; diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/Cookie.cs b/dotnet/src/webdriver/BiDi/Modules/Network/Cookie.cs index 0c615762e7044..f3a4bedc8f926 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/Cookie.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/Cookie.cs @@ -1,6 +1,8 @@ using System; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record Cookie(string Name, BytesValue Value, string Domain, string Path, long Size, bool HttpOnly, bool Secure, SameSite SameSite) diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/CookieHeader.cs b/dotnet/src/webdriver/BiDi/Modules/Network/CookieHeader.cs index dac9bd7b8260a..e588a87d0acb8 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/CookieHeader.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/CookieHeader.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record CookieHeader(string Name, BytesValue Value); diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/FailRequestCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Network/FailRequestCommand.cs index fe25e4904e34f..f3b01ee692743 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/FailRequestCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/FailRequestCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; internal class FailRequestCommand(FailRequestCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/FetchErrorEventArgs.cs b/dotnet/src/webdriver/BiDi/Modules/Network/FetchErrorEventArgs.cs index ce77fbed5216c..6c911e0009fa7 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/FetchErrorEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/FetchErrorEventArgs.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Modules.BrowsingContext; using System; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record FetchErrorEventArgs(BiDi BiDi, BrowsingContext.BrowsingContext Context, bool IsBlocked, Navigation Navigation, long RedirectCount, RequestData Request, DateTimeOffset Timestamp, string ErrorText) diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/FetchTimingInfo.cs b/dotnet/src/webdriver/BiDi/Modules/Network/FetchTimingInfo.cs index d1b8caf24e5ca..d5980cc2ca141 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/FetchTimingInfo.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/FetchTimingInfo.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record FetchTimingInfo(double TimeOrigin, diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/Header.cs b/dotnet/src/webdriver/BiDi/Modules/Network/Header.cs index d32397f88dbd3..0804a1919dec0 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/Header.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/Header.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record Header(string Name, BytesValue Value); diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/Initiator.cs b/dotnet/src/webdriver/BiDi/Modules/Network/Initiator.cs index 128b69f5097cf..a1449e77928a2 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/Initiator.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/Initiator.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record Initiator(InitiatorType Type) diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/Intercept.cs b/dotnet/src/webdriver/BiDi/Modules/Network/Intercept.cs index 26d71006cc03f..4fd55a7d14b0f 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/Intercept.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/Intercept.cs @@ -3,39 +3,41 @@ using System.Linq; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public class Intercept : IAsyncDisposable { private readonly BiDi _bidi; - protected readonly IList _onBeforeRequestSentSubscriptions = []; - protected readonly IList _onResponseStartedSubscriptions = []; - protected readonly IList _onAuthRequiredSubscriptions = []; - internal Intercept(BiDi bidi, string id) { _bidi = bidi; Id = id; } - public string Id { get; } + internal string Id { get; } + + protected IList OnBeforeRequestSentSubscriptions { get; } = []; + protected IList OnResponseStartedSubscriptions { get; } = []; + protected IList OnAuthRequiredSubscriptions { get; } = []; public async Task RemoveAsync() { await _bidi.Network.RemoveInterceptAsync(this).ConfigureAwait(false); - foreach (var subscription in _onBeforeRequestSentSubscriptions) + foreach (var subscription in OnBeforeRequestSentSubscriptions) { await subscription.UnsubscribeAsync().ConfigureAwait(false); } - foreach (var subscription in _onResponseStartedSubscriptions) + foreach (var subscription in OnResponseStartedSubscriptions) { await subscription.UnsubscribeAsync().ConfigureAwait(false); } - foreach (var subscription in _onAuthRequiredSubscriptions) + foreach (var subscription in OnAuthRequiredSubscriptions) { await subscription.UnsubscribeAsync().ConfigureAwait(false); } @@ -45,21 +47,21 @@ public async Task OnBeforeRequestSentAsync(Func await Filter(args, handler), options).ConfigureAwait(false); - _onBeforeRequestSentSubscriptions.Add(subscription); + OnBeforeRequestSentSubscriptions.Add(subscription); } public async Task OnResponseStartedAsync(Func handler, SubscriptionOptions? options = null) { var subscription = await _bidi.Network.OnResponseStartedAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); - _onResponseStartedSubscriptions.Add(subscription); + OnResponseStartedSubscriptions.Add(subscription); } public async Task OnAuthRequiredAsync(Func handler, SubscriptionOptions? options = null) { var subscription = await _bidi.Network.OnAuthRequiredAsync(async args => await Filter(args, handler), options).ConfigureAwait(false); - _onAuthRequiredSubscriptions.Add(subscription); + OnAuthRequiredSubscriptions.Add(subscription); } private async Task Filter(BeforeRequestSentEventArgs args, Func handler) diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/NetworkModule.cs b/dotnet/src/webdriver/BiDi/Modules/Network/NetworkModule.cs index 65264dbf51a67..7d4eac19a673f 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/NetworkModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/NetworkModule.cs @@ -3,6 +3,8 @@ using System.Threading.Tasks; using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public sealed class NetworkModule(Broker broker) : Module(broker) @@ -47,7 +49,7 @@ public async Task InterceptResponseAsync(Func InterceptAuthenticationAsync(Func handler, AddInterceptOptions? interceptOptions = null, SubscriptionOptions? options = null) + public async Task InterceptAuthAsync(Func handler, AddInterceptOptions? interceptOptions = null, SubscriptionOptions? options = null) { var intercept = await AddInterceptAsync([InterceptPhase.AuthRequired], interceptOptions).ConfigureAwait(false); @@ -113,17 +115,17 @@ internal async Task ProvideResponseAsync(Request request, ProvideResponseOptions internal async Task ContinueWithAuthAsync(Request request, AuthCredentials credentials, ContinueWithAuthOptions? options = null) { - await Broker.ExecuteCommandAsync(new ContinueWithAuthCommand(new ContinueWithAuthCredentials(request, credentials)), options).ConfigureAwait(false); + await Broker.ExecuteCommandAsync(new ContinueWithAuthCommand(new ContinueWithAuthParameters.Credentials(request, credentials)), options).ConfigureAwait(false); } internal async Task ContinueWithAuthAsync(Request request, ContinueWithDefaultAuthOptions? options = null) { - await Broker.ExecuteCommandAsync(new ContinueWithAuthCommand(new ContinueWithDefaultAuth(request)), options).ConfigureAwait(false); + await Broker.ExecuteCommandAsync(new ContinueWithAuthCommand(new ContinueWithAuthParameters.Default(request)), options).ConfigureAwait(false); } internal async Task ContinueWithAuthAsync(Request request, ContinueWithCancelledAuthOptions? options = null) { - await Broker.ExecuteCommandAsync(new ContinueWithAuthCommand(new ContinueWithCancelledAuth(request)), options).ConfigureAwait(false); + await Broker.ExecuteCommandAsync(new ContinueWithAuthCommand(new ContinueWithAuthParameters.Cancel(request)), options).ConfigureAwait(false); } public async Task OnBeforeRequestSentAsync(Func handler, SubscriptionOptions? options = null) @@ -166,7 +168,12 @@ public async Task OnFetchErrorAsync(Action ha return await Broker.SubscribeAsync("network.fetchError", handler, options).ConfigureAwait(false); } - internal async Task OnAuthRequiredAsync(Func handler, SubscriptionOptions? options = null) + public async Task OnAuthRequiredAsync(Func handler, SubscriptionOptions? options = null) + { + return await Broker.SubscribeAsync("network.authRequired", handler, options).ConfigureAwait(false); + } + + public async Task OnAuthRequiredAsync(Action handler, SubscriptionOptions? options = null) { return await Broker.SubscribeAsync("network.authRequired", handler, options).ConfigureAwait(false); } diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/ProvideResponseCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Network/ProvideResponseCommand.cs index 317ac4474b4fa..6dae6fc24556f 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/ProvideResponseCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/ProvideResponseCommand.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Communication; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; internal class ProvideResponseCommand(ProvideResponseCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/RemoveInterceptCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Network/RemoveInterceptCommand.cs index de64aa1200fb7..c592b74e13a1a 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/RemoveInterceptCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/RemoveInterceptCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; internal class RemoveInterceptCommand(RemoveInterceptCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/Request.cs b/dotnet/src/webdriver/BiDi/Modules/Network/Request.cs index 1b68df0768897..f7b93fbebff19 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/Request.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/Request.cs @@ -1,5 +1,7 @@ using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public class Request diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/RequestData.cs b/dotnet/src/webdriver/BiDi/Modules/Network/RequestData.cs index 442db03520234..01cc77f040e79 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/RequestData.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/RequestData.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record RequestData(Request Request, string Url, string Method, IReadOnlyList
Headers, IReadOnlyList Cookies, long HeadersSize, long? BodySize, FetchTimingInfo Timings); diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/ResponseCompletedEventArgs.cs b/dotnet/src/webdriver/BiDi/Modules/Network/ResponseCompletedEventArgs.cs index 81fec792efdfd..75c9aa21332bd 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/ResponseCompletedEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/ResponseCompletedEventArgs.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Modules.BrowsingContext; using System; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record ResponseCompletedEventArgs(BiDi BiDi, BrowsingContext.BrowsingContext Context, bool IsBlocked, Navigation Navigation, long RedirectCount, RequestData Request, DateTimeOffset Timestamp, ResponseData Response) diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/ResponseContent.cs b/dotnet/src/webdriver/BiDi/Modules/Network/ResponseContent.cs index 9647356e7b052..5511c4b24129f 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/ResponseContent.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/ResponseContent.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record ResponseContent(long Size); diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/ResponseData.cs b/dotnet/src/webdriver/BiDi/Modules/Network/ResponseData.cs index 5ac779301b9ab..6096bda7fd8a6 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/ResponseData.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/ResponseData.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record ResponseData(string Url, diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/ResponseStartedEventArgs.cs b/dotnet/src/webdriver/BiDi/Modules/Network/ResponseStartedEventArgs.cs index 0c80739bf4c72..aa3aff6fd5cf9 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/ResponseStartedEventArgs.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/ResponseStartedEventArgs.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Modules.BrowsingContext; using System; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record ResponseStartedEventArgs(BiDi BiDi, BrowsingContext.BrowsingContext Context, bool IsBlocked, Navigation Navigation, long RedirectCount, RequestData Request, DateTimeOffset Timestamp, ResponseData Response) diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/SetCookieHeader.cs b/dotnet/src/webdriver/BiDi/Modules/Network/SetCookieHeader.cs index d11d8ee8a21e5..a73c9171419f0 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/SetCookieHeader.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/SetCookieHeader.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; public record SetCookieHeader(string Name, BytesValue Value) diff --git a/dotnet/src/webdriver/BiDi/Modules/Network/UrlPattern.cs b/dotnet/src/webdriver/BiDi/Modules/Network/UrlPattern.cs index 50226a115f327..30a034fbee4d0 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Network/UrlPattern.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Network/UrlPattern.cs @@ -1,31 +1,31 @@ using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Network; [JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -[JsonDerivedType(typeof(UrlPatternPattern), "pattern")] -[JsonDerivedType(typeof(UrlPatternString), "string")] +[JsonDerivedType(typeof(Pattern), "pattern")] +[JsonDerivedType(typeof(String), "string")] public abstract record UrlPattern { - public static UrlPatternPattern Patter(string? protocol = null, string? hostname = null, string? port = null, string? pathname = null, string? search = null) - => new() { Protocol = protocol, Hostname = hostname, Port = port, Pathname = pathname, Search = search }; + public static implicit operator UrlPattern(string value) => new String(value); - public static UrlPatternString String(string pattern) => new UrlPatternString(pattern); + public record Pattern : UrlPattern + { + public string? Protocol { get; set; } - public static implicit operator UrlPattern(string value) => new UrlPatternString(value); -} + public string? Hostname { get; set; } -public record UrlPatternPattern : UrlPattern -{ - public string? Protocol { get; set; } + public string? Port { get; set; } - public string? Hostname { get; set; } + public string? Pathname { get; set; } - public string? Port { get; set; } + public string? Search { get; set; } + } - public string? Pathname { get; set; } - - public string? Search { get; set; } + public record String(string Pattern) : UrlPattern + { + public new string Pattern { get; } = Pattern; + } } - -public record UrlPatternString(string Pattern) : UrlPattern; diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/AddPreloadScriptCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Script/AddPreloadScriptCommand.cs index 516e65b10f45c..512d79a86900e 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/AddPreloadScriptCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/AddPreloadScriptCommand.cs @@ -1,13 +1,15 @@ using OpenQA.Selenium.BiDi.Communication; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; internal class AddPreloadScriptCommand(AddPreloadScriptCommandParameters @params) : Command(@params); internal record AddPreloadScriptCommandParameters(string FunctionDeclaration) : CommandParameters { - public IEnumerable? Arguments { get; set; } + public IEnumerable? Arguments { get; set; } public IEnumerable? Contexts { get; set; } @@ -24,7 +26,7 @@ internal AddPreloadScriptOptions(BrowsingContextAddPreloadScriptOptions? options Sandbox = options?.Sandbox; } - public IEnumerable? Arguments { get; set; } + public IEnumerable? Arguments { get; set; } public IEnumerable? Contexts { get; set; } @@ -33,7 +35,7 @@ internal AddPreloadScriptOptions(BrowsingContextAddPreloadScriptOptions? options public record BrowsingContextAddPreloadScriptOptions { - public IEnumerable? Arguments { get; set; } + public IEnumerable? Arguments { get; set; } public string? Sandbox { get; set; } } diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/CallFunctionCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Script/CallFunctionCommand.cs index 08c9800911044..9ff03a72896f4 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/CallFunctionCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/CallFunctionCommand.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Communication; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; internal class CallFunctionCommand(CallFunctionCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/Channel.cs b/dotnet/src/webdriver/BiDi/Modules/Script/Channel.cs index a828d9a4caff3..6518aee1d5388 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/Channel.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/Channel.cs @@ -1,14 +1,5 @@ -namespace OpenQA.Selenium.BiDi.Modules.Script; - -public class Channel -{ - readonly BiDi _bidi; +#nullable enable - internal Channel(BiDi bidi, string id) - { - _bidi = bidi; - Id = id; - } +namespace OpenQA.Selenium.BiDi.Modules.Script; - internal string Id { get; } -} +public record Channel(string Id); diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/ChannelValue.cs b/dotnet/src/webdriver/BiDi/Modules/Script/ChannelValue.cs deleted file mode 100644 index 4b92a7dc15b96..0000000000000 --- a/dotnet/src/webdriver/BiDi/Modules/Script/ChannelValue.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace OpenQA.Selenium.BiDi.Modules.Script; - -public record ChannelValue : LocalValue -{ - public string Type => "channel"; -} - -public record ChannelProperties(Channel Channel) -{ - public SerializationOptions? SerializationOptions { get; set; } - - public ResultOwnership? Ownership { get; set; } -} diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/DisownCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Script/DisownCommand.cs index dfe04fc14e0be..b09ab31da07b3 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/DisownCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/DisownCommand.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Communication; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; internal class DisownCommand(DisownCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/EvaluateCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Script/EvaluateCommand.cs index 307a9156e8b4b..8ccba001543af 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/EvaluateCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/EvaluateCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; internal class EvaluateCommand(EvaluateCommandParameters @params) : Command(@params); @@ -24,12 +26,16 @@ public record EvaluateOptions : CommandOptions // https://github.com/dotnet/runtime/issues/72604 //[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -//[JsonDerivedType(typeof(EvaluateResultSuccess), "success")] -//[JsonDerivedType(typeof(EvaluateResultException), "exception")] -public abstract record EvaluateResult; - -public record EvaluateResultSuccess(RemoteValue Result) : EvaluateResult; +//[JsonDerivedType(typeof(Success), "success")] +//[JsonDerivedType(typeof(Exception), "exception")] +public abstract record EvaluateResult +{ + public record Success(RemoteValue Result, Realm Realm) : EvaluateResult + { + public static implicit operator RemoteValue(Success success) => success.Result; + } -public record EvaluateResultException(ExceptionDetails ExceptionDetails) : EvaluateResult; + public record Exception(ExceptionDetails ExceptionDetails, Realm Realm) : EvaluateResult; +} public record ExceptionDetails(long ColumnNumber, long LineNumber, StackTrace StackTrace, string Text); diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/GetRealmsCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Script/GetRealmsCommand.cs index 98d4a03ba785f..e5730a9d21a06 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/GetRealmsCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/GetRealmsCommand.cs @@ -1,6 +1,9 @@ using OpenQA.Selenium.BiDi.Communication; +using System.Collections; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; internal class GetRealmsCommand(GetRealmsCommandParameters @params) : Command(@params); @@ -19,4 +22,20 @@ public record GetRealmsOptions : CommandOptions public RealmType? Type { get; set; } } -internal record GetRealmsResult(IReadOnlyList Realms); +public record GetRealmsResult : IReadOnlyList +{ + private readonly IReadOnlyList _realms; + + internal GetRealmsResult(IReadOnlyList realms) + { + _realms = realms; + } + + public RealmInfo this[int index] => _realms[index]; + + public int Count => _realms.Count; + + public IEnumerator GetEnumerator() => _realms.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => (_realms as IEnumerable).GetEnumerator(); +} diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/Handle.cs b/dotnet/src/webdriver/BiDi/Modules/Script/Handle.cs index 2e2649af926cf..8323bea292827 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/Handle.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/Handle.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; public class Handle diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/InternalId.cs b/dotnet/src/webdriver/BiDi/Modules/Script/InternalId.cs index 89e08f58f9121..1a34d8bd61bb5 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/InternalId.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/InternalId.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; public class InternalId diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/LocalValue.cs b/dotnet/src/webdriver/BiDi/Modules/Script/LocalValue.cs index 3451352ab962d..2b162c438dd3d 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/LocalValue.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/LocalValue.cs @@ -1,31 +1,36 @@ using System.Collections.Generic; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; [JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -[JsonDerivedType(typeof(NumberLocalValue), "number")] -[JsonDerivedType(typeof(StringLocalValue), "string")] -[JsonDerivedType(typeof(NullLocalValue), "null")] -[JsonDerivedType(typeof(UndefinedLocalValue), "undefined")] -[JsonDerivedType(typeof(ArrayLocalValue), "array")] -[JsonDerivedType(typeof(DateLocalValue), "date")] -[JsonDerivedType(typeof(MapLocalValue), "map")] -[JsonDerivedType(typeof(ObjectLocalValue), "object")] -[JsonDerivedType(typeof(RegExpLocalValue), "regexp")] -[JsonDerivedType(typeof(SetLocalValue), "set")] +[JsonDerivedType(typeof(Number), "number")] +[JsonDerivedType(typeof(String), "string")] +[JsonDerivedType(typeof(Null), "null")] +[JsonDerivedType(typeof(Undefined), "undefined")] +[JsonDerivedType(typeof(Channel), "channel")] +[JsonDerivedType(typeof(Array), "array")] +[JsonDerivedType(typeof(Date), "date")] +[JsonDerivedType(typeof(Map), "map")] +[JsonDerivedType(typeof(Object), "object")] +[JsonDerivedType(typeof(RegExp), "regexp")] +[JsonDerivedType(typeof(Set), "set")] public abstract record LocalValue { - public static implicit operator LocalValue(int value) { return new NumberLocalValue(value); } - public static implicit operator LocalValue(string value) { return new StringLocalValue(value); } + public static implicit operator LocalValue(int value) { return new Number(value); } + public static implicit operator LocalValue(string value) { return new String(value); } // TODO: Extend converting from types public static LocalValue ConvertFrom(object? value) { switch (value) { + case LocalValue: + return (LocalValue)value; case null: - return new NullLocalValue(); + return new Null(); case int: return (int)value; case string: @@ -43,41 +48,55 @@ public static LocalValue ConvertFrom(object? value) values.Add([property.Name, ConvertFrom(property.GetValue(value))]); } - return new ObjectLocalValue(values); + return new Object(values); } } } -} -public abstract record PrimitiveProtocolLocalValue : LocalValue -{ + public abstract record PrimitiveProtocolLocalValue : LocalValue + { -} + } -public record NumberLocalValue(long Value) : PrimitiveProtocolLocalValue -{ - public static explicit operator NumberLocalValue(int n) => new NumberLocalValue(n); -} + public record Number(long Value) : PrimitiveProtocolLocalValue + { + public static explicit operator Number(int n) => new Number(n); + } -public record StringLocalValue(string Value) : PrimitiveProtocolLocalValue; + public record String(string Value) : PrimitiveProtocolLocalValue; -public record NullLocalValue : PrimitiveProtocolLocalValue; + public record Null : PrimitiveProtocolLocalValue; -public record UndefinedLocalValue : PrimitiveProtocolLocalValue; + public record Undefined : PrimitiveProtocolLocalValue; -public record ArrayLocalValue(IEnumerable Value) : LocalValue; + public record Channel(Channel.ChannelProperties Value) : LocalValue + { + [JsonInclude] + internal string type = "channel"; -public record DateLocalValue(string Value) : LocalValue; + public record ChannelProperties(Script.Channel Channel) + { + public SerializationOptions? SerializationOptions { get; set; } -public record MapLocalValue(IDictionary Value) : LocalValue; // seems to implement IDictionary + public ResultOwnership? Ownership { get; set; } + } + } -public record ObjectLocalValue(IEnumerable> Value) : LocalValue; + public record Array(IEnumerable Value) : LocalValue; -public record RegExpLocalValue(RegExpValue Value) : LocalValue; + public record Date(string Value) : LocalValue; -public record RegExpValue(string Pattern) -{ - public string? Flags { get; set; } -} + public record Map(IDictionary Value) : LocalValue; // seems to implement IDictionary + + public record Object(IEnumerable> Value) : LocalValue; -public record SetLocalValue(IEnumerable Value) : LocalValue; + public record RegExp(RegExp.RegExpValue Value) : LocalValue + { + public record RegExpValue(string Pattern) + { + public string? Flags { get; set; } + } + } + + public record Set(IEnumerable Value) : LocalValue; +} diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/MessageEventArgs.cs b/dotnet/src/webdriver/BiDi/Modules/Script/MessageEventArgs.cs new file mode 100644 index 0000000000000..e6062a76262c1 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Modules/Script/MessageEventArgs.cs @@ -0,0 +1,5 @@ +#nullable enable + +namespace OpenQA.Selenium.BiDi.Modules.Script; + +public record MessageEventArgs(BiDi BiDi, Channel Channel, RemoteValue Data, Source Source) : EventArgs(BiDi); diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/NodeProperties.cs b/dotnet/src/webdriver/BiDi/Modules/Script/NodeProperties.cs index 87bf2680efa6f..5cc214fcd225c 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/NodeProperties.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/NodeProperties.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; public record NodeProperties(long NodeType, long ChildNodeCount) @@ -9,7 +11,7 @@ public record NodeProperties(long NodeType, long ChildNodeCount) public IReadOnlyDictionary? Attributes { get; internal set; } [JsonInclude] - public IReadOnlyList? Children { get; internal set; } + public IReadOnlyList? Children { get; internal set; } [JsonInclude] public string? LocalName { get; internal set; } @@ -24,5 +26,5 @@ public record NodeProperties(long NodeType, long ChildNodeCount) public string? NodeValue { get; internal set; } [JsonInclude] - public NodeRemoteValue? ShadowRoot { get; internal set; } + public RemoteValue.Node? ShadowRoot { get; internal set; } } diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/PreloadScript.cs b/dotnet/src/webdriver/BiDi/Modules/Script/PreloadScript.cs index a59b9c099f05d..1b9027f21cf39 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/PreloadScript.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/PreloadScript.cs @@ -1,6 +1,8 @@ using System; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; public class PreloadScript : IAsyncDisposable @@ -17,7 +19,7 @@ public PreloadScript(BiDi bidi, string id) public Task RemoveAsync() { - return _bidi.ScriptModule.RemovePreloadScriptAsync(this); + return _bidi.Script.RemovePreloadScriptAsync(this); } public async ValueTask DisposeAsync() diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/Realm.cs b/dotnet/src/webdriver/BiDi/Modules/Script/Realm.cs index 0b8bf28fdf994..a690df5eabd91 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/Realm.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/Realm.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; public class Realm diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/RealmDestroyedEventArgs.cs b/dotnet/src/webdriver/BiDi/Modules/Script/RealmDestroyedEventArgs.cs new file mode 100644 index 0000000000000..b5d30f09c5fd3 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Modules/Script/RealmDestroyedEventArgs.cs @@ -0,0 +1,5 @@ +#nullable enable + +namespace OpenQA.Selenium.BiDi.Modules.Script; + +public record RealmDestroyedEventArgs(BiDi BiDi, Realm Realm) : EventArgs(BiDi); diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/RealmInfo.cs b/dotnet/src/webdriver/BiDi/Modules/Script/RealmInfo.cs index 4d88aa5e7b25c..4715be57392a7 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/RealmInfo.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/RealmInfo.cs @@ -1,36 +1,37 @@ using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; // https://github.com/dotnet/runtime/issues/72604 //[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -//[JsonDerivedType(typeof(WindowRealmInfo), "window")] -//[JsonDerivedType(typeof(DedicatedWorkerRealmInfo), "dedicated-worker")] -//[JsonDerivedType(typeof(SharedWorkerRealmInfo), "shared-worker")] -//[JsonDerivedType(typeof(ServiceWorkerRealmInfo), "service-worker")] -//[JsonDerivedType(typeof(WorkerRealmInfo), "worker")] -//[JsonDerivedType(typeof(PaintWorkletRealmInfo), "paint-worklet")] -//[JsonDerivedType(typeof(AudioWorkletRealmInfo), "audio-worklet")] -//[JsonDerivedType(typeof(WorkletRealmInfo), "worklet")] -public abstract record RealmInfo(BiDi BiDi) : EventArgs(BiDi); - -public abstract record BaseRealmInfo(BiDi BiDi, Realm Realm, string Origin) : RealmInfo(BiDi); - -public record WindowRealmInfo(BiDi BiDi, Realm Realm, string Origin, BrowsingContext.BrowsingContext Context) : BaseRealmInfo(BiDi, Realm, Origin) +//[JsonDerivedType(typeof(Window), "window")] +//[JsonDerivedType(typeof(DedicatedWorker), "dedicated-worker")] +//[JsonDerivedType(typeof(SharedWorker), "shared-worker")] +//[JsonDerivedType(typeof(ServiceWorker), "service-worker")] +//[JsonDerivedType(typeof(Worker), "worker")] +//[JsonDerivedType(typeof(PaintWorklet), "paint-worklet")] +//[JsonDerivedType(typeof(AudioWorklet), "audio-worklet")] +//[JsonDerivedType(typeof(Worklet), "worklet")] +public abstract record RealmInfo(BiDi BiDi, Realm Realm, string Origin) : EventArgs(BiDi) { - public string? Sandbox { get; set; } -} + public record Window(BiDi BiDi, Realm Realm, string Origin, BrowsingContext.BrowsingContext Context) : RealmInfo(BiDi, Realm, Origin) + { + public string? Sandbox { get; set; } + } -public record DedicatedWorkerRealmInfo(BiDi BiDi, Realm Realm, string Origin, IReadOnlyList Owners) : BaseRealmInfo(BiDi, Realm, Origin); + public record DedicatedWorker(BiDi BiDi, Realm Realm, string Origin, IReadOnlyList Owners) : RealmInfo(BiDi, Realm, Origin); -public record SharedWorkerRealmInfo(BiDi BiDi, Realm Realm, string Origin) : BaseRealmInfo(BiDi, Realm, Origin); + public record SharedWorker(BiDi BiDi, Realm Realm, string Origin) : RealmInfo(BiDi, Realm, Origin); -public record ServiceWorkerRealmInfo(BiDi BiDi, Realm Realm, string Origin) : BaseRealmInfo(BiDi, Realm, Origin); + public record ServiceWorker(BiDi BiDi, Realm Realm, string Origin) : RealmInfo(BiDi, Realm, Origin); -public record WorkerRealmInfo(BiDi BiDi, Realm Realm, string Origin) : BaseRealmInfo(BiDi, Realm, Origin); + public record Worker(BiDi BiDi, Realm Realm, string Origin) : RealmInfo(BiDi, Realm, Origin); -public record PaintWorkletRealmInfo(BiDi BiDi, Realm Realm, string Origin) : BaseRealmInfo(BiDi, Realm, Origin); + public record PaintWorklet(BiDi BiDi, Realm Realm, string Origin) : RealmInfo(BiDi, Realm, Origin); -public record AudioWorkletRealmInfo(BiDi BiDi, Realm Realm, string Origin) : BaseRealmInfo(BiDi, Realm, Origin); + public record AudioWorklet(BiDi BiDi, Realm Realm, string Origin) : RealmInfo(BiDi, Realm, Origin); -public record WorkletRealmInfo(BiDi BiDi, Realm Realm, string Origin) : BaseRealmInfo(BiDi, Realm, Origin); + public record Worklet(BiDi BiDi, Realm Realm, string Origin) : RealmInfo(BiDi, Realm, Origin); +} diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/RealmType.cs b/dotnet/src/webdriver/BiDi/Modules/Script/RealmType.cs index 0db521054c4d9..08444b2666830 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/RealmType.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/RealmType.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; public enum RealmType diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/RemoteReference.cs b/dotnet/src/webdriver/BiDi/Modules/Script/RemoteReference.cs index f936501b0cb14..ac64940070e7e 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/RemoteReference.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/RemoteReference.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; public abstract record RemoteReference : LocalValue; diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/RemoteValue.cs b/dotnet/src/webdriver/BiDi/Modules/Script/RemoteValue.cs index 0ce3be3404fa5..074ab2570b43e 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/RemoteValue.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/RemoteValue.cs @@ -1,44 +1,49 @@ using System; using System.Collections.Generic; +using System.Text.Json; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; // https://github.com/dotnet/runtime/issues/72604 //[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -//[JsonDerivedType(typeof(NumberRemoteValue), "number")] -//[JsonDerivedType(typeof(StringRemoteValue), "string")] -//[JsonDerivedType(typeof(NullRemoteValue), "null")] -//[JsonDerivedType(typeof(UndefinedRemoteValue), "undefined")] -//[JsonDerivedType(typeof(SymbolRemoteValue), "symbol")] -//[JsonDerivedType(typeof(ObjectRemoteValue), "object")] -//[JsonDerivedType(typeof(FunctionRemoteValue), "function")] -//[JsonDerivedType(typeof(RegExpRemoteValue), "regexp")] -//[JsonDerivedType(typeof(DateRemoteValue), "date")] -//[JsonDerivedType(typeof(MapRemoteValue), "map")] -//[JsonDerivedType(typeof(SetRemoteValue), "set")] -//[JsonDerivedType(typeof(WeakMapRemoteValue), "weakmap")] -//[JsonDerivedType(typeof(WeakSetRemoteValue), "weakset")] -//[JsonDerivedType(typeof(GeneratorRemoteValue), "generator")] -//[JsonDerivedType(typeof(ErrorRemoteValue), "error")] -//[JsonDerivedType(typeof(ProxyRemoteValue), "proxy")] -//[JsonDerivedType(typeof(PromiseRemoteValue), "promise")] -//[JsonDerivedType(typeof(TypedArrayRemoteValue), "typedarray")] -//[JsonDerivedType(typeof(ArrayBufferRemoteValue), "arraybuffer")] -//[JsonDerivedType(typeof(NodeListRemoteValue), "nodelist")] -//[JsonDerivedType(typeof(HtmlCollectionRemoteValue), "htmlcollection")] -//[JsonDerivedType(typeof(NodeRemoteValue), "node")] -//[JsonDerivedType(typeof(WindowProxyRemoteValue), "window")] +//[JsonDerivedType(typeof(Number), "number")] +//[JsonDerivedType(typeof(Boolean), "boolean")] +//[JsonDerivedType(typeof(String), "string")] +//[JsonDerivedType(typeof(Null), "null")] +//[JsonDerivedType(typeof(Undefined), "undefined")] +//[JsonDerivedType(typeof(Symbol), "symbol")] +//[JsonDerivedType(typeof(Array), "array")] +//[JsonDerivedType(typeof(Object), "object")] +//[JsonDerivedType(typeof(Function), "function")] +//[JsonDerivedType(typeof(RegExp), "regexp")] +//[JsonDerivedType(typeof(Date), "date")] +//[JsonDerivedType(typeof(Map), "map")] +//[JsonDerivedType(typeof(Set), "set")] +//[JsonDerivedType(typeof(WeakMap), "weakmap")] +//[JsonDerivedType(typeof(WeakSet), "weakset")] +//[JsonDerivedType(typeof(Generator), "generator")] +//[JsonDerivedType(typeof(Error), "error")] +//[JsonDerivedType(typeof(Proxy), "proxy")] +//[JsonDerivedType(typeof(Promise), "promise")] +//[JsonDerivedType(typeof(TypedArray), "typedarray")] +//[JsonDerivedType(typeof(ArrayBuffer), "arraybuffer")] +//[JsonDerivedType(typeof(NodeList), "nodelist")] +//[JsonDerivedType(typeof(HtmlCollection), "htmlcollection")] +//[JsonDerivedType(typeof(Node), "node")] +//[JsonDerivedType(typeof(WindowProxy), "window")] public abstract record RemoteValue { - public static implicit operator int(RemoteValue remoteValue) => (int)((NumberRemoteValue)remoteValue).Value; - public static implicit operator long(RemoteValue remoteValue) => ((NumberRemoteValue)remoteValue).Value; + public static implicit operator int(RemoteValue remoteValue) => (int)((Number)remoteValue).Value; + public static implicit operator long(RemoteValue remoteValue) => ((Number)remoteValue).Value; public static implicit operator string(RemoteValue remoteValue) { return remoteValue switch { - StringRemoteValue stringValue => stringValue.Value, - NullRemoteValue => null!, + String stringValue => stringValue.Value, + Null => null!, _ => throw new BiDiException($"Cannot convert {remoteValue} to string") }; } @@ -48,13 +53,17 @@ public static implicit operator string(RemoteValue remoteValue) { var type = typeof(TResult); + if (type == typeof(bool)) + { + return (TResult)(Convert.ToBoolean(((Boolean)this).Value) as object); + } if (type == typeof(int)) { - return (TResult)(Convert.ToInt32(((NumberRemoteValue)this).Value) as object); + return (TResult)(Convert.ToInt32(((Number)this).Value) as object); } else if (type == typeof(string)) { - return (TResult)(((StringRemoteValue)this).Value as object); + return (TResult)(((String)this).Value as object); } else if (type is object) { @@ -64,177 +73,184 @@ public static implicit operator string(RemoteValue remoteValue) throw new BiDiException("Cannot convert ....."); } -} -public abstract record PrimitiveProtocolRemoteValue : RemoteValue; + public record Number(long Value) : PrimitiveProtocolRemoteValue; -public record NumberRemoteValue(long Value) : PrimitiveProtocolRemoteValue; + public record Boolean(bool Value) : PrimitiveProtocolRemoteValue; -public record StringRemoteValue(string Value) : PrimitiveProtocolRemoteValue; + public record String(string Value) : PrimitiveProtocolRemoteValue; -public record NullRemoteValue : PrimitiveProtocolRemoteValue; + public record Null : PrimitiveProtocolRemoteValue; -public record UndefinedRemoteValue : PrimitiveProtocolRemoteValue; + public record Undefined : PrimitiveProtocolRemoteValue; -public record SymbolRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public record Symbol : RemoteValue + { + public Handle? Handle { get; set; } - public InternalId? InternalId { get; set; } -} + public InternalId? InternalId { get; set; } + } -public record ArrayRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public record Array : RemoteValue + { + public Handle? Handle { get; set; } - public InternalId? InternalId { get; set; } + public InternalId? InternalId { get; set; } - public IReadOnlyList? Value { get; set; } -} + public IReadOnlyList? Value { get; set; } + } -public record ObjectRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public record Object : RemoteValue + { + public Handle? Handle { get; set; } - public InternalId? InternalId { get; set; } + public InternalId? InternalId { get; set; } - public IReadOnlyList>? Value { get; set; } -} + public IReadOnlyList>? Value { get; set; } + } -public record FunctionRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public record Function : RemoteValue + { + public Handle? Handle { get; set; } - public InternalId? InternalId { get; set; } -} + public InternalId? InternalId { get; set; } + } -public record RegExpRemoteValue(RegExpValue Value) : RemoteValue -{ - public Handle? Handle { get; set; } + public record RegExp(RegExp.RegExpValue Value) : RemoteValue + { + public Handle? Handle { get; set; } - public InternalId? InternalId { get; set; } -} + public InternalId? InternalId { get; set; } -public record DateRemoteValue(string Value) : RemoteValue -{ - public Handle? Handle { get; set; } + public record RegExpValue(string Pattern) + { + public string? Flags { get; set; } + } + } - public InternalId? InternalId { get; set; } -} + public record Date(string Value) : RemoteValue + { + public Handle? Handle { get; set; } -public record MapRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public InternalId? InternalId { get; set; } + } - public InternalId? InternalId { get; set; } + public record Map : RemoteValue + { + public Handle? Handle { get; set; } - public IDictionary? Value { get; set; } -} + public InternalId? InternalId { get; set; } -public record SetRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public IDictionary? Value { get; set; } + } - public InternalId? InternalId { get; set; } + public record Set : RemoteValue + { + public Handle? Handle { get; set; } - public IReadOnlyList? Value { get; set; } -} + public InternalId? InternalId { get; set; } -public record WeakMapRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public IReadOnlyList? Value { get; set; } + } - public InternalId? InternalId { get; set; } -} + public record WeakMap : RemoteValue + { + public Handle? Handle { get; set; } -public record WeakSetRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public InternalId? InternalId { get; set; } + } - public InternalId? InternalId { get; set; } -} + public record WeakSet : RemoteValue + { + public Handle? Handle { get; set; } -public record GeneratorRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public InternalId? InternalId { get; set; } + } - public InternalId? InternalId { get; set; } -} + public record Generator : RemoteValue + { + public Handle? Handle { get; set; } -public record ErrorRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public InternalId? InternalId { get; set; } + } - public InternalId? InternalId { get; set; } -} + public record Error : RemoteValue + { + public Handle? Handle { get; set; } -public record ProxyRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public InternalId? InternalId { get; set; } + } - public InternalId? InternalId { get; set; } -} + public record Proxy : RemoteValue + { + public Handle? Handle { get; set; } -public record PromiseRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public InternalId? InternalId { get; set; } + } - public InternalId? InternalId { get; set; } -} + public record Promise : RemoteValue + { + public Handle? Handle { get; set; } -public record TypedArrayRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public InternalId? InternalId { get; set; } + } - public InternalId? InternalId { get; set; } -} + public record TypedArray : RemoteValue + { + public Handle? Handle { get; set; } -public record ArrayBufferRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public InternalId? InternalId { get; set; } + } - public InternalId? InternalId { get; set; } -} + public record ArrayBuffer : RemoteValue + { + public Handle? Handle { get; set; } -public record NodeListRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public InternalId? InternalId { get; set; } + } - public InternalId? InternalId { get; set; } + public record NodeList : RemoteValue + { + public Handle? Handle { get; set; } - public IReadOnlyList? Value { get; set; } -} + public InternalId? InternalId { get; set; } -public record HtmlCollectionRemoteValue : RemoteValue -{ - public Handle? Handle { get; set; } + public IReadOnlyList? Value { get; set; } + } - public InternalId? InternalId { get; set; } + public record HtmlCollection : RemoteValue + { + public Handle? Handle { get; set; } - public IReadOnlyList? Value { get; set; } -} + public InternalId? InternalId { get; set; } -public record NodeRemoteValue : RemoteValue -{ - [JsonInclude] - public string? SharedId { get; internal set; } + public IReadOnlyList? Value { get; set; } + } - public Handle? Handle { get; set; } + public record Node : RemoteValue + { + [JsonInclude] + public string? SharedId { get; internal set; } - public InternalId? InternalId { get; set; } + public Handle? Handle { get; set; } - [JsonInclude] - public NodeProperties? Value { get; internal set; } -} + public InternalId? InternalId { get; set; } -public record WindowProxyRemoteValue(WindowProxyProperties Value) : RemoteValue -{ - public Handle? Handle { get; set; } + [JsonInclude] + public NodeProperties? Value { get; internal set; } + } - public InternalId? InternalId { get; set; } + public record WindowProxy(WindowProxy.Properties Value) : RemoteValue + { + public Handle? Handle { get; set; } + + public InternalId? InternalId { get; set; } + + public record Properties(BrowsingContext.BrowsingContext Context); + } } -public record WindowProxyProperties(BrowsingContext.BrowsingContext Context); +public abstract record PrimitiveProtocolRemoteValue : RemoteValue; public enum Mode { diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/RemovePreloadScriptCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Script/RemovePreloadScriptCommand.cs index a64d5dd42775c..850ab9ecc0f6c 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/RemovePreloadScriptCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/RemovePreloadScriptCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; internal class RemovePreloadScriptCommand(RemovePreloadScriptCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/ResultOwnership.cs b/dotnet/src/webdriver/BiDi/Modules/Script/ResultOwnership.cs index 68e77e72a1f01..c69595bc3293c 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/ResultOwnership.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/ResultOwnership.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; public enum ResultOwnership diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/ScriptEvaluateException.cs b/dotnet/src/webdriver/BiDi/Modules/Script/ScriptEvaluateException.cs index 2270835f32639..4daa2cc704b1c 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/ScriptEvaluateException.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/ScriptEvaluateException.cs @@ -1,10 +1,12 @@ using System; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; -public class ScriptEvaluateException(EvaluateResultException evaluateResultException) : Exception +public class ScriptEvaluateException(EvaluateResult.Exception evaluateResultException) : Exception { - private readonly EvaluateResultException _evaluateResultException = evaluateResultException; + private readonly EvaluateResult.Exception _evaluateResultException = evaluateResultException; public string Text => _evaluateResultException.ExceptionDetails.Text; diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/ScriptModule.cs b/dotnet/src/webdriver/BiDi/Modules/Script/ScriptModule.cs index b5e8f2ae61b22..fee6e4a10dcfc 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/ScriptModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/ScriptModule.cs @@ -1,13 +1,16 @@ using OpenQA.Selenium.BiDi.Communication; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; public sealed class ScriptModule(Broker broker) : Module(broker) { - public async Task EvaluateAsync(string expression, bool awaitPromise, Target target, EvaluateOptions? options = null) + public async Task EvaluateAsync(string expression, bool awaitPromise, Target target, EvaluateOptions? options = null) { var @params = new EvaluateCommandParameters(expression, target, awaitPromise); @@ -20,15 +23,22 @@ public async Task EvaluateAsync(string expression, bool awaitPromis var result = await Broker.ExecuteCommandAsync(new EvaluateCommand(@params), options).ConfigureAwait(false); - if (result is EvaluateResultException exp) + if (result is EvaluateResult.Exception exp) { throw new ScriptEvaluateException(exp); } - return ((EvaluateResultSuccess)result).Result; + return (EvaluateResult.Success)result; } - public async Task CallFunctionAsync(string functionDeclaration, bool awaitPromise, Target target, CallFunctionOptions? options = null) + public async Task EvaluateAsync(string expression, bool awaitPromise, Target target, EvaluateOptions? options = null) + { + var result = await EvaluateAsync(expression, awaitPromise, target, options).ConfigureAwait(false); + + return result.Result.ConvertTo(); + } + + public async Task CallFunctionAsync(string functionDeclaration, bool awaitPromise, Target target, CallFunctionOptions? options = null) { var @params = new CallFunctionCommandParameters(functionDeclaration, awaitPromise, target); @@ -43,15 +53,22 @@ public async Task CallFunctionAsync(string functionDeclaration, boo var result = await Broker.ExecuteCommandAsync(new CallFunctionCommand(@params), options).ConfigureAwait(false); - if (result is EvaluateResultException exp) + if (result is EvaluateResult.Exception exp) { throw new ScriptEvaluateException(exp); } - return ((EvaluateResultSuccess)result).Result; + return (EvaluateResult.Success)result; + } + + public async Task CallFunctionAsync(string functionDeclaration, bool awaitPromise, Target target, CallFunctionOptions? options = null) + { + var result = await CallFunctionAsync(functionDeclaration, awaitPromise, target, options).ConfigureAwait(false); + + return result.Result.ConvertTo(); } - public async Task> GetRealmsAsync(GetRealmsOptions? options = null) + public async Task GetRealmsAsync(GetRealmsOptions? options = null) { var @params = new GetRealmsCommandParameters(); @@ -61,9 +78,7 @@ public async Task> GetRealmsAsync(GetRealmsOptions? opt @params.Type = options.Type; } - var result = await Broker.ExecuteCommandAsync(new GetRealmsCommand(@params), options).ConfigureAwait(false); - - return result.Realms; + return await Broker.ExecuteCommandAsync(new GetRealmsCommand(@params), options).ConfigureAwait(false); } public async Task AddPreloadScriptAsync(string functionDeclaration, AddPreloadScriptOptions? options = null) @@ -88,4 +103,34 @@ public async Task RemovePreloadScriptAsync(PreloadScript script, RemovePreloadSc await Broker.ExecuteCommandAsync(new RemovePreloadScriptCommand(@params), options).ConfigureAwait(false); } + + public async Task OnMessageAsync(Func handler, SubscriptionOptions? options = null) + { + return await Broker.SubscribeAsync("script.message", handler, options).ConfigureAwait(false); + } + + public async Task OnMessageAsync(Action handler, SubscriptionOptions? options = null) + { + return await Broker.SubscribeAsync("script.message", handler, options).ConfigureAwait(false); + } + + public async Task OnRealmCreatedAsync(Func handler, SubscriptionOptions? options = null) + { + return await Broker.SubscribeAsync("script.realmCreated", handler, options).ConfigureAwait(false); + } + + public async Task OnRealmCreatedAsync(Action handler, SubscriptionOptions? options = null) + { + return await Broker.SubscribeAsync("script.realmCreated", handler, options).ConfigureAwait(false); + } + + public async Task OnRealmDestroyedAsync(Func handler, SubscriptionOptions? options = null) + { + return await Broker.SubscribeAsync("script.realmDestroyed", handler, options).ConfigureAwait(false); + } + + public async Task OnRealmDestroyedAsync(Action handler, SubscriptionOptions? options = null) + { + return await Broker.SubscribeAsync("script.realmDestroyed", handler, options).ConfigureAwait(false); + } } diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/SerializationOptions.cs b/dotnet/src/webdriver/BiDi/Modules/Script/SerializationOptions.cs index 57659570eaaf4..bbb275cc08c2f 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/SerializationOptions.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/SerializationOptions.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; public class SerializationOptions diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/Source.cs b/dotnet/src/webdriver/BiDi/Modules/Script/Source.cs index 309ac31a0ba75..27bdbcad6f695 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/Source.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/Source.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; public record Source(Realm Realm) diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/StackFrame.cs b/dotnet/src/webdriver/BiDi/Modules/Script/StackFrame.cs index 7e3694e9a5e68..208485e0bd636 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/StackFrame.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/StackFrame.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; public record StackFrame(long LineNumber, long ColumnNumber, string Url, string FunctionName); diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/StackTrace.cs b/dotnet/src/webdriver/BiDi/Modules/Script/StackTrace.cs index b9ec5c6bf1d0a..15bbfd829bb1e 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/StackTrace.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/StackTrace.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Script; public record StackTrace(IReadOnlyCollection CallFrames); diff --git a/dotnet/src/webdriver/BiDi/Modules/Script/Target.cs b/dotnet/src/webdriver/BiDi/Modules/Script/Target.cs index 7c20cb8b33b6f..a05849a62c8b9 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Script/Target.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Script/Target.cs @@ -1,16 +1,19 @@ using System.Text.Json.Serialization; -namespace OpenQA.Selenium.BiDi.Modules.Script; - -[JsonDerivedType(typeof(RealmTarget))] -[JsonDerivedType(typeof(ContextTarget))] -public abstract record Target; +#nullable enable -public record RealmTarget(Realm Realm) : Target; +namespace OpenQA.Selenium.BiDi.Modules.Script; -public record ContextTarget(BrowsingContext.BrowsingContext Context) : Target +[JsonDerivedType(typeof(Realm))] +[JsonDerivedType(typeof(Context))] +public abstract record Target { - public string? Sandbox { get; set; } + public record Realm([property: JsonPropertyName("realm")] Script.Realm Target) : Target; + + public record Context([property: JsonPropertyName("context")] BrowsingContext.BrowsingContext Target) : Target + { + public string? Sandbox { get; set; } + } } public class ContextTargetOptions diff --git a/dotnet/src/webdriver/BiDi/Modules/Session/CapabilitiesRequest.cs b/dotnet/src/webdriver/BiDi/Modules/Session/CapabilitiesRequest.cs index be4c7ac6d69db..542f9e1c3f076 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Session/CapabilitiesRequest.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Session/CapabilitiesRequest.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Session; public class CapabilitiesRequest diff --git a/dotnet/src/webdriver/BiDi/Modules/Session/CapabilityRequest.cs b/dotnet/src/webdriver/BiDi/Modules/Session/CapabilityRequest.cs index 1cd33a08be0ad..b449e984bb540 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Session/CapabilityRequest.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Session/CapabilityRequest.cs @@ -1,3 +1,5 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Session; public class CapabilityRequest diff --git a/dotnet/src/webdriver/BiDi/Modules/Session/EndCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Session/EndCommand.cs index 73180d2cd6bda..a41d0be7c2ded 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Session/EndCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Session/EndCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Session; internal class EndCommand() : Command(CommandParameters.Empty); diff --git a/dotnet/src/webdriver/BiDi/Modules/Session/NewCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Session/NewCommand.cs index 3c965e0f1d505..97759165116a2 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Session/NewCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Session/NewCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Session; internal class NewCommand(NewCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Session/ProxyConfiguration.cs b/dotnet/src/webdriver/BiDi/Modules/Session/ProxyConfiguration.cs index 171dbb0ec8c2b..4243dbbaf69c1 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Session/ProxyConfiguration.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Session/ProxyConfiguration.cs @@ -1,32 +1,35 @@ using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Session; [JsonPolymorphic(TypeDiscriminatorPropertyName = "proxyType")] -[JsonDerivedType(typeof(AutodetectProxyConfiguration), "autodetect")] -[JsonDerivedType(typeof(DirectProxyConfiguration), "direct")] -[JsonDerivedType(typeof(ManualProxyConfiguration), "manual")] -[JsonDerivedType(typeof(PacProxyConfiguration), "pac")] -[JsonDerivedType(typeof(SystemProxyConfiguration), "system")] -public abstract record ProxyConfiguration; - -public record AutodetectProxyConfiguration : ProxyConfiguration; +[JsonDerivedType(typeof(Autodetect), "autodetect")] +[JsonDerivedType(typeof(Direct), "direct")] +[JsonDerivedType(typeof(Manual), "manual")] +[JsonDerivedType(typeof(Pac), "pac")] +[JsonDerivedType(typeof(System), "system")] +public abstract record ProxyConfiguration +{ + public record Autodetect : ProxyConfiguration; -public record DirectProxyConfiguration : ProxyConfiguration; + public record Direct : ProxyConfiguration; -public record ManualProxyConfiguration : ProxyConfiguration -{ - public string? FtpProxy { get; set; } + public record Manual : ProxyConfiguration + { + public string? FtpProxy { get; set; } - public string? HttpProxy { get; set; } + public string? HttpProxy { get; set; } - public string? SslProxy { get; set; } + public string? SslProxy { get; set; } - public string? SocksProxy { get; set; } + public string? SocksProxy { get; set; } - public long? SocksVersion { get; set; } -} + public long? SocksVersion { get; set; } + } -public record PacProxyConfiguration(string ProxyAutoconfigUrl) : ProxyConfiguration; + public record Pac(string ProxyAutoconfigUrl) : ProxyConfiguration; -public record SystemProxyConfiguration : ProxyConfiguration; + public record System : ProxyConfiguration; +} diff --git a/dotnet/src/webdriver/BiDi/Modules/Session/SessionModule.cs b/dotnet/src/webdriver/BiDi/Modules/Session/SessionModule.cs index 3a1ec251a2956..88503bf894cd8 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Session/SessionModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Session/SessionModule.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Session; internal sealed class SessionModule(Broker broker) : Module(broker) diff --git a/dotnet/src/webdriver/BiDi/Modules/Session/StatusCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Session/StatusCommand.cs index 2c25c17e60313..8ab6de213b138 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Session/StatusCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Session/StatusCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Session; internal class StatusCommand() : Command(CommandParameters.Empty); diff --git a/dotnet/src/webdriver/BiDi/Modules/Session/SubscribeCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Session/SubscribeCommand.cs index 1d33180d1e3b7..607e5c69944c6 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Session/SubscribeCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Session/SubscribeCommand.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Communication; using System.Collections.Generic; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Session; internal class SubscribeCommand(SubscribeCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Session/UnsubscribeCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Session/UnsubscribeCommand.cs index e96f6b4cf828d..6ca1f7517b439 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Session/UnsubscribeCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Session/UnsubscribeCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Session; internal class UnsubscribeCommand(SubscribeCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Storage/DeleteCookiesCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Storage/DeleteCookiesCommand.cs index bcc27fdf9f8b3..13dcf2f30d3ba 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Storage/DeleteCookiesCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Storage/DeleteCookiesCommand.cs @@ -1,5 +1,7 @@ using OpenQA.Selenium.BiDi.Communication; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Storage; internal class DeleteCookiesCommand(DeleteCookiesCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Storage/GetCookiesCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Storage/GetCookiesCommand.cs index c7c7c2c01dda3..06cd0c09f6925 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Storage/GetCookiesCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Storage/GetCookiesCommand.cs @@ -1,8 +1,11 @@ using OpenQA.Selenium.BiDi.Communication; using System; +using System.Collections; using System.Collections.Generic; using System.Text.Json.Serialization; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Storage; internal class GetCookiesCommand(GetCookiesCommandParameters @params) : Command(@params); @@ -21,7 +24,26 @@ public record GetCookiesOptions : CommandOptions public PartitionDescriptor? Partition { get; set; } } -public record GetCookiesResult(IReadOnlyList Cookies, PartitionKey PartitionKey); +public record GetCookiesResult : IReadOnlyList +{ + private readonly IReadOnlyList _cookies; + + internal GetCookiesResult(IReadOnlyList cookies, PartitionKey partitionKey) + { + _cookies = cookies; + PartitionKey = partitionKey; + } + + public PartitionKey PartitionKey { get; init; } + + public Network.Cookie this[int index] => _cookies[index]; + + public int Count => _cookies.Count; + + public IEnumerator GetEnumerator() => _cookies.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => (_cookies as IEnumerable).GetEnumerator(); +} public class CookieFilter { @@ -45,15 +67,16 @@ public class CookieFilter } [JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] -[JsonDerivedType(typeof(BrowsingContextPartitionDescriptor), "context")] -[JsonDerivedType(typeof(StorageKeyPartitionDescriptor), "storageKey")] -public abstract record PartitionDescriptor; - -public record BrowsingContextPartitionDescriptor(BrowsingContext.BrowsingContext Context) : PartitionDescriptor; - -public record StorageKeyPartitionDescriptor : PartitionDescriptor +[JsonDerivedType(typeof(Context), "context")] +[JsonDerivedType(typeof(StorageKey), "storageKey")] +public abstract record PartitionDescriptor { - public string? UserContext { get; set; } + public record Context([property: JsonPropertyName("context")] BrowsingContext.BrowsingContext Descriptor) : PartitionDescriptor; + + public record StorageKey : PartitionDescriptor + { + public string? UserContext { get; set; } - public string? SourceOrigin { get; set; } + public string? SourceOrigin { get; set; } + } } diff --git a/dotnet/src/webdriver/BiDi/Modules/Storage/PartitionKey.cs b/dotnet/src/webdriver/BiDi/Modules/Storage/PartitionKey.cs index 2d9ac37a41a22..30200db4b5f60 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Storage/PartitionKey.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Storage/PartitionKey.cs @@ -1,8 +1,10 @@ +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Storage; public class PartitionKey { - public string? UserContext { get; set; } + public Browser.UserContext? UserContext { get; set; } public string? SourceOrigin { get; set; } } diff --git a/dotnet/src/webdriver/BiDi/Modules/Storage/SetCookieCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Storage/SetCookieCommand.cs index f0dcf22904eba..7e7cb79824cbc 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Storage/SetCookieCommand.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Storage/SetCookieCommand.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Communication; using System; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Storage; internal class SetCookieCommand(SetCookieCommandParameters @params) : Command(@params); diff --git a/dotnet/src/webdriver/BiDi/Modules/Storage/StorageModule.cs b/dotnet/src/webdriver/BiDi/Modules/Storage/StorageModule.cs index 249d7d37634d1..71969d9914c2a 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Storage/StorageModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Storage/StorageModule.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Communication; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.BiDi.Modules.Storage; public class StorageModule(Broker broker) : Module(broker) diff --git a/dotnet/src/webdriver/BiDi/Subscription.cs b/dotnet/src/webdriver/BiDi/Subscription.cs index 21995fee00dcf..8870b07fb18bf 100644 --- a/dotnet/src/webdriver/BiDi/Subscription.cs +++ b/dotnet/src/webdriver/BiDi/Subscription.cs @@ -3,22 +3,24 @@ using System.Collections.Generic; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.BiDi; public class Subscription : IAsyncDisposable { - private readonly Broker Broker; + private readonly Broker _broker; private readonly Communication.EventHandler _eventHandler; internal Subscription(Broker broker, Communication.EventHandler eventHandler) { - Broker = broker; + _broker = broker; _eventHandler = eventHandler; } public async Task UnsubscribeAsync() { - await Broker.UnsubscribeAsync(_eventHandler).ConfigureAwait(false); + await _broker.UnsubscribeAsync(_eventHandler).ConfigureAwait(false); } public async ValueTask DisposeAsync() diff --git a/dotnet/src/webdriver/BiDi/WebDriver.Extensions.cs b/dotnet/src/webdriver/BiDi/WebDriver.Extensions.cs index c039dd4087740..a3e7df31cec50 100644 --- a/dotnet/src/webdriver/BiDi/WebDriver.Extensions.cs +++ b/dotnet/src/webdriver/BiDi/WebDriver.Extensions.cs @@ -1,6 +1,8 @@ using OpenQA.Selenium.BiDi.Modules.BrowsingContext; using System.Threading.Tasks; +#nullable enable + namespace OpenQA.Selenium.BiDi; public static class WebDriverExtensions diff --git a/dotnet/test/common/BiDi/BiDiFixture.cs b/dotnet/test/common/BiDi/BiDiFixture.cs new file mode 100644 index 0000000000000..b7bf01de81b52 --- /dev/null +++ b/dotnet/test/common/BiDi/BiDiFixture.cs @@ -0,0 +1,54 @@ +using NUnit.Framework; +using OpenQA.Selenium.Environment; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi; + +[Parallelizable(ParallelScope.All)] +[FixtureLifeCycle(LifeCycle.InstancePerTestCase)] +public class BiDiTestFixture +{ + protected IWebDriver driver; + protected BiDi bidi; + protected Modules.BrowsingContext.BrowsingContext context; + + protected UrlBuilder UrlBuilder { get; } = EnvironmentManager.Instance.UrlBuilder; + + [SetUp] + public async Task BiDiSetUp() + { + var options = new BiDiEnabledDriverOptions() + { + UseWebSocketUrl = true, + UnhandledPromptBehavior = UnhandledPromptBehavior.Ignore, + }; + + driver = EnvironmentManager.Instance.CreateDriverInstance(options); + + context = await driver.AsBiDiContextAsync(); + bidi = context.BiDi; + } + + [TearDown] + public async Task BiDiTearDown() + { + if (bidi is not null) + { + await bidi.DisposeAsync(); + } + + driver?.Dispose(); + } + + public class BiDiEnabledDriverOptions : DriverOptions + { + public override void AddAdditionalOption(string capabilityName, object capabilityValue) + { + } + + public override ICapabilities ToCapabilities() + { + return null; + } + } +} diff --git a/dotnet/test/common/BiDi/Browser/BrowserTest.cs b/dotnet/test/common/BiDi/Browser/BrowserTest.cs new file mode 100644 index 0000000000000..74bbd956848a1 --- /dev/null +++ b/dotnet/test/common/BiDi/Browser/BrowserTest.cs @@ -0,0 +1,43 @@ +using NUnit.Framework; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.Browser; + +class BrowserTest : BiDiTestFixture +{ + [Test] + public async Task CanCreateUserContext() + { + var userContext = await bidi.Browser.CreateUserContextAsync(); + + Assert.That(userContext, Is.Not.Null); + } + + [Test] + public async Task CanGetUserContexts() + { + var userContext1 = await bidi.Browser.CreateUserContextAsync(); + var userContext2 = await bidi.Browser.CreateUserContextAsync(); + + var userContexts = await bidi.Browser.GetUserContextsAsync(); + + Assert.That(userContexts, Is.Not.Null); + Assert.That(userContexts.Count, Is.GreaterThanOrEqualTo(2)); + Assert.That(userContexts, Does.Contain(userContext1)); + Assert.That(userContexts, Does.Contain(userContext2)); + } + + [Test] + public async Task CanRemoveUserContext() + { + var userContext1 = await bidi.Browser.CreateUserContextAsync(); + var userContext2 = await bidi.Browser.CreateUserContextAsync(); + + await userContext2.UserContext.RemoveAsync(); + + var userContexts = await bidi.Browser.GetUserContextsAsync(); + + Assert.That(userContexts, Does.Contain(userContext1)); + Assert.That(userContexts, Does.Not.Contain(userContext2)); + } +} diff --git a/dotnet/test/common/BiDi/BrowsingContext/BrowsingContextTest.cs b/dotnet/test/common/BiDi/BrowsingContext/BrowsingContextTest.cs new file mode 100644 index 0000000000000..510daceddfb11 --- /dev/null +++ b/dotnet/test/common/BiDi/BrowsingContext/BrowsingContextTest.cs @@ -0,0 +1,301 @@ +using NUnit.Framework; +using OpenQA.Selenium.BiDi.Modules.BrowsingContext; +using System.Linq; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.BrowsingContext; + +class BrowsingContextTest : BiDiTestFixture +{ + [Test] + public async Task CanCreateNewTab() + { + var tab = await bidi.BrowsingContext.CreateAsync(ContextType.Tab); + + Assert.That(tab, Is.Not.Null); + } + + [Test] + public async Task CanCreateNewTabWithReferencedContext() + { + var tab = await bidi.BrowsingContext.CreateAsync(ContextType.Tab, new() + { + ReferenceContext = context + }); + + Assert.That(tab, Is.Not.Null); + } + + [Test] + public async Task CanCreateNewWindow() + { + var window = await bidi.BrowsingContext.CreateAsync(ContextType.Window); + + Assert.That(window, Is.Not.Null); + } + + [Test] + public async Task CanCreateNewWindowWithReferencedContext() + { + var window = await bidi.BrowsingContext.CreateAsync(ContextType.Window, new() + { + ReferenceContext = context + }); + + Assert.That(window, Is.Not.Null); + } + + [Test] + public async Task CanCreateContextWithAllParameters() + { + var userContext = await bidi.Browser.CreateUserContextAsync(); + + var window = await bidi.BrowsingContext.CreateAsync(ContextType.Window, new() + { + ReferenceContext = context, + UserContext = userContext.UserContext, + Background = true + }); + + Assert.That(window, Is.Not.Null); + } + + [Test] + public async Task CanNavigateToUrl() + { + var info = await context.NavigateAsync(UrlBuilder.WhereIs("/bidi/logEntryAdded.html")); + + Assert.That(info.Url, Does.Contain("/bidi/logEntryAdded.html")); + } + + [Test] + public async Task CanNavigateToUrlWithReadinessState() + { + var info = await context.NavigateAsync(UrlBuilder.WhereIs("/bidi/logEntryAdded.html"), new() + { + Wait = ReadinessState.Complete + }); + + Assert.That(info, Is.Not.Null); + Assert.That(info.Url, Does.Contain("/bidi/logEntryAdded.html")); + } + + [Test] + public async Task CanGetTreeWithChild() + { + await context.NavigateAsync(UrlBuilder.WhereIs("iframes.html"), new() { Wait = ReadinessState.Complete }); + + var tree = await context.GetTreeAsync(); + + Assert.That(tree, Has.Count.EqualTo(1)); + Assert.That(tree[0].Context, Is.EqualTo(context)); + Assert.That(tree[0].Children, Has.Count.EqualTo(1)); + Assert.That(tree[0].Children[0].Url, Does.Contain("formPage.html")); + } + + [Test] + public async Task CanGetTreeWithDepth() + { + await context.NavigateAsync(UrlBuilder.WhereIs("iframes.html"), new() { Wait = ReadinessState.Complete }); + + var tree = await context.GetTreeAsync(new() { MaxDepth = 0 }); + + Assert.That(tree, Has.Count.EqualTo(1)); + Assert.That(tree[0].Context, Is.EqualTo(context)); + Assert.That(tree[0].Children, Is.Null); + } + + [Test] + public async Task CanGetTreeTopLevel() + { + var window1 = await bidi.BrowsingContext.CreateAsync(ContextType.Window); + var window2 = await bidi.BrowsingContext.CreateAsync(ContextType.Window); + + var tree = await bidi.BrowsingContext.GetTreeAsync(); + + Assert.That(tree, Has.Count.GreaterThanOrEqualTo(2)); + } + + [Test] + public async Task CanCloseWindow() + { + var window = await bidi.BrowsingContext.CreateAsync(ContextType.Window); + + await window.CloseAsync(); + + var tree = await bidi.BrowsingContext.GetTreeAsync(); + + Assert.That(tree.Select(i => i.Context), Does.Not.Contain(window)); + } + + [Test] + public async Task CanCloseTab() + { + var tab = await bidi.BrowsingContext.CreateAsync(ContextType.Tab); + + await tab.CloseAsync(); + + var tree = await bidi.BrowsingContext.GetTreeAsync(); + + Assert.That(tree.Select(i => i.Context), Does.Not.Contain(tab)); + } + + [Test] + public async Task CanActivate() + { + await context.ActivateAsync(); + + // TODO: Add assertion when https://w3c.github.io/webdriver-bidi/#type-browser-ClientWindowInfo is implemented + } + + [Test] + public async Task CanReload() + { + string url = UrlBuilder.WhereIs("/bidi/logEntryAdded.html"); + + await context.NavigateAsync(url, new() { Wait = ReadinessState.Complete }); + + var info = await context.ReloadAsync(); + + Assert.That(info, Is.Not.Null); + Assert.That(info.Url, Does.Contain("/bidi/logEntryAdded.html")); + } + + [Test] + public async Task CanReloadWithReadinessState() + { + string url = UrlBuilder.WhereIs("/bidi/logEntryAdded.html"); + + await context.NavigateAsync(url, new() { Wait = ReadinessState.Complete }); + + var info = await context.ReloadAsync(new() + { + Wait = ReadinessState.Complete + }); + + Assert.That(info, Is.Not.Null); + Assert.That(info.Url, Does.Contain("/bidi/logEntryAdded.html")); + } + + [Test] + public async Task CanHandleUserPrompt() + { + await context.NavigateAsync(UrlBuilder.WhereIs("alerts.html"), new() { Wait = ReadinessState.Complete }); + + driver.FindElement(By.Id("alert")).Click(); + + await context.HandleUserPromptAsync(); + } + + [Test] + public async Task CanAcceptUserPrompt() + { + await context.NavigateAsync(UrlBuilder.WhereIs("alerts.html"), new() { Wait = ReadinessState.Complete }); + + driver.FindElement(By.Id("alert")).Click(); + + await context.HandleUserPromptAsync(new() + { + Accept = true + }); + } + + [Test] + public async Task CanDismissUserPrompt() + { + await context.NavigateAsync(UrlBuilder.WhereIs("alerts.html"), new() { Wait = ReadinessState.Complete }); + + driver.FindElement(By.Id("alert")).Click(); + + await context.HandleUserPromptAsync(new() + { + Accept = false + }); + } + + [Test] + public async Task CanPassUserTextToPrompt() + { + await context.NavigateAsync(UrlBuilder.WhereIs("alerts.html"), new() { Wait = ReadinessState.Complete }); + + driver.FindElement(By.Id("alert")).Click(); + + await context.HandleUserPromptAsync(new() + { + UserText = "Selenium automates browsers" + }); + } + + [Test] + public async Task CanCaptureScreenshot() + { + var screenshot = await context.CaptureScreenshotAsync(); + + Assert.That(screenshot, Is.Not.Null); + Assert.That(screenshot.Data, Is.Not.Empty); + } + + [Test] + public async Task CanCaptureScreenshotWithParameters() + { + var screenshot = await context.CaptureScreenshotAsync(new() + { + Origin = Origin.Document, + Clip = new ClipRectangle.Box(5, 5, 10, 10) + }); + + Assert.That(screenshot, Is.Not.Null); + Assert.That(screenshot.Data, Is.Not.Empty); + } + + [Test] + public async Task CanCaptureScreenshotOfViewport() + { + var screenshot = await context.CaptureScreenshotAsync(new() + { + Origin = Origin.Viewport, + Clip = new ClipRectangle.Box(5, 5, 10, 10) + }); + + Assert.That(screenshot, Is.Not.Null); + Assert.That(screenshot.Data, Is.Not.Empty); + } + + [Test] + public async Task CanCaptureScreenshotOfElement() + { + await context.NavigateAsync(UrlBuilder.WhereIs("formPage.html"), new() { Wait = ReadinessState.Complete }); + + var nodes = await context.LocateNodesAsync(new Locator.Css("#checky")); + + var screenshot = await context.CaptureScreenshotAsync(new() + { + // TODO: Seems Node implements ISharedReference + Clip = new ClipRectangle.Element(new Modules.Script.SharedReference(nodes[0].SharedId)) + }); + + Assert.That(screenshot, Is.Not.Null); + Assert.That(screenshot.Data, Is.Not.Empty); + } + + [Test] + public async Task CanSetViewport() + { + await context.SetViewportAsync(new() { Viewport = new(250, 300) }); + } + + [Test] + public async Task CanSetViewportWithDevicePixelRatio() + { + await context.SetViewportAsync(new() { Viewport = new(250, 300), DevicePixelRatio = 5 }); + } + + [Test] + public async Task CanPrintPage() + { + var pdf = await context.PrintAsync(); + + Assert.That(pdf, Is.Not.Null); + Assert.That(pdf.Data, Is.Not.Empty); + } +} diff --git a/dotnet/test/common/BiDi/Input/CombinedInputActionsTest.cs b/dotnet/test/common/BiDi/Input/CombinedInputActionsTest.cs new file mode 100644 index 0000000000000..cb832cdeb9e41 --- /dev/null +++ b/dotnet/test/common/BiDi/Input/CombinedInputActionsTest.cs @@ -0,0 +1,55 @@ +using NUnit.Framework; +using OpenQA.Selenium.BiDi.Modules.BrowsingContext; +using OpenQA.Selenium.BiDi.Modules.Input; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.Input; + +class CombinedInputActionsTest : BiDiTestFixture +{ + //[Test] + public async Task Paint() + { + driver.Url = "https://kleki.com/"; + + await Task.Delay(3000); + + await context.Input.PerformActionsAsync([new PointerActions { + new Pointer.Move(300, 300), + new Pointer.Down(0), + new Pointer.Move(400, 400) { Duration = 2000, Width = 1, Twist = 1 }, + new Pointer.Up(0), + }]); + + await context.Input.PerformActionsAsync([new KeyActions { + new Key.Down('U'), + new Key.Up('U'), + new Pause { Duration = 3000 } + }]); + + await context.Input.PerformActionsAsync([new PointerActions { + new Pointer.Move(300, 300), + new Pointer.Down(0), + new Pointer.Move(400, 400) { Duration = 2000 }, + new Pointer.Up(0), + }]); + + await Task.Delay(3000); + } + + [Test] + public async Task TestShiftClickingOnMultiSelectionList() + { + driver.Url = UrlBuilder.WhereIs("formSelectionPage.html"); + + var options = await context.LocateNodesAsync(new Locator.Css("option")); + + await context.Input.PerformActionsAsync([ + new PointerActions + { + new Pointer.Down(1), + new Pointer.Up(1), + } + ]); + } +} diff --git a/dotnet/test/common/BiDi/Input/DefaultKeyboardTest.cs b/dotnet/test/common/BiDi/Input/DefaultKeyboardTest.cs new file mode 100644 index 0000000000000..f226719e17c0a --- /dev/null +++ b/dotnet/test/common/BiDi/Input/DefaultKeyboardTest.cs @@ -0,0 +1,88 @@ +//using NUnit.Framework; +//using OpenQA.Selenium.BiDi.Modules.BrowsingContext; +//using OpenQA.Selenium.BiDi.Modules.Input; +//using System.Threading.Tasks; + +//namespace OpenQA.Selenium.BiDi.Input; + +//class DefaultKeyboardTest : BiDiTestFixture +//{ +// [Test] +// public async Task TestBasicKeyboardInput() +// { +// driver.Url = UrlBuilder.WhereIs("single_text_input.html"); + +// var input = (await context.LocateNodesAsync(new Locator.Css("#textInput")))[0]; + +// await context.Input.PerformActionsAsync(new SequentialSourceActions() +// .PointerMove(0, 0, new() { Origin = new Modules.Input.Origin.Element(new Modules.Script.SharedReference(input.SharedId)) }) +// .PointerDown(0) +// .PointerUp(0) +// .Type("abc def")); + +// Assert.That(driver.FindElement(By.Id("textInput")).GetAttribute("value"), Is.EqualTo("abc def")); +// } + +// [Test] +// public async Task TestSendingKeyDownOnly() +// { +// driver.Url = UrlBuilder.WhereIs("key_logger.html"); + +// var input = (await context.LocateNodesAsync(new Locator.Css("#theworks")))[0]; + +// await context.Input.PerformActionsAsync(new SequentialSourceActions() +// .PointerMove(0, 0, new() { Origin = new Modules.Input.Origin.Element(new Modules.Script.SharedReference(input.SharedId)) }) +// .PointerDown(0) +// .PointerUp(0) +// .KeyDown(Key.Shift)); + +// Assert.That(driver.FindElement(By.Id("result")).Text, Does.EndWith("keydown")); +// } + +// [Test] +// public async Task TestSendingKeyUp() +// { +// driver.Url = UrlBuilder.WhereIs("key_logger.html"); + +// var input = (await context.LocateNodesAsync(new Locator.Css("#theworks")))[0]; + +// await context.Input.PerformActionsAsync(new SequentialSourceActions() +// .PointerMove(0, 0, new() { Origin = new Modules.Input.Origin.Element(new Modules.Script.SharedReference(input.SharedId)) }) +// .PointerDown(0) +// .PointerUp(0) +// .KeyDown(Key.Shift) +// .KeyUp(Key.Shift)); + +// Assert.That(driver.FindElement(By.Id("result")).Text, Does.EndWith("keyup")); +// } + +// [Test] +// public async Task TestSendingKeysWithShiftPressed() +// { +// driver.Url = UrlBuilder.WhereIs("key_logger.html"); + +// var input = (await context.LocateNodesAsync(new Locator.Css("#theworks")))[0]; + +// await context.Input.PerformActionsAsync(new SequentialSourceActions() +// .PointerMove(0, 0, new() { Origin = new Modules.Input.Origin.Element(new Modules.Script.SharedReference(input.SharedId)) }) +// .PointerDown(0) +// .PointerUp(0) +// .KeyDown(Key.Shift) +// .Type("ab") +// .KeyUp(Key.Shift)); + +// Assert.That(driver.FindElement(By.Id("result")).Text, Does.EndWith("keydown keydown keypress keyup keydown keypress keyup keyup")); +// Assert.That(driver.FindElement(By.Id("theworks")).GetAttribute("value"), Is.EqualTo("AB")); +// } + +// [Test] +// public async Task TestSendingKeysToActiveElement() +// { +// driver.Url = UrlBuilder.WhereIs("bodyTypingTest.html"); + +// await context.Input.PerformActionsAsync(new SequentialSourceActions().Type("ab")); + +// Assert.That(driver.FindElement(By.Id("body_result")).Text, Does.EndWith("keypress keypress")); +// Assert.That(driver.FindElement(By.Id("result")).Text, Is.EqualTo(" ")); +// } +//} diff --git a/dotnet/test/common/BiDi/Input/DefaultMouseTest.cs b/dotnet/test/common/BiDi/Input/DefaultMouseTest.cs new file mode 100644 index 0000000000000..c7408a83101f1 --- /dev/null +++ b/dotnet/test/common/BiDi/Input/DefaultMouseTest.cs @@ -0,0 +1,49 @@ +//using NUnit.Framework; +//using OpenQA.Selenium.BiDi.Modules.BrowsingContext; +//using OpenQA.Selenium.BiDi.Modules.Input; +//using System.Threading.Tasks; + +//namespace OpenQA.Selenium.BiDi.Input; + +//class DefaultMouseTest : BiDiTestFixture +//{ +// [Test] +// public async Task PerformDragAndDropWithMouse() +// { +// driver.Url = UrlBuilder.WhereIs("draggableLists.html"); + +// await context.Input.PerformActionsAsync([ +// new KeyActions +// { +// Actions = +// { +// new Key.Down('A'), +// new Key.Up('B') +// } +// } +// ]); + +// await context.Input.PerformActionsAsync([new KeyActions +// { +// new Key.Down('A'), +// new Key.Down('B'), +// new Pause() +// }]); + +// await context.Input.PerformActionsAsync([new PointerActions +// { +// new Pointer.Down(0), +// new Pointer.Up(0), +// }]); +// } + +// //[Test] +// public async Task PerformCombined() +// { +// await context.NavigateAsync("https://nuget.org", new() { Wait = ReadinessState.Complete }); + +// await context.Input.PerformActionsAsync(new SequentialSourceActions().Type("Hello").Pause(2000).KeyDown(Key.Shift).Type("World")); + +// await Task.Delay(3000); +// } +//} diff --git a/dotnet/test/common/BiDi/Log/LogTest.cs b/dotnet/test/common/BiDi/Log/LogTest.cs new file mode 100644 index 0000000000000..f67621bfc3b43 --- /dev/null +++ b/dotnet/test/common/BiDi/Log/LogTest.cs @@ -0,0 +1,75 @@ +using NUnit.Framework; +using OpenQA.Selenium.BiDi.Modules.Log; +using System; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.Log; + +class LogTest : BiDiTestFixture +{ + [Test] + public async Task CanListenToConsoleLog() + { + TaskCompletionSource tcs = new(); + + await using var subscription = await context.Log.OnEntryAddedAsync(tcs.SetResult); + + driver.Url = UrlBuilder.WhereIs("bidi/logEntryAdded.html"); + driver.FindElement(By.Id("consoleLog")).Click(); + + var logEntry = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.That(logEntry, Is.Not.Null); + Assert.That(logEntry.Source, Is.Not.Null); + Assert.That(logEntry.Source.Context, Is.EqualTo(context)); + Assert.That(logEntry.Source.Realm, Is.Not.Null); + Assert.That(logEntry.Text, Is.EqualTo("Hello, world!")); + Assert.That(logEntry.Level, Is.EqualTo(Level.Info)); + Assert.That(logEntry, Is.AssignableFrom()); + + var consoleLogEntry = logEntry as Entry.Console; + + Assert.That(consoleLogEntry.Method, Is.EqualTo("log")); + + Assert.That(consoleLogEntry.Args, Is.Not.Null); + Assert.That(consoleLogEntry.Args, Has.Count.EqualTo(1)); + Assert.That(consoleLogEntry.Args[0], Is.AssignableFrom()); + } + + [Test] + public async Task CanListenToJavascriptLog() + { + TaskCompletionSource tcs = new(); + + await using var subscription = await context.Log.OnEntryAddedAsync(tcs.SetResult); + + driver.Url = UrlBuilder.WhereIs("bidi/logEntryAdded.html"); + driver.FindElement(By.Id("jsException")).Click(); + + var logEntry = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.That(logEntry, Is.Not.Null); + Assert.That(logEntry.Source, Is.Not.Null); + Assert.That(logEntry.Source.Context, Is.EqualTo(context)); + Assert.That(logEntry.Source.Realm, Is.Not.Null); + Assert.That(logEntry.Text, Is.EqualTo("Error: Not working")); + Assert.That(logEntry.Level, Is.EqualTo(Level.Error)); + Assert.That(logEntry, Is.AssignableFrom()); + } + + [Test] + public async Task CanRetrieveStacktrace() + { + TaskCompletionSource tcs = new(); + + await using var subscription = await bidi.Log.OnEntryAddedAsync(tcs.SetResult); + + driver.Url = UrlBuilder.WhereIs("bidi/logEntryAdded.html"); + driver.FindElement(By.Id("logWithStacktrace")).Click(); + + var logEntry = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.That(logEntry, Is.Not.Null); + Assert.That(logEntry.StackTrace, Is.Not.Null); + } +} diff --git a/dotnet/test/common/BiDi/Network/NetworkEventsTest.cs b/dotnet/test/common/BiDi/Network/NetworkEventsTest.cs new file mode 100644 index 0000000000000..230351ba436df --- /dev/null +++ b/dotnet/test/common/BiDi/Network/NetworkEventsTest.cs @@ -0,0 +1,132 @@ +using NUnit.Framework; +using OpenQA.Selenium.BiDi.Modules.BrowsingContext; +using OpenQA.Selenium.BiDi.Modules.Network; +using System; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.Network; + +class NetworkEventsTest : BiDiTestFixture +{ + [Test] + public async Task CanListenToBeforeRequestSentEvent() + { + TaskCompletionSource tcs = new(); + + await using var subscription = await context.Network.OnBeforeRequestSentAsync(tcs.SetResult); + + await context.NavigateAsync(UrlBuilder.WhereIs("bidi/logEntryAdded.html"), new() { Wait = ReadinessState.Complete }); + + var req = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.That(req.Context, Is.EqualTo(context)); + Assert.That(req.Request, Is.Not.Null); + Assert.That(req.Request.Method, Is.EqualTo("GET")); + Assert.That(req.Request.Url, Does.Contain("bidi/logEntryAdded.html")); + Assert.That(req.Initiator.Type, Is.EqualTo(InitiatorType.Other)); + } + + [Test] + public async Task CanListenToResponseStartedEvent() + { + TaskCompletionSource tcs = new(); + + await using var subscription = await context.Network.OnResponseStartedAsync(tcs.SetResult); + + await context.NavigateAsync(UrlBuilder.WhereIs("bidi/logEntryAdded.html"), new() { Wait = ReadinessState.Complete }); + + var res = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.That(res.Context, Is.EqualTo(context)); + Assert.That(res.Request, Is.Not.Null); + Assert.That(res.Request.Method, Is.EqualTo("GET")); + Assert.That(res.Request.Url, Does.Contain("bidi/logEntryAdded.html")); + Assert.That(res.Response.Headers, Is.Not.Empty); + Assert.That(res.Response.Status, Is.EqualTo(200)); + } + + [Test] + public async Task CanListenToResponseCompletedEvent() + { + TaskCompletionSource tcs = new(); + + await using var subscription = await context.Network.OnResponseCompletedAsync(tcs.SetResult); + + await context.NavigateAsync(UrlBuilder.WhereIs("bidi/logEntryAdded.html"), new() { Wait = ReadinessState.Complete }); + + var res = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.That(res.Context, Is.EqualTo(context)); + Assert.That(res.Request, Is.Not.Null); + Assert.That(res.Request.Method, Is.EqualTo("GET")); + Assert.That(res.Request.Url, Does.Contain("bidi/logEntryAdded.html")); + Assert.That(res.Response.Url, Does.Contain("bidi/logEntryAdded.html")); + Assert.That(res.Response.Headers, Is.Not.Empty); + Assert.That(res.Response.Status, Is.EqualTo(200)); + } + + [Test] + public async Task CanListenToBeforeRequestSentEventWithCookie() + { + TaskCompletionSource tcs = new(); + + await context.NavigateAsync(UrlBuilder.WhereIs("bidi/logEntryAdded.html"), new() { Wait = ReadinessState.Complete }); + + driver.Manage().Cookies.AddCookie(new("foo", "bar")); + + await using var subscription = await bidi.Network.OnBeforeRequestSentAsync(tcs.SetResult); + + await context.ReloadAsync(); + + var req = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.That(req.Request.Cookies.Count, Is.EqualTo(1)); + Assert.That(req.Request.Cookies[0].Name, Is.EqualTo("foo")); + Assert.That((req.Request.Cookies[0].Value as BytesValue.String).Value, Is.EqualTo("bar")); + } + + [Test] + [IgnoreBrowser(Selenium.Browser.Chrome)] + [IgnoreBrowser(Selenium.Browser.Edge)] + public async Task CanListenToOnAuthRequiredEvent() + { + TaskCompletionSource tcs = new(); + + await using var subscription = await context.Network.OnAuthRequiredAsync(tcs.SetResult); + + driver.Url = UrlBuilder.WhereIs("basicAuth"); + + var res = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.That(res.Context, Is.EqualTo(context)); + Assert.That(res.Request, Is.Not.Null); + Assert.That(res.Request.Method, Is.EqualTo("GET")); + Assert.That(res.Request.Url, Does.Contain("basicAuth")); + Assert.That(res.Response.Headers, Is.Not.Null.And.Count.GreaterThanOrEqualTo(1)); + Assert.That(res.Response.Status, Is.EqualTo(401)); + } + + [Test] + public async Task CanListenToFetchError() + { + TaskCompletionSource tcs = new(); + + await using var subscription = await context.Network.OnFetchErrorAsync(tcs.SetResult); + + try + { + await context.NavigateAsync("https://not_a_valid_url.test", new() { Wait = ReadinessState.Complete }); + } + catch (Exception) { } + + var res = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.That(res.Context, Is.EqualTo(context)); + Assert.That(res.Request, Is.Not.Null); + Assert.That(res.Request.Method, Is.EqualTo("GET")); + Assert.That(res.Request.Url, Does.Contain("https://not_a_valid_url.test")); + Assert.That(res.Request.Headers.Count, Is.GreaterThanOrEqualTo(1)); + Assert.That(res.Navigation, Is.Not.Null); + Assert.That(res.ErrorText, Does.Contain("net::ERR_NAME_NOT_RESOLVED").Or.Contain("NS_ERROR_UNKNOWN_HOST")); + } +} diff --git a/dotnet/test/common/BiDi/Network/NetworkTest.cs b/dotnet/test/common/BiDi/Network/NetworkTest.cs new file mode 100644 index 0000000000000..b743378c385ea --- /dev/null +++ b/dotnet/test/common/BiDi/Network/NetworkTest.cs @@ -0,0 +1,195 @@ +using NUnit.Framework; +using OpenQA.Selenium.BiDi.Modules.BrowsingContext; +using OpenQA.Selenium.BiDi.Modules.Network; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.Network; + +class NetworkTest : BiDiTestFixture +{ + [Test] + public async Task CanAddIntercept() + { + await using var intercept = await bidi.Network.InterceptRequestAsync(e => Task.CompletedTask); + + Assert.That(intercept, Is.Not.Null); + } + + [Test] + public async Task CanAddInterceptStringUrlPattern() + { + await using var intercept = await bidi.Network.InterceptRequestAsync(e => Task.CompletedTask, new() + { + UrlPatterns = [ + new UrlPattern.String("http://localhost:4444"), + "http://localhost:4444/" + ] + }); + + Assert.That(intercept, Is.Not.Null); + } + + [Test] + public async Task CanAddInterceptUrlPattern() + { + await using var intercept = await bidi.Network.InterceptRequestAsync(e => Task.CompletedTask, interceptOptions: new() + { + UrlPatterns = [new UrlPattern.Pattern() + { + Hostname = "localhost", + Protocol = "http" + }] + }); + + Assert.That(intercept, Is.Not.Null); + } + + [Test] + public async Task CanContinueRequest() + { + int times = 0; + await using var intercept = await bidi.Network.InterceptRequestAsync(async e => + { + times++; + + await e.Request.Request.ContinueAsync(); + }); + + await context.NavigateAsync(UrlBuilder.WhereIs("bidi/logEntryAdded.html"), new() { Wait = ReadinessState.Complete }); + + Assert.That(intercept, Is.Not.Null); + Assert.That(times, Is.GreaterThan(0)); + } + + [Test] + public async Task CanContinueResponse() + { + int times = 0; + + await using var intercept = await bidi.Network.InterceptResponseAsync(async e => + { + times++; + + await e.Request.Request.ContinueResponseAsync(); + }); + + await context.NavigateAsync(UrlBuilder.WhereIs("bidi/logEntryAdded.html"), new() { Wait = ReadinessState.Complete }); + + Assert.That(intercept, Is.Not.Null); + Assert.That(times, Is.GreaterThan(0)); + } + + [Test] + public async Task CanProvideResponse() + { + int times = 0; + + await using var intercept = await bidi.Network.InterceptRequestAsync(async e => + { + times++; + + await e.Request.Request.ProvideResponseAsync(); + }); + + await context.NavigateAsync(UrlBuilder.WhereIs("bidi/logEntryAdded.html"), new() { Wait = ReadinessState.Complete }); + + Assert.That(intercept, Is.Not.Null); + Assert.That(times, Is.GreaterThan(0)); + } + + [Test] + public async Task CanProvideResponseWithParameters() + { + int times = 0; + + await using var intercept = await bidi.Network.InterceptRequestAsync(async e => + { + times++; + + await e.Request.Request.ProvideResponseAsync(new() { Body = """ + + + Hello + + + + + """ }); + }); + + await context.NavigateAsync(UrlBuilder.WhereIs("bidi/logEntryAdded.html"), new() { Wait = ReadinessState.Complete }); + + Assert.That(intercept, Is.Not.Null); + Assert.That(times, Is.GreaterThan(0)); + Assert.That(driver.Title, Is.EqualTo("Hello")); + } + + [Test] + public async Task CanRemoveIntercept() + { + var intercept = await bidi.Network.InterceptRequestAsync(_ => Task.CompletedTask); + + await intercept.RemoveAsync(); + + // or + + intercept = await context.Network.InterceptRequestAsync(_ => Task.CompletedTask); + + await intercept.DisposeAsync(); + } + + [Test] + public async Task CanContinueWithAuthCredentials() + { + await using var intercept = await bidi.Network.InterceptAuthAsync(async e => + { + //TODO Seems it would be better to have method which takes abstract options + await e.Request.Request.ContinueWithAuthAsync(new AuthCredentials.Basic("test", "test")); + }); + + await context.NavigateAsync(UrlBuilder.WhereIs("basicAuth"), new() { Wait = ReadinessState.Complete }); + + Assert.That(driver.FindElement(By.CssSelector("h1")).Text, Is.EqualTo("authorized")); + } + + [Test] + [IgnoreBrowser(Selenium.Browser.Firefox)] + public async Task CanContinueWithDefaultCredentials() + { + await using var intercept = await bidi.Network.InterceptAuthAsync(async e => + { + await e.Request.Request.ContinueWithAuthAsync(new ContinueWithDefaultAuthOptions()); + }); + + var action = async () => await context.NavigateAsync(UrlBuilder.WhereIs("basicAuth"), new() { Wait = ReadinessState.Complete }); + + Assert.That(action, Throws.TypeOf().With.Message.Contain("net::ERR_INVALID_AUTH_CREDENTIALS")); + } + + [Test] + [IgnoreBrowser(Selenium.Browser.Firefox)] + public async Task CanContinueWithCanceledCredentials() + { + await using var intercept = await bidi.Network.InterceptAuthAsync(async e => + { + await e.Request.Request.ContinueWithAuthAsync(new ContinueWithCancelledAuthOptions()); + }); + + var action = async () => await context.NavigateAsync(UrlBuilder.WhereIs("basicAuth"), new() { Wait = ReadinessState.Complete }); + + Assert.That(action, Throws.TypeOf().With.Message.Contain("net::ERR_HTTP_RESPONSE_CODE_FAILURE")); + } + + [Test] + public async Task CanFailRequest() + { + await using var intercept = await bidi.Network.InterceptRequestAsync(async e => + { + await e.Request.Request.FailAsync(); + }); + + var action = async () => await context.NavigateAsync(UrlBuilder.WhereIs("basicAuth"), new() { Wait = ReadinessState.Complete }); + + Assert.That(action, Throws.TypeOf().With.Message.Contain("net::ERR_FAILED").Or.Message.Contain("NS_ERROR_ABORT")); + } +} diff --git a/dotnet/test/common/BiDi/Script/CallFunctionParameterTest.cs b/dotnet/test/common/BiDi/Script/CallFunctionParameterTest.cs new file mode 100644 index 0000000000000..3fc11764fca2e --- /dev/null +++ b/dotnet/test/common/BiDi/Script/CallFunctionParameterTest.cs @@ -0,0 +1,203 @@ +using NUnit.Framework; +using OpenQA.Selenium.BiDi.Modules.Script; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.Script; + +class CallFunctionParameterTest : BiDiTestFixture +{ + [Test] + public async Task CanCallFunctionWithDeclaration() + { + var res = await context.Script.CallFunctionAsync("() => { return 1 + 2; }", false); + + Assert.That(res, Is.Not.Null); + Assert.That(res.Realm, Is.Not.Null); + Assert.That((res.Result as RemoteValue.Number).Value, Is.EqualTo(3)); + } + + [Test] + public async Task CanCallFunctionWithDeclarationImplicitCast() + { + var res = await context.Script.CallFunctionAsync("() => { return 1 + 2; }", false); + + Assert.That(res, Is.EqualTo(3)); + } + + [Test] + public async Task CanEvaluateScriptWithUserActivationTrue() + { + await context.Script.EvaluateAsync("window.open();", true, new() { UserActivation = true }); + + var res = await context.Script.CallFunctionAsync(""" + () => navigator.userActivation.isActive && navigator.userActivation.hasBeenActive + """, true, new() { UserActivation = true }); + + Assert.That(res, Is.True); + } + + [Test] + public async Task CanEvaluateScriptWithUserActivationFalse() + { + await context.Script.EvaluateAsync("window.open();", true); + + var res = await context.Script.CallFunctionAsync(""" + () => navigator.userActivation.isActive && navigator.userActivation.hasBeenActive + """, true); + + Assert.That(res, Is.False); + } + + [Test] + public async Task CanCallFunctionWithArguments() + { + var res = await context.Script.CallFunctionAsync("(...args)=>{return args}", false, new() + { + Arguments = ["abc", 42] + }); + + Assert.That(res.Result, Is.AssignableFrom()); + Assert.That((string)(res.Result as RemoteValue.Array).Value[0], Is.EqualTo("abc")); + Assert.That((int)(res.Result as RemoteValue.Array).Value[1], Is.EqualTo(42)); + } + + [Test] + public async Task CanCallFunctionToGetIFrameBrowsingContext() + { + driver.Url = UrlBuilder.WhereIs("click_too_big_in_frame.html"); + + var res = await context.Script.CallFunctionAsync(""" + () => document.querySelector('iframe[id="iframe1"]').contentWindow + """, false); + + Assert.That(res, Is.Not.Null); + Assert.That(res.Result, Is.AssignableFrom()); + Assert.That((res.Result as RemoteValue.WindowProxy).Value, Is.Not.Null); + } + + [Test] + public async Task CanCallFunctionToGetElement() + { + driver.Url = UrlBuilder.WhereIs("bidi/logEntryAdded.html"); + + var res = await context.Script.CallFunctionAsync(""" + () => document.getElementById("consoleLog") + """, false); + + Assert.That(res, Is.Not.Null); + Assert.That(res.Result, Is.AssignableFrom()); + Assert.That((res.Result as RemoteValue.Node).Value, Is.Not.Null); + } + + [Test] + public async Task CanCallFunctionWithAwaitPromise() + { + var res = await context.Script.CallFunctionAsync(""" + async function() { + await new Promise(r => setTimeout(() => r(), 0)); + return "SOME_DELAYED_RESULT"; + } + """, awaitPromise: true); + + Assert.That(res, Is.EqualTo("SOME_DELAYED_RESULT")); + } + + [Test] + public async Task CanCallFunctionWithAwaitPromiseFalse() + { + var res = await context.Script.CallFunctionAsync(""" + async function() { + await new Promise(r => setTimeout(() => r(), 0)); + return "SOME_DELAYED_RESULT"; + } + """, awaitPromise: false); + + Assert.That(res, Is.Not.Null); + Assert.That(res.Result, Is.AssignableFrom()); + } + + [Test] + public async Task CanCallFunctionWithThisParameter() + { + var thisParameter = new LocalValue.Object([["some_property", 42]]); + + var res = await context.Script.CallFunctionAsync(""" + function(){return this.some_property} + """, false, new() { This = thisParameter }); + + Assert.That(res, Is.EqualTo(42)); + } + + [Test] + public async Task CanCallFunctionWithOwnershipRoot() + { + var res = await context.Script.CallFunctionAsync("async function(){return {a:1}}", true, new() + { + ResultOwnership = ResultOwnership.Root + }); + + Assert.That(res, Is.Not.Null); + Assert.That((res.Result as RemoteValue.Object).Handle, Is.Not.Null); + Assert.That((string)(res.Result as RemoteValue.Object).Value[0][0], Is.EqualTo("a")); + Assert.That((int)(res.Result as RemoteValue.Object).Value[0][1], Is.EqualTo(1)); + } + + [Test] + public async Task CanCallFunctionWithOwnershipNone() + { + var res = await context.Script.CallFunctionAsync("async function(){return {a:1}}", true, new() + { + ResultOwnership = ResultOwnership.None + }); + + Assert.That(res, Is.Not.Null); + Assert.That((res.Result as RemoteValue.Object).Handle, Is.Null); + Assert.That((string)(res.Result as RemoteValue.Object).Value[0][0], Is.EqualTo("a")); + Assert.That((int)(res.Result as RemoteValue.Object).Value[0][1], Is.EqualTo(1)); + } + + [Test] + public void CanCallFunctionThatThrowsException() + { + var action = () => context.Script.CallFunctionAsync("))) !!@@## some invalid JS script (((", false); + + Assert.That(action, Throws.InstanceOf().And.Message.Contain("SyntaxError:")); + } + + [Test] + public async Task CanCallFunctionInASandBox() + { + // Make changes without sandbox + await context.Script.CallFunctionAsync("() => { window.foo = 1; }", true); + + var res = await context.Script.CallFunctionAsync("() => window.foo", true, targetOptions: new() { Sandbox = "sandbox" }); + + Assert.That(res.Result, Is.AssignableFrom()); + + // Make changes in the sandbox + await context.Script.CallFunctionAsync("() => { window.foo = 2; }", true, targetOptions: new() { Sandbox = "sandbox" }); + + // Check if the changes are present in the sandbox + res = await context.Script.CallFunctionAsync("() => window.foo", true, targetOptions: new() { Sandbox = "sandbox" }); + + Assert.That(res.Result, Is.AssignableFrom()); + Assert.That((res.Result as RemoteValue.Number).Value, Is.EqualTo(2)); + } + + [Test] + public async Task CanCallFunctionInARealm() + { + await bidi.BrowsingContext.CreateAsync(Modules.BrowsingContext.ContextType.Tab); + + var realms = await bidi.Script.GetRealmsAsync(); + + await bidi.Script.CallFunctionAsync("() => { window.foo = 3; }", true, new Target.Realm(realms[0].Realm)); + await bidi.Script.CallFunctionAsync("() => { window.foo = 5; }", true, new Target.Realm(realms[1].Realm)); + + var res1 = await bidi.Script.CallFunctionAsync("() => window.foo", true, new Target.Realm(realms[0].Realm)); + var res2 = await bidi.Script.CallFunctionAsync("() => window.foo", true, new Target.Realm(realms[1].Realm)); + + Assert.That(res1, Is.EqualTo(3)); + Assert.That(res2, Is.EqualTo(5)); + } +} diff --git a/dotnet/test/common/BiDi/Script/EvaluateParametersTest.cs b/dotnet/test/common/BiDi/Script/EvaluateParametersTest.cs new file mode 100644 index 0000000000000..bb526ff9a4d89 --- /dev/null +++ b/dotnet/test/common/BiDi/Script/EvaluateParametersTest.cs @@ -0,0 +1,109 @@ +using NUnit.Framework; +using OpenQA.Selenium.BiDi.Modules.Script; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.Script; + +class EvaluateParametersTest : BiDiTestFixture +{ + [Test] + public async Task CanEvaluateScript() + { + var res = await context.Script.EvaluateAsync("1 + 2", false); + + Assert.That(res, Is.Not.Null); + Assert.That(res.Realm, Is.Not.Null); + Assert.That((res.Result as RemoteValue.Number).Value, Is.EqualTo(3)); + } + + [Test] + public async Task CanEvaluateScriptImplicitCast() + { + var res = await context.Script.EvaluateAsync("1 + 2", false); + + Assert.That(res, Is.EqualTo(3)); + } + + [Test] + public async Task СanEvaluateScriptWithUserActivationTrue() + { + await context.Script.EvaluateAsync("window.open();", true, new() { UserActivation = true }); + + var res = await context.Script.EvaluateAsync(""" + navigator.userActivation.isActive && navigator.userActivation.hasBeenActive + """, true, new() { UserActivation = true }); + + Assert.That(res, Is.True); + } + + [Test] + public async Task СanEvaluateScriptWithUserActivationFalse() + { + await context.Script.EvaluateAsync("window.open();", true, new() { UserActivation = true }); + + var res = await context.Script.EvaluateAsync(""" + navigator.userActivation.isActive && navigator.userActivation.hasBeenActive + """, true, new() { UserActivation = false }); + + Assert.That(res, Is.False); + } + + [Test] + public void CanCallFunctionThatThrowsException() + { + var action = () => context.Script.EvaluateAsync("))) !!@@## some invalid JS script (((", false); + + Assert.That(action, Throws.InstanceOf().And.Message.Contain("SyntaxError:")); + } + + [Test] + public async Task CanEvaluateScriptWithResulWithOwnership() + { + var res = await context.Script.EvaluateAsync("Promise.resolve({a:1})", true, new() + { + ResultOwnership = ResultOwnership.Root + }); + + Assert.That(res, Is.Not.Null); + Assert.That((res.Result as RemoteValue.Object).Handle, Is.Not.Null); + Assert.That((string)(res.Result as RemoteValue.Object).Value[0][0], Is.EqualTo("a")); + Assert.That((int)(res.Result as RemoteValue.Object).Value[0][1], Is.EqualTo(1)); + } + + [Test] + public async Task CanEvaluateInASandBox() + { + // Make changes without sandbox + await context.Script.EvaluateAsync("window.foo = 1", true); + + var res = await context.Script.EvaluateAsync("window.foo", true, targetOptions: new() { Sandbox = "sandbox" }); + + Assert.That(res.Result, Is.AssignableFrom()); + + // Make changes in the sandbox + await context.Script.EvaluateAsync("window.foo = 2", true, targetOptions: new() { Sandbox = "sandbox" }); + + // Check if the changes are present in the sandbox + res = await context.Script.EvaluateAsync("window.foo", true, targetOptions: new() { Sandbox = "sandbox" }); + + Assert.That(res.Result, Is.AssignableFrom()); + Assert.That((res.Result as RemoteValue.Number).Value, Is.EqualTo(2)); + } + + [Test] + public async Task CanEvaluateInARealm() + { + await bidi.BrowsingContext.CreateAsync(Modules.BrowsingContext.ContextType.Tab); + + var realms = await bidi.Script.GetRealmsAsync(); + + await bidi.Script.EvaluateAsync("window.foo = 3", true, new Target.Realm(realms[0].Realm)); + await bidi.Script.EvaluateAsync("window.foo = 5", true, new Target.Realm(realms[1].Realm)); + + var res1 = await bidi.Script.EvaluateAsync("window.foo", true, new Target.Realm(realms[0].Realm)); + var res2 = await bidi.Script.EvaluateAsync("window.foo", true, new Target.Realm(realms[1].Realm)); + + Assert.That(res1, Is.EqualTo(3)); + Assert.That(res2, Is.EqualTo(5)); + } +} diff --git a/dotnet/test/common/BiDi/Script/ScriptCommandsTest.cs b/dotnet/test/common/BiDi/Script/ScriptCommandsTest.cs new file mode 100644 index 0000000000000..c013fbbbed2d4 --- /dev/null +++ b/dotnet/test/common/BiDi/Script/ScriptCommandsTest.cs @@ -0,0 +1,150 @@ +using NUnit.Framework; +using OpenQA.Selenium.BiDi.Modules.Script; +using System; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.Script; + +class ScriptCommandsTest : BiDiTestFixture +{ + [Test] + public async Task CanGetAllRealms() + { + _ = await bidi.BrowsingContext.CreateAsync(Modules.BrowsingContext.ContextType.Window); + + var realms = await bidi.Script.GetRealmsAsync(); + + Assert.That(realms, Is.Not.Null); + Assert.That(realms.Count, Is.EqualTo(2)); + + Assert.That(realms[0], Is.AssignableFrom()); + Assert.That(realms[0].Realm, Is.Not.Null); + + Assert.That(realms[1], Is.AssignableFrom()); + Assert.That(realms[1].Realm, Is.Not.Null); + } + + [Test] + public async Task CanGetAllRealmsByType() + { + _ = await bidi.BrowsingContext.CreateAsync(Modules.BrowsingContext.ContextType.Window); + + var realms = await bidi.Script.GetRealmsAsync(new() { Type = RealmType.Window }); + + Assert.That(realms, Is.Not.Null); + Assert.That(realms.Count, Is.EqualTo(2)); + + Assert.That(realms[0], Is.AssignableFrom()); + Assert.That(realms[0].Realm, Is.Not.Null); + + Assert.That(realms[1], Is.AssignableFrom()); + Assert.That(realms[1].Realm, Is.Not.Null); + } + + [Test] + public async Task CanGetRealmInBrowsingContext() + { + var tab = await bidi.BrowsingContext.CreateAsync(Modules.BrowsingContext.ContextType.Tab); + + var realms = await tab.Script.GetRealmsAsync(); + + var tabRealm = realms[0] as RealmInfo.Window; + + Assert.That(tabRealm, Is.Not.Null); + Assert.That(tabRealm.Context, Is.EqualTo(tab)); + } + + [Test] + public async Task CanGetRealmInBrowsingContextByType() + { + var tab = await bidi.BrowsingContext.CreateAsync(Modules.BrowsingContext.ContextType.Tab); + + var realms = await tab.Script.GetRealmsAsync(new() { Type = RealmType.Window }); + + var tabRealm = realms[0] as RealmInfo.Window; + + Assert.That(tabRealm, Is.Not.Null); + Assert.That(tabRealm.Context, Is.EqualTo(tab)); + } + + [Test] + public async Task CanAddPreloadScript() + { + var preloadScript = await bidi.Script.AddPreloadScriptAsync("() => { console.log('preload_script_console_text') }"); + + Assert.That(preloadScript, Is.Not.Null); + + TaskCompletionSource tcs = new(); + + await context.Log.OnEntryAddedAsync(tcs.SetResult); + + await context.ReloadAsync(new() { Wait = Modules.BrowsingContext.ReadinessState.Interactive }); + + var entry = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.That(entry.Level, Is.EqualTo(Modules.Log.Level.Info)); + Assert.That(entry.Text, Is.EqualTo("preload_script_console_text")); + } + + [Test] + public async Task CanAddPreloadScriptWithArguments() + { + var preloadScript = await bidi.Script.AddPreloadScriptAsync("(channel) => channel('will_be_send', 'will_be_ignored')", new() + { + Arguments = [new LocalValue.Channel(new(new("channel_name")))] + }); + + Assert.That(preloadScript, Is.Not.Null); + } + + + [Test] + public async Task CanAddPreloadScriptWithChannelOptions() + { + var preloadScript = await bidi.Script.AddPreloadScriptAsync("(channel) => channel('will_be_send', 'will_be_ignored')", new() + { + Arguments = [new LocalValue.Channel(new(new("channel_name")) + { + SerializationOptions = new() + { + MaxDomDepth = 0 + }, + Ownership = ResultOwnership.Root + })] + }); + + Assert.That(preloadScript, Is.Not.Null); + } + + [Test] + public async Task CanAddPreloadScriptInASandbox() + { + var preloadScript = await bidi.Script.AddPreloadScriptAsync("() => { window.bar = 2; }", new() { Sandbox = "sandbox" }); + + Assert.That(preloadScript, Is.Not.Null); + + await context.ReloadAsync(new() { Wait = Modules.BrowsingContext.ReadinessState.Interactive }); + + var bar = await context.Script.EvaluateAsync("window.bar", true, targetOptions: new() { Sandbox = "sandbox" }); + + Assert.That(bar, Is.EqualTo(2)); + } + + [Test] + public async Task CanRemovePreloadedScript() + { + var preloadScript = await context.Script.AddPreloadScriptAsync("() => { window.bar = 2; }"); + + await context.ReloadAsync(new() { Wait = Modules.BrowsingContext.ReadinessState.Interactive }); + + var bar = await context.Script.EvaluateAsync("window.bar", true); + + Assert.That(bar, Is.EqualTo(2)); + + await preloadScript.RemoveAsync(); + + var resultAfterRemoval = await context.Script.EvaluateAsync("window.bar", true, targetOptions: new() { Sandbox = "sandbox" }); + + Assert.That(resultAfterRemoval.Result, Is.AssignableFrom()); + } +} diff --git a/dotnet/test/common/BiDi/Script/ScriptEventsTest.cs b/dotnet/test/common/BiDi/Script/ScriptEventsTest.cs new file mode 100644 index 0000000000000..48fc3b5686371 --- /dev/null +++ b/dotnet/test/common/BiDi/Script/ScriptEventsTest.cs @@ -0,0 +1,63 @@ +using NUnit.Framework; +using OpenQA.Selenium.BiDi.Modules.Script; +using System; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.Script; + +class ScriptEventsTest : BiDiTestFixture +{ + [Test] + public async Task CanListenToChannelMessage() + { + TaskCompletionSource tcs = new(); + + await bidi.Script.OnMessageAsync(tcs.SetResult); + + await context.Script.CallFunctionAsync("(channel) => channel('foo')", false, new() + { + Arguments = [new LocalValue.Channel(new(new("channel_name")))] + }); + + var message = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.That(message, Is.Not.Null); + Assert.That(message.Channel.Id, Is.EqualTo("channel_name")); + Assert.That((string)message.Data, Is.EqualTo("foo")); + Assert.That(message.Source, Is.Not.Null); + Assert.That(message.Source.Realm, Is.Not.Null); + Assert.That(message.Source.Context, Is.EqualTo(context)); + } + + [Test] + public async Task CanListenToRealmCreatedEvent() + { + TaskCompletionSource tcs = new(); + + await bidi.Script.OnRealmCreatedAsync(tcs.SetResult); + + await bidi.BrowsingContext.CreateAsync(Modules.BrowsingContext.ContextType.Window); + + var realmInfo = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.That(realmInfo, Is.Not.Null); + Assert.That(realmInfo, Is.AssignableFrom()); + Assert.That(realmInfo.Realm, Is.Not.Null); + } + + [Test] + public async Task CanListenToRealmDestroyedEvent() + { + TaskCompletionSource tcs = new(); + + await bidi.Script.OnRealmDestroyedAsync(tcs.SetResult); + + var ctx = await bidi.BrowsingContext.CreateAsync(Modules.BrowsingContext.ContextType.Window); + await ctx.CloseAsync(); + + var args = await tcs.Task.WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.That(args, Is.Not.Null); + Assert.That(args.Realm, Is.Not.Null); + } +} diff --git a/dotnet/test/common/BiDi/Storage/StorageTest.cs b/dotnet/test/common/BiDi/Storage/StorageTest.cs new file mode 100644 index 0000000000000..2f9877c4ca1aa --- /dev/null +++ b/dotnet/test/common/BiDi/Storage/StorageTest.cs @@ -0,0 +1,161 @@ +using NUnit.Framework; +using OpenQA.Selenium.BiDi.Modules.Network; +using System; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.Storage; + +class StorageTest : BiDiTestFixture +{ + [Test] + public async Task CanGetCookieByName() + { + driver.Url = UrlBuilder.WhereIs("animals"); + + var cookies = await bidi.Storage.GetCookiesAsync(new() + { + Filter = new() + { + Name = Guid.NewGuid().ToString(), + Value = "set" + } + }); + + Assert.That(cookies, Is.Not.Null); + Assert.That(cookies, Is.Empty); + } + + [Test] + public async Task CanGetCookieInDefaultUserContext() + { + driver.Url = UrlBuilder.WhereIs("animals"); + + var userContexts = await bidi.Browser.GetUserContextsAsync(); + + var cookies = await context.Storage.GetCookiesAsync(new() + { + Filter = new() + { + Name = Guid.NewGuid().ToString(), + Value = "set" + } + }); + + Assert.That(cookies, Is.Not.Null); + Assert.That(cookies, Is.Empty); + Assert.That(cookies.PartitionKey.UserContext, Is.EqualTo(userContexts[0].UserContext)); + } + + [Test] + public async Task CanAddCookie() + { + driver.Url = UrlBuilder.WhereIs("animals"); + + var partitionKey = await context.Storage.SetCookieAsync(new("fish", "cod", UrlBuilder.HostName)); + + Assert.That(partitionKey, Is.Not.Null); + } + + [Test] + public async Task CanAddAndGetCookie() + { + driver.Url = UrlBuilder.WhereIs("animals"); + + var expiry = DateTime.Now.AddDays(1); + + await context.Storage.SetCookieAsync(new("fish", "cod", UrlBuilder.HostName) + { + Path = "/common/animals", + HttpOnly = true, + Secure = false, + SameSite = SameSite.Lax, + Expiry = expiry + }); + + var cookies = await context.Storage.GetCookiesAsync(); + + Assert.That(cookies, Is.Not.Null); + Assert.That(cookies.Count, Is.EqualTo(1)); + + var cookie = cookies[0]; + + Assert.That(cookie.Name, Is.EqualTo("fish")); + Assert.That((cookie.Value as BytesValue.String).Value, Is.EqualTo("cod")); + Assert.That(cookie.Path, Is.EqualTo("/common/animals")); + Assert.That(cookie.HttpOnly, Is.True); + Assert.That(cookie.Secure, Is.False); + Assert.That(cookie.SameSite, Is.EqualTo(SameSite.Lax)); + Assert.That(cookie.Size, Is.EqualTo(7)); + // Assert.That(cookie.Expiry, Is.EqualTo(expiry)); // chrome issue + } + + [Test] + public async Task CanGetAllCookies() + { + driver.Url = UrlBuilder.WhereIs("animals"); + + driver.Manage().Cookies.AddCookie(new("key1", "value1")); + driver.Manage().Cookies.AddCookie(new("key2", "value2")); + + var cookies = await bidi.Storage.GetCookiesAsync(); + + Assert.That(cookies, Is.Not.Null); + Assert.That(cookies.Count, Is.EqualTo(2)); + Assert.That(cookies[0].Name, Is.EqualTo("key1")); + Assert.That(cookies[1].Name, Is.EqualTo("key2")); + } + + [Test] + public async Task CanDeleteAllCookies() + { + driver.Url = UrlBuilder.WhereIs("animals"); + + driver.Manage().Cookies.AddCookie(new("key1", "value1")); + driver.Manage().Cookies.AddCookie(new("key2", "value2")); + + var result = await bidi.Storage.DeleteCookiesAsync(); + + Assert.That(result, Is.Not.Null); + + var cookies = await bidi.Storage.GetCookiesAsync(); + + Assert.That(cookies, Is.Not.Null); + Assert.That(cookies.Count, Is.EqualTo(0)); + } + + [Test] + public async Task CanDeleteCookieWithName() + { + driver.Url = UrlBuilder.WhereIs("animals"); + + driver.Manage().Cookies.AddCookie(new("key1", "value1")); + driver.Manage().Cookies.AddCookie(new("key2", "value2")); + + var result = await bidi.Storage.DeleteCookiesAsync(new() { Filter = new() { Name = "key1" } }); + + Assert.That(result, Is.Not.Null); + + var cookies = await bidi.Storage.GetCookiesAsync(); + + Assert.That(cookies, Is.Not.Null); + Assert.That(cookies.Count, Is.EqualTo(1)); + Assert.That(cookies[0].Name, Is.EqualTo("key2")); + } + + [Test] + public async Task AddCookiesWithDifferentPathsThatAreRelatedToOurs() + { + driver.Url = UrlBuilder.WhereIs("animals"); + + await context.Storage.SetCookieAsync(new("fish", "cod", UrlBuilder.HostName) + { + Path = "/common/animals" + }); + + driver.Url = UrlBuilder.WhereIs("simpleTest"); + + var result = driver.Manage().Cookies.AllCookies; + + Assert.That(result, Is.Empty); + } +} diff --git a/dotnet/test/common/Environment/DriverFactory.cs b/dotnet/test/common/Environment/DriverFactory.cs index 8ce615235dc7d..5708ebda6495d 100644 --- a/dotnet/test/common/Environment/DriverFactory.cs +++ b/dotnet/test/common/Environment/DriverFactory.cs @@ -67,12 +67,6 @@ public IWebDriver CreateDriverWithOptions(Type driverType, DriverOptions driverO { browser = Browser.Chrome; options = GetDriverOptions(driverType, driverOptions); - // Disabling this since we do not have any BiDi tests currently. - //options.UseWebSocketUrl = true; - - // If BiDi is enabled above then the undhandler prompt behaviour needs to set accordingly. - // Reasoning : https://github.com/SeleniumHQ/selenium/pull/14429#issuecomment-2311614822 - //options.UnhandledPromptBehavior = UnhandledPromptBehavior.Ignore; var chromeOptions = (ChromeOptions)options; chromeOptions.AddArguments("--no-sandbox", "--disable-dev-shm-usage"); @@ -188,6 +182,8 @@ protected void OnDriverLaunching(DriverService service, DriverOptions options) options.ScriptTimeout = overriddenOptions.ScriptTimeout; options.PageLoadTimeout = overriddenOptions.PageLoadTimeout; options.ImplicitWaitTimeout = overriddenOptions.ImplicitWaitTimeout; + + options.UseWebSocketUrl = overriddenOptions.UseWebSocketUrl; } return options;