diff --git a/dotnet/src/webdriver/BiDi/Communication/Broker.cs b/dotnet/src/webdriver/BiDi/Communication/Broker.cs index f249631cf5ce2..2e3982b4bdccb 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Broker.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Broker.cs @@ -70,6 +70,7 @@ internal Broker(BiDi bidi, ITransport transport) { new BrowsingContextConverter(_bidi), new BrowserUserContextConverter(bidi), + new BrowserClientWindowConverter(), new NavigationConverter(), new InterceptConverter(_bidi), new RequestConverter(_bidi), @@ -97,6 +98,7 @@ internal Broker(BiDi bidi, ITransport transport) new Json.Converters.Enumerable.LocateNodesResultConverter(), new Json.Converters.Enumerable.InputSourceActionsConverter(), new Json.Converters.Enumerable.GetUserContextsResultConverter(), + new Json.Converters.Enumerable.GetClientWindowsResultConverter(), new Json.Converters.Enumerable.GetRealmsResultConverter(), } }; diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs b/dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs index 6da7e08a01a84..09e0a8564ce86 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs @@ -86,8 +86,11 @@ namespace OpenQA.Selenium.BiDi.Communication.Json; [JsonSerializable(typeof(Modules.Browser.GetUserContextsCommand))] [JsonSerializable(typeof(Modules.Browser.GetUserContextsResult))] [JsonSerializable(typeof(Modules.Browser.RemoveUserContextCommand))] +[JsonSerializable(typeof(Modules.Browser.GetClientWindowsCommand))] +[JsonSerializable(typeof(Modules.Browser.GetClientWindowsResult))] [JsonSerializable(typeof(Modules.Browser.UserContextInfo))] [JsonSerializable(typeof(IReadOnlyList))] +[JsonSerializable(typeof(IReadOnlyList))] [JsonSerializable(typeof(Modules.BrowsingContext.ActivateCommand))] diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/BrowserClientWindowConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/BrowserClientWindowConverter.cs new file mode 100644 index 0000000000000..30a9761eff982 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/BrowserClientWindowConverter.cs @@ -0,0 +1,42 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using OpenQA.Selenium.BiDi.Modules.Browser; +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +#nullable enable + +namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; + +internal class BrowserClientWindowConverter : JsonConverter +{ + public override ClientWindow? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var id = reader.GetString(); + + return new ClientWindow(id!); + } + + public override void Write(Utf8JsonWriter writer, ClientWindow value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.Id); + } +} diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetClientWindowsResultConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetClientWindowsResultConverter.cs new file mode 100644 index 0000000000000..b8453d1884fd0 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetClientWindowsResultConverter.cs @@ -0,0 +1,44 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +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 GetClientWindowsResultConverter : JsonConverter +{ + public override GetClientWindowsResult Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + using var doc = JsonDocument.ParseValue(ref reader); + var clientWindows = doc.RootElement.GetProperty("clientWindows").Deserialize>(options); + + return new GetClientWindowsResult(clientWindows!); + } + + public override void Write(Utf8JsonWriter writer, GetClientWindowsResult value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetCookiesResultConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetCookiesResultConverter.cs index ebb0beada2d22..28a6ee03d74c3 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetCookiesResultConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetCookiesResultConverter.cs @@ -31,7 +31,7 @@ internal class GetCookiesResultConverter : JsonConverter { public override GetCookiesResult Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - var doc = JsonDocument.ParseValue(ref reader); + using var doc = JsonDocument.ParseValue(ref reader); var cookies = doc.RootElement.GetProperty("cookies").Deserialize>(options); var partitionKey = doc.RootElement.GetProperty("partitionKey").Deserialize(options); diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetRealmsResultConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetRealmsResultConverter.cs index d09e40789f6d8..f37d3c996de3c 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetRealmsResultConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetRealmsResultConverter.cs @@ -31,7 +31,7 @@ internal class GetRealmsResultConverter : JsonConverter { public override GetRealmsResult Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - var doc = JsonDocument.ParseValue(ref reader); + using var doc = JsonDocument.ParseValue(ref reader); var realms = doc.RootElement.GetProperty("realms").Deserialize>(options); return new GetRealmsResult(realms!); diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetUserContextsResultConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetUserContextsResultConverter.cs index 5e78a58ddd304..ec3aca43e29ed 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetUserContextsResultConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetUserContextsResultConverter.cs @@ -31,7 +31,7 @@ internal class GetUserContextsResultConverter : JsonConverter>(options); return new GetUserContextsResult(userContexts!); diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/LocateNodesResultConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/LocateNodesResultConverter.cs index 7a6c5cd6b68fa..68c038a263cd4 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/LocateNodesResultConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/LocateNodesResultConverter.cs @@ -32,7 +32,7 @@ internal class LocateNodesResultConverter : JsonConverter { public override LocateNodesResult Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - var doc = JsonDocument.ParseValue(ref reader); + using var doc = JsonDocument.ParseValue(ref reader); var nodes = doc.RootElement.GetProperty("nodes").Deserialize>(options); return new LocateNodesResult(nodes!); diff --git a/dotnet/src/webdriver/BiDi/Modules/Browser/BrowserModule.cs b/dotnet/src/webdriver/BiDi/Modules/Browser/BrowserModule.cs index 54e9dc69b29e3..31bd62fb754f7 100644 --- a/dotnet/src/webdriver/BiDi/Modules/Browser/BrowserModule.cs +++ b/dotnet/src/webdriver/BiDi/Modules/Browser/BrowserModule.cs @@ -48,4 +48,9 @@ public async Task RemoveUserContextAsync(UserContext userContext, RemoveUserCont await Broker.ExecuteCommandAsync(new RemoveUserContextCommand(@params), options).ConfigureAwait(false); } + + public async Task GetClientWindowsAsync(GetClientWindowsOptions? options = null) + { + return await Broker.ExecuteCommandAsync(new(), options).ConfigureAwait(false); + } } diff --git a/dotnet/src/webdriver/BiDi/Modules/Browser/ClientWindow.cs b/dotnet/src/webdriver/BiDi/Modules/Browser/ClientWindow.cs new file mode 100644 index 0000000000000..3d7fe15e77ad3 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Modules/Browser/ClientWindow.cs @@ -0,0 +1,32 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +#nullable enable + +namespace OpenQA.Selenium.BiDi.Modules.Browser; + +public record ClientWindow +{ + internal ClientWindow(string id) + { + Id = id; + } + + internal string Id { get; } +} diff --git a/dotnet/src/webdriver/BiDi/Modules/Browser/ClientWindowInfo.cs b/dotnet/src/webdriver/BiDi/Modules/Browser/ClientWindowInfo.cs new file mode 100644 index 0000000000000..190897a67e4bb --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Modules/Browser/ClientWindowInfo.cs @@ -0,0 +1,34 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +#nullable enable + +using System.Text.Json.Serialization; + +namespace OpenQA.Selenium.BiDi.Modules.Browser; + +public record ClientWindowInfo([property: JsonPropertyName("active")] bool IsActive, ClientWindow ClientWindow, ClientWindowState State, int Height, int Width, int X, int Y); + +public enum ClientWindowState +{ + Fullscreen, + Maximized, + Minimized, + Normal +} diff --git a/dotnet/src/webdriver/BiDi/Modules/Browser/GetClientWindowsCommand.cs b/dotnet/src/webdriver/BiDi/Modules/Browser/GetClientWindowsCommand.cs new file mode 100644 index 0000000000000..f302a787e4388 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Modules/Browser/GetClientWindowsCommand.cs @@ -0,0 +1,49 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using OpenQA.Selenium.BiDi.Communication; +using System.Collections; +using System.Collections.Generic; + +#nullable enable + +namespace OpenQA.Selenium.BiDi.Modules.Browser; + +internal class GetClientWindowsCommand() + : Command(CommandParameters.Empty, "browser.getClientWindows"); + +public record GetClientWindowsOptions : CommandOptions; + +public record GetClientWindowsResult : IReadOnlyList +{ + private readonly IReadOnlyList _clientWindows; + + internal GetClientWindowsResult(IReadOnlyList clientWindows) + { + _clientWindows = clientWindows; + } + + public ClientWindowInfo this[int index] => _clientWindows[index]; + + public int Count => _clientWindows.Count; + + public IEnumerator GetEnumerator() => _clientWindows.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => (_clientWindows as IEnumerable).GetEnumerator(); +} diff --git a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextInfo.cs b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextInfo.cs index 615730885f8b4..adc744bdf4776 100644 --- a/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextInfo.cs +++ b/dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextInfo.cs @@ -25,7 +25,7 @@ namespace OpenQA.Selenium.BiDi.Modules.BrowsingContext; // TODO: Split it to separate class with just info and event args -public record BrowsingContextInfo(BiDi BiDi, IReadOnlyList Children, BrowsingContext Context, BrowsingContext OriginalOpener, string Url, Browser.UserContext UserContext) +public record BrowsingContextInfo(BiDi BiDi, IReadOnlyList Children, Browser.ClientWindow ClientWindow, BrowsingContext Context, BrowsingContext OriginalOpener, string Url, Browser.UserContext UserContext) : BrowsingContextEventArgs(BiDi, Context) { [JsonInclude] diff --git a/dotnet/test/common/BiDi/Browser/BrowserTest.cs b/dotnet/test/common/BiDi/Browser/BrowserTest.cs index 096970d178543..ca8dc63abba0f 100644 --- a/dotnet/test/common/BiDi/Browser/BrowserTest.cs +++ b/dotnet/test/common/BiDi/Browser/BrowserTest.cs @@ -59,4 +59,16 @@ public async Task CanRemoveUserContext() Assert.That(userContexts, Does.Contain(userContext1)); Assert.That(userContexts, Does.Not.Contain(userContext2)); } + + [Test] + [IgnoreBrowser(Selenium.Browser.Chrome, "BiDi GetClientWindows command not yet supported by Chrome 133")] + [IgnoreBrowser(Selenium.Browser.Edge, "BiDi GetClientWindows command not yet supported by Edge 133")] + public async Task CanGetClientWindows() + { + var clientWindows = await bidi.Browser.GetClientWindowsAsync(); + + Assert.That(clientWindows, Is.Not.Null); + Assert.That(clientWindows, Has.Count.GreaterThanOrEqualTo(1)); + Assert.That(clientWindows[0].ClientWindow, Is.Not.Null); + } }