From b8cb6c28b4ab105d6c2a5bf2925a310e6b3c1b85 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Tue, 3 Jun 2025 01:33:47 +0300 Subject: [PATCH 01/12] Install --- .../BiDi/WebExtension/InstallCommand.cs | 46 +++++++++++++++++++ .../BiDi/WebExtension/WebExtensionModule.cs | 33 +++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs create mode 100644 dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs diff --git a/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs b/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs new file mode 100644 index 0000000000000..8b0be8cdf68f5 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs @@ -0,0 +1,46 @@ +// +// 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.Text.Json.Serialization; + +namespace OpenQA.Selenium.BiDi.WebExtension; + +internal class InstallCommand(InstallCommandParameters @params) + : Command(@params, "webExtension.install"); + +internal record InstallCommandParameters(ExtensionData ExtensionData) : CommandParameters; + +[JsonDerivedType(typeof(ExtensionArchivePath), "archivePath")] +[JsonDerivedType(typeof(ExtensionBase64Encoded), "base64")] +[JsonDerivedType(typeof(ExtensionPath), "path")] +public abstract record ExtensionData; + +public record ExtensionArchivePath(string Path) : ExtensionData; + +public record ExtensionBase64Encoded(string Value) : ExtensionData; + +public record ExtensionPath(string Path) : ExtensionData; + +public record InstallCommandOptions : CommandOptions; + +public record InstallResult : EmptyResult +{ + +} diff --git a/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs b/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs new file mode 100644 index 0000000000000..fabbd0bc61c9a --- /dev/null +++ b/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs @@ -0,0 +1,33 @@ +// +// 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.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.WebExtension; + +public sealed class WebExtensionModule(Broker broker) : Module(broker) +{ + public async Task InstallAsync(ExtensionData extensionData, InstallCommandOptions? options = null) + { + var @params = new InstallCommandParameters(extensionData); + + return await Broker.ExecuteCommandAsync(new InstallCommand(@params), options).ConfigureAwait(false); + } +} From 9bb7c20fbb28672351996c00aad367671752d2ab Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Tue, 3 Jun 2025 01:58:39 +0300 Subject: [PATCH 02/12] Install coommand --- .../webdriver/BiDi/Communication/Broker.cs | 1 + .../Json/Converters/WebExtensionConverter.cs | 40 +++++++++++++++++++ .../webdriver/BiDi/WebExtension/Extension.cs | 22 ++++++++++ .../BiDi/WebExtension/InstallCommand.cs | 6 +-- 4 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 dotnet/src/webdriver/BiDi/Communication/Json/Converters/WebExtensionConverter.cs create mode 100644 dotnet/src/webdriver/BiDi/WebExtension/Extension.cs diff --git a/dotnet/src/webdriver/BiDi/Communication/Broker.cs b/dotnet/src/webdriver/BiDi/Communication/Broker.cs index db926e3b7228e..288914dde2b8a 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Broker.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Broker.cs @@ -86,6 +86,7 @@ internal Broker(BiDi bidi, Uri url) new DateTimeOffsetConverter(), new PrintPageRangeConverter(), new InputOriginConverter(), + new WebExtensionConverter(), new SubscriptionConverter(), new JsonStringEnumConverter(JsonNamingPolicy.CamelCase), diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/WebExtensionConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/WebExtensionConverter.cs new file mode 100644 index 0000000000000..3df451c8938d0 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/WebExtensionConverter.cs @@ -0,0 +1,40 @@ +// +// 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.WebExtension; +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; + +internal class WebExtensionConverter : JsonConverter +{ + public override Extension? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var id = reader.GetString(); + + return new Extension(id!); + } + + public override void Write(Utf8JsonWriter writer, Extension value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.Id); + } +} diff --git a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs new file mode 100644 index 0000000000000..0879dd8fbc6f5 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs @@ -0,0 +1,22 @@ +// +// 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. +// + +namespace OpenQA.Selenium.BiDi.WebExtension; + +public record Extension(string Id); diff --git a/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs b/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs index 8b0be8cdf68f5..d11363fe0a7be 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs @@ -27,6 +27,7 @@ internal class InstallCommand(InstallCommandParameters @params) internal record InstallCommandParameters(ExtensionData ExtensionData) : CommandParameters; +[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] [JsonDerivedType(typeof(ExtensionArchivePath), "archivePath")] [JsonDerivedType(typeof(ExtensionBase64Encoded), "base64")] [JsonDerivedType(typeof(ExtensionPath), "path")] @@ -40,7 +41,4 @@ public record ExtensionPath(string Path) : ExtensionData; public record InstallCommandOptions : CommandOptions; -public record InstallResult : EmptyResult -{ - -} +public record InstallResult(Extension Extension) : EmptyResult; From 3bb1ab683608d582f81a7cb44c3e66b3153104a8 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Tue, 3 Jun 2025 02:08:50 +0300 Subject: [PATCH 03/12] Install command --- dotnet/src/webdriver/BiDi/BiDi.cs | 3 ++ .../Json/BiDiJsonSerializerContext.cs | 3 ++ .../BiDi/WebExtension/WebExtensionTest.cs | 34 +++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs diff --git a/dotnet/src/webdriver/BiDi/BiDi.cs b/dotnet/src/webdriver/BiDi/BiDi.cs index 9964b4e59cea8..7bb83f93137a3 100644 --- a/dotnet/src/webdriver/BiDi/BiDi.cs +++ b/dotnet/src/webdriver/BiDi/BiDi.cs @@ -35,6 +35,7 @@ public class BiDi : IAsyncDisposable private readonly Lazy _scriptModule; private readonly Lazy _logModule; private readonly Lazy _storageModule; + private readonly Lazy _webExtensionModule; internal BiDi(string url) { @@ -50,6 +51,7 @@ internal BiDi(string url) _scriptModule = new Lazy(() => new Script.ScriptModule(_broker)); _logModule = new Lazy(() => new Log.LogModule(_broker)); _storageModule = new Lazy(() => new Storage.StorageModule(_broker)); + _webExtensionModule = new Lazy(() => new WebExtension.WebExtensionModule(_broker)); } internal Session.SessionModule SessionModule => _sessionModule.Value; @@ -60,6 +62,7 @@ internal BiDi(string url) public Script.ScriptModule Script => _scriptModule.Value; public Log.LogModule Log => _logModule.Value; public Storage.StorageModule Storage => _storageModule.Value; + public WebExtension.WebExtensionModule WebExtension => _webExtensionModule.Value; public Task StatusAsync() { diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs b/dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs index 0803f13404c3c..ace02081bce80 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs @@ -164,4 +164,7 @@ namespace OpenQA.Selenium.BiDi.Communication.Json; [JsonSerializable(typeof(IEnumerable))] [JsonSerializable(typeof(IEnumerable))] +[JsonSerializable(typeof(WebExtension.InstallCommand))] +[JsonSerializable(typeof(WebExtension.InstallResult))] + internal partial class BiDiJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs new file mode 100644 index 0000000000000..feadad452b2c7 --- /dev/null +++ b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.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. +// + +using NUnit.Framework; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.BiDi.WebExtension; + +class WebExtensionTest : BiDiTestFixture +{ + [Test] + public async Task CanInstallWebExtension() + { + var result = await bidi.WebExtension.InstallAsync(new ExtensionArchivePath("qwe")); + + Assert.That(result, Is.Not.Null); + } +} From 3a78096fff87abd363c54b38de4af35c0a812e1f Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Tue, 3 Jun 2025 13:50:19 +0300 Subject: [PATCH 04/12] Tests --- .../BiDi/WebExtension/WebExtensionTest.cs | 28 +++++++++++++++++-- .../test/common/WebDriver.Common.Tests.csproj | 4 +++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs index feadad452b2c7..7681933764dfe 100644 --- a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs +++ b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs @@ -18,6 +18,8 @@ // using NUnit.Framework; +using System; +using System.IO; using System.Threading.Tasks; namespace OpenQA.Selenium.BiDi.WebExtension; @@ -25,9 +27,31 @@ namespace OpenQA.Selenium.BiDi.WebExtension; class WebExtensionTest : BiDiTestFixture { [Test] - public async Task CanInstallWebExtension() + public async Task CanInstallPathWebExtension() { - var result = await bidi.WebExtension.InstallAsync(new ExtensionArchivePath("qwe")); + string path = Path.GetFullPath("data/extensions/webextensions-selenium-example"); + + var result = await bidi.WebExtension.InstallAsync(new ExtensionPath(path)); + + Assert.That(result, Is.Not.Null); + } + + [Test] + public async Task CanInstallArchiveWebExtension() + { + string path = Path.GetFullPath("data/extensions/webextensions-selenium-example.zip"); + + var result = await bidi.WebExtension.InstallAsync(new ExtensionArchivePath(path)); + + Assert.That(result, Is.Not.Null); + } + + [Test] + public async Task CanInstallBase64WebExtension() + { + string base64 = Convert.ToBase64String(File.ReadAllBytes("data/extensions/webextensions-selenium-example.zip")); + + var result = await bidi.WebExtension.InstallAsync(new ExtensionBase64Encoded(base64)); Assert.That(result, Is.Not.Null); } diff --git a/dotnet/test/common/WebDriver.Common.Tests.csproj b/dotnet/test/common/WebDriver.Common.Tests.csproj index 270c832cb6785..980b97160959f 100644 --- a/dotnet/test/common/WebDriver.Common.Tests.csproj +++ b/dotnet/test/common/WebDriver.Common.Tests.csproj @@ -27,6 +27,10 @@ Always + + data\extensions\%(RecursiveDir)%(Filename)%(Extension) + PreserveNewest + From 80801a52f6da4dc1bd275694fc980f3fb0bc6eb6 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Tue, 3 Jun 2025 22:16:16 +0300 Subject: [PATCH 05/12] Uninstall --- .../webdriver/BiDi/Communication/Broker.cs | 2 +- .../Json/BiDiJsonSerializerContext.cs | 1 + .../Json/Converters/WebExtensionConverter.cs | 9 +++++- .../webdriver/BiDi/WebExtension/Extension.cs | 20 ++++++++++++- .../BiDi/WebExtension/InstallCommand.cs | 2 +- .../BiDi/WebExtension/UninstallCommand.cs | 29 +++++++++++++++++++ .../BiDi/WebExtension/WebExtensionModule.cs | 9 +++++- .../BiDi/WebExtension/WebExtensionTest.cs | 10 +++++++ 8 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 dotnet/src/webdriver/BiDi/WebExtension/UninstallCommand.cs diff --git a/dotnet/src/webdriver/BiDi/Communication/Broker.cs b/dotnet/src/webdriver/BiDi/Communication/Broker.cs index 288914dde2b8a..f1f4aa79579d7 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Broker.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Broker.cs @@ -86,7 +86,7 @@ internal Broker(BiDi bidi, Uri url) new DateTimeOffsetConverter(), new PrintPageRangeConverter(), new InputOriginConverter(), - new WebExtensionConverter(), + new WebExtensionConverter(_bidi), new SubscriptionConverter(), new JsonStringEnumConverter(JsonNamingPolicy.CamelCase), diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs b/dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs index ace02081bce80..88b48fc6e3780 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/BiDiJsonSerializerContext.cs @@ -166,5 +166,6 @@ namespace OpenQA.Selenium.BiDi.Communication.Json; [JsonSerializable(typeof(WebExtension.InstallCommand))] [JsonSerializable(typeof(WebExtension.InstallResult))] +[JsonSerializable(typeof(WebExtension.UninstallCommand))] internal partial class BiDiJsonSerializerContext : JsonSerializerContext; diff --git a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/WebExtensionConverter.cs b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/WebExtensionConverter.cs index 3df451c8938d0..f29dc90567fad 100644 --- a/dotnet/src/webdriver/BiDi/Communication/Json/Converters/WebExtensionConverter.cs +++ b/dotnet/src/webdriver/BiDi/Communication/Json/Converters/WebExtensionConverter.cs @@ -26,11 +26,18 @@ namespace OpenQA.Selenium.BiDi.Communication.Json.Converters; internal class WebExtensionConverter : JsonConverter { + private readonly BiDi _bidi; + + public WebExtensionConverter(BiDi bidi) + { + _bidi = bidi; + } + public override Extension? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var id = reader.GetString(); - return new Extension(id!); + return new Extension(_bidi, id!); } public override void Write(Utf8JsonWriter writer, Extension value, JsonSerializerOptions options) diff --git a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs index 0879dd8fbc6f5..ba36dc4f53e13 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs @@ -17,6 +17,24 @@ // under the License. // +using System.Threading.Tasks; + namespace OpenQA.Selenium.BiDi.WebExtension; -public record Extension(string Id); +public class Extension +{ + private readonly BiDi _bidi; + + public Extension(BiDi bidi, string id) + { + _bidi = bidi; + Id = id; + } + + internal string Id { get; } + + public Task UninstallAsync(UninstallOptions? options = null) + { + return _bidi.WebExtension.UninstallAsync(this, options); + } +} diff --git a/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs b/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs index d11363fe0a7be..95a6a77250af6 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs @@ -39,6 +39,6 @@ public record ExtensionBase64Encoded(string Value) : ExtensionData; public record ExtensionPath(string Path) : ExtensionData; -public record InstallCommandOptions : CommandOptions; +public record InstallOptions : CommandOptions; public record InstallResult(Extension Extension) : EmptyResult; diff --git a/dotnet/src/webdriver/BiDi/WebExtension/UninstallCommand.cs b/dotnet/src/webdriver/BiDi/WebExtension/UninstallCommand.cs new file mode 100644 index 0000000000000..39b35a05ad1a7 --- /dev/null +++ b/dotnet/src/webdriver/BiDi/WebExtension/UninstallCommand.cs @@ -0,0 +1,29 @@ +// +// 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; + +namespace OpenQA.Selenium.BiDi.WebExtension; + +internal class UninstallCommand(UninstallCommandParameters @params) + : Command(@params, "webExtension.uninstall"); + +internal record UninstallCommandParameters(Extension Extension) : CommandParameters; + +public record UninstallOptions : CommandOptions; diff --git a/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs b/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs index fabbd0bc61c9a..5ec32d4db2342 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/WebExtensionModule.cs @@ -24,10 +24,17 @@ namespace OpenQA.Selenium.BiDi.WebExtension; public sealed class WebExtensionModule(Broker broker) : Module(broker) { - public async Task InstallAsync(ExtensionData extensionData, InstallCommandOptions? options = null) + public async Task InstallAsync(ExtensionData extensionData, InstallOptions? options = null) { var @params = new InstallCommandParameters(extensionData); return await Broker.ExecuteCommandAsync(new InstallCommand(@params), options).ConfigureAwait(false); } + + internal async Task UninstallAsync(Extension extension, UninstallOptions? options = null) + { + var @params = new UninstallCommandParameters(extension); + + await Broker.ExecuteCommandAsync(new UninstallCommand(@params), options).ConfigureAwait(false); + } } diff --git a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs index 7681933764dfe..f4d0ad57653f2 100644 --- a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs +++ b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs @@ -55,4 +55,14 @@ public async Task CanInstallBase64WebExtension() Assert.That(result, Is.Not.Null); } + + [Test] + public async Task CanUninstallExtension() + { + string path = Path.GetFullPath("data/extensions/webextensions-selenium-example"); + + var result = await bidi.WebExtension.InstallAsync(new ExtensionPath(path)); + + await result.Extension.UninstallAsync(); + } } From 73e12f5d8702eeeda8135750d453db6674ce9e1c Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Tue, 3 Jun 2025 23:02:50 +0300 Subject: [PATCH 06/12] Ignore tests --- dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs index f4d0ad57653f2..cf68f7d018b06 100644 --- a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs +++ b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs @@ -27,6 +27,8 @@ namespace OpenQA.Selenium.BiDi.WebExtension; class WebExtensionTest : BiDiTestFixture { [Test] + [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] + [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanInstallPathWebExtension() { string path = Path.GetFullPath("data/extensions/webextensions-selenium-example"); @@ -37,6 +39,8 @@ public async Task CanInstallPathWebExtension() } [Test] + [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] + [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanInstallArchiveWebExtension() { string path = Path.GetFullPath("data/extensions/webextensions-selenium-example.zip"); @@ -47,6 +51,8 @@ public async Task CanInstallArchiveWebExtension() } [Test] + [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] + [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanInstallBase64WebExtension() { string base64 = Convert.ToBase64String(File.ReadAllBytes("data/extensions/webextensions-selenium-example.zip")); @@ -57,6 +63,8 @@ public async Task CanInstallBase64WebExtension() } [Test] + [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] + [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanUninstallExtension() { string path = Path.GetFullPath("data/extensions/webextensions-selenium-example"); From c0c27d3af9615be0294d5d5e86d24336bbc22f78 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Fri, 20 Jun 2025 17:30:40 +0300 Subject: [PATCH 07/12] Test data in bazel --- common/extensions/BUILD.bazel | 1 + dotnet/test/common/BUILD.bazel | 1 + 2 files changed, 2 insertions(+) diff --git a/common/extensions/BUILD.bazel b/common/extensions/BUILD.bazel index 9095b311e4fb3..71b72cbbdf491 100644 --- a/common/extensions/BUILD.bazel +++ b/common/extensions/BUILD.bazel @@ -7,6 +7,7 @@ filegroup( "**/*", ]), visibility = [ + "//dotnet/test/common:__pkg__", "//java/test/org/openqa/selenium/chrome:__pkg__", "//java/test/org/openqa/selenium/edge:__pkg__", "//java/test/org/openqa/selenium/environment:__pkg__", diff --git a/dotnet/test/common/BUILD.bazel b/dotnet/test/common/BUILD.bazel index 23212fd57def4..7c210e2b8ea6c 100644 --- a/dotnet/test/common/BUILD.bazel +++ b/dotnet/test/common/BUILD.bazel @@ -17,6 +17,7 @@ filegroup( srcs = [], data = [ "appconfig.json", + "//common/extensions", "//common/src/web", "//dotnet/src/webdriver:manager-linux", "//dotnet/src/webdriver:manager-macos", From 393e41489a6fb939c1df6323444dcb2fef456db3 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Fri, 20 Jun 2025 17:37:19 +0300 Subject: [PATCH 08/12] Works on remote? --- dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs index cf68f7d018b06..b904ca0158bfb 100644 --- a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs +++ b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs @@ -27,6 +27,7 @@ namespace OpenQA.Selenium.BiDi.WebExtension; class WebExtensionTest : BiDiTestFixture { [Test] + [Ignore("qwe")] [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanInstallPathWebExtension() @@ -43,7 +44,8 @@ public async Task CanInstallPathWebExtension() [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanInstallArchiveWebExtension() { - string path = Path.GetFullPath("data/extensions/webextensions-selenium-example.zip"); + //string path = Path.GetFullPath("data/extensions/webextensions-selenium-example.zip"); + string path = Bazel.Runfiles.Create().Rlocation("_main/common/extensions/webextensions-selenium-example.zip"); var result = await bidi.WebExtension.InstallAsync(new ExtensionArchivePath(path)); @@ -51,6 +53,7 @@ public async Task CanInstallArchiveWebExtension() } [Test] + [Ignore("qwe")] [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanInstallBase64WebExtension() @@ -63,6 +66,7 @@ public async Task CanInstallBase64WebExtension() } [Test] + [Ignore("qwe")] [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanUninstallExtension() From d040dae7a558e5b4d0d235e8da9cf75f14a8c92e Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Fri, 20 Jun 2025 19:45:35 +0300 Subject: [PATCH 09/12] Support test data in bazel --- .../BiDi/WebExtension/WebExtensionTest.cs | 26 +++++++++++++------ .../Selenium.WebDriver.Common.Tests.csproj | 2 +- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs index b904ca0158bfb..e4632741207f4 100644 --- a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs +++ b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs @@ -27,12 +27,11 @@ namespace OpenQA.Selenium.BiDi.WebExtension; class WebExtensionTest : BiDiTestFixture { [Test] - [Ignore("qwe")] [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanInstallPathWebExtension() { - string path = Path.GetFullPath("data/extensions/webextensions-selenium-example"); + string path = Path.GetFullPath("common/extensions/webextensions-selenium-example"); var result = await bidi.WebExtension.InstallAsync(new ExtensionPath(path)); @@ -44,8 +43,7 @@ public async Task CanInstallPathWebExtension() [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanInstallArchiveWebExtension() { - //string path = Path.GetFullPath("data/extensions/webextensions-selenium-example.zip"); - string path = Bazel.Runfiles.Create().Rlocation("_main/common/extensions/webextensions-selenium-example.zip"); + string path = LocateRelativePath("common/extensions/webextensions-selenium-example.zip"); var result = await bidi.WebExtension.InstallAsync(new ExtensionArchivePath(path)); @@ -53,12 +51,13 @@ public async Task CanInstallArchiveWebExtension() } [Test] - [Ignore("qwe")] [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanInstallBase64WebExtension() { - string base64 = Convert.ToBase64String(File.ReadAllBytes("data/extensions/webextensions-selenium-example.zip")); + var path = LocateRelativePath("common/extensions/webextensions-selenium-example.zip"); + + string base64 = Convert.ToBase64String(File.ReadAllBytes(path)); var result = await bidi.WebExtension.InstallAsync(new ExtensionBase64Encoded(base64)); @@ -66,15 +65,26 @@ public async Task CanInstallBase64WebExtension() } [Test] - [Ignore("qwe")] [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanUninstallExtension() { - string path = Path.GetFullPath("data/extensions/webextensions-selenium-example"); + string path = LocateRelativePath("common/extensions/webextensions-selenium-example"); var result = await bidi.WebExtension.InstallAsync(new ExtensionPath(path)); await result.Extension.UninstallAsync(); } + + private string LocateRelativePath(string path) + { + try + { + return Bazel.Runfiles.Create().Rlocation($"_main/{path}"); + } + catch (FileNotFoundException) + { + return Path.GetFullPath(path); + } + } } diff --git a/dotnet/test/common/Selenium.WebDriver.Common.Tests.csproj b/dotnet/test/common/Selenium.WebDriver.Common.Tests.csproj index dc806fcfc2a1e..9518def5a986b 100644 --- a/dotnet/test/common/Selenium.WebDriver.Common.Tests.csproj +++ b/dotnet/test/common/Selenium.WebDriver.Common.Tests.csproj @@ -28,7 +28,7 @@ Always - data\extensions\%(RecursiveDir)%(Filename)%(Extension) + common\extensions\%(RecursiveDir)%(Filename)%(Extension) PreserveNewest From 0c3ed57b1cdde3735d56aa4b309c7cea4fad0eb4 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Fri, 20 Jun 2025 20:12:02 +0300 Subject: [PATCH 10/12] Enable some tests --- .../common/BiDi/WebExtension/WebExtensionTest.cs | 14 +++++--------- dotnet/test/common/Environment/DriverFactory.cs | 4 ++-- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs index e4632741207f4..56a5fc392f191 100644 --- a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs +++ b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs @@ -27,8 +27,6 @@ namespace OpenQA.Selenium.BiDi.WebExtension; class WebExtensionTest : BiDiTestFixture { [Test] - [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] - [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanInstallPathWebExtension() { string path = Path.GetFullPath("common/extensions/webextensions-selenium-example"); @@ -39,8 +37,8 @@ public async Task CanInstallPathWebExtension() } [Test] - [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] - [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] + [IgnoreBrowser(Selenium.Browser.Chrome, "Archived and Base64 extensions are not supported?")] + [IgnoreBrowser(Selenium.Browser.Edge, "Archived and Base64 extensions are not supported?")] public async Task CanInstallArchiveWebExtension() { string path = LocateRelativePath("common/extensions/webextensions-selenium-example.zip"); @@ -51,8 +49,8 @@ public async Task CanInstallArchiveWebExtension() } [Test] - [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] - [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] + [IgnoreBrowser(Selenium.Browser.Chrome, "Archived and Base64 extensions are not supported?")] + [IgnoreBrowser(Selenium.Browser.Edge, "Archived and Base64 extensions are not supported?")] public async Task CanInstallBase64WebExtension() { var path = LocateRelativePath("common/extensions/webextensions-selenium-example.zip"); @@ -65,8 +63,6 @@ public async Task CanInstallBase64WebExtension() } [Test] - [IgnoreBrowser(Selenium.Browser.Chrome, "Web extensions are not supported yet?")] - [IgnoreBrowser(Selenium.Browser.Edge, "Web extensions are not supported yet?")] public async Task CanUninstallExtension() { string path = LocateRelativePath("common/extensions/webextensions-selenium-example"); @@ -76,7 +72,7 @@ public async Task CanUninstallExtension() await result.Extension.UninstallAsync(); } - private string LocateRelativePath(string path) + private static string LocateRelativePath(string path) { try { diff --git a/dotnet/test/common/Environment/DriverFactory.cs b/dotnet/test/common/Environment/DriverFactory.cs index f58eea2430673..94305a1d9977f 100644 --- a/dotnet/test/common/Environment/DriverFactory.cs +++ b/dotnet/test/common/Environment/DriverFactory.cs @@ -86,7 +86,7 @@ public IWebDriver CreateDriverWithOptions(Type driverType, DriverOptions driverO options = GetDriverOptions(driverType, driverOptions); var chromeOptions = (ChromeOptions)options; - chromeOptions.AddArguments("--no-sandbox", "--disable-dev-shm-usage"); + chromeOptions.AddArguments("--no-sandbox", "--disable-dev-shm-usage", "--remote-debugging-pipe", "--enable-unsafe-extension-debugging"); service = CreateService(); if (!string.IsNullOrEmpty(this.browserBinaryLocation)) @@ -104,7 +104,7 @@ public IWebDriver CreateDriverWithOptions(Type driverType, DriverOptions driverO options = GetDriverOptions(driverType, driverOptions); var edgeOptions = (EdgeOptions)options; - edgeOptions.AddArguments("--no-sandbox", "--disable-dev-shm-usage"); + edgeOptions.AddArguments("--no-sandbox", "--disable-dev-shm-usage", "--remote-debugging-pipe", "--enable-unsafe-extension-debugging"); service = CreateService(); if (!string.IsNullOrEmpty(this.browserBinaryLocation)) From 69fdad9a7683497bda18fa6f12ec7ab31999fce8 Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Fri, 20 Jun 2025 20:15:34 +0300 Subject: [PATCH 11/12] Deeper asserts --- dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs index 56a5fc392f191..7973ea497cd85 100644 --- a/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs +++ b/dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs @@ -34,6 +34,7 @@ public async Task CanInstallPathWebExtension() var result = await bidi.WebExtension.InstallAsync(new ExtensionPath(path)); Assert.That(result, Is.Not.Null); + Assert.That(result.Extension, Is.Not.Null); } [Test] @@ -46,6 +47,7 @@ public async Task CanInstallArchiveWebExtension() var result = await bidi.WebExtension.InstallAsync(new ExtensionArchivePath(path)); Assert.That(result, Is.Not.Null); + Assert.That(result.Extension, Is.Not.Null); } [Test] @@ -60,6 +62,7 @@ public async Task CanInstallBase64WebExtension() var result = await bidi.WebExtension.InstallAsync(new ExtensionBase64Encoded(base64)); Assert.That(result, Is.Not.Null); + Assert.That(result.Extension, Is.Not.Null); } [Test] From 94436221ef3205d09021bde0ed28a872d724904e Mon Sep 17 00:00:00 2001 From: Nikolay Borisenko <22616990+nvborisenko@users.noreply.github.com> Date: Fri, 20 Jun 2025 20:40:47 +0300 Subject: [PATCH 12/12] Sealed types --- .../src/webdriver/BiDi/WebExtension/Extension.cs | 2 +- .../webdriver/BiDi/WebExtension/InstallCommand.cs | 14 +++++++------- .../BiDi/WebExtension/UninstallCommand.cs | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs index ba36dc4f53e13..c19beb1579e70 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/Extension.cs @@ -21,7 +21,7 @@ namespace OpenQA.Selenium.BiDi.WebExtension; -public class Extension +public sealed class Extension { private readonly BiDi _bidi; diff --git a/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs b/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs index 95a6a77250af6..b0f121420656d 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/InstallCommand.cs @@ -22,10 +22,10 @@ namespace OpenQA.Selenium.BiDi.WebExtension; -internal class InstallCommand(InstallCommandParameters @params) +internal sealed class InstallCommand(InstallCommandParameters @params) : Command(@params, "webExtension.install"); -internal record InstallCommandParameters(ExtensionData ExtensionData) : CommandParameters; +internal sealed record InstallCommandParameters(ExtensionData ExtensionData) : CommandParameters; [JsonPolymorphic(TypeDiscriminatorPropertyName = "type")] [JsonDerivedType(typeof(ExtensionArchivePath), "archivePath")] @@ -33,12 +33,12 @@ internal record InstallCommandParameters(ExtensionData ExtensionData) : CommandP [JsonDerivedType(typeof(ExtensionPath), "path")] public abstract record ExtensionData; -public record ExtensionArchivePath(string Path) : ExtensionData; +public sealed record ExtensionArchivePath(string Path) : ExtensionData; -public record ExtensionBase64Encoded(string Value) : ExtensionData; +public sealed record ExtensionBase64Encoded(string Value) : ExtensionData; -public record ExtensionPath(string Path) : ExtensionData; +public sealed record ExtensionPath(string Path) : ExtensionData; -public record InstallOptions : CommandOptions; +public sealed record InstallOptions : CommandOptions; -public record InstallResult(Extension Extension) : EmptyResult; +public sealed record InstallResult(Extension Extension) : EmptyResult; diff --git a/dotnet/src/webdriver/BiDi/WebExtension/UninstallCommand.cs b/dotnet/src/webdriver/BiDi/WebExtension/UninstallCommand.cs index 39b35a05ad1a7..7bede2fa2c384 100644 --- a/dotnet/src/webdriver/BiDi/WebExtension/UninstallCommand.cs +++ b/dotnet/src/webdriver/BiDi/WebExtension/UninstallCommand.cs @@ -21,9 +21,9 @@ namespace OpenQA.Selenium.BiDi.WebExtension; -internal class UninstallCommand(UninstallCommandParameters @params) +internal sealed class UninstallCommand(UninstallCommandParameters @params) : Command(@params, "webExtension.uninstall"); -internal record UninstallCommandParameters(Extension Extension) : CommandParameters; +internal sealed record UninstallCommandParameters(Extension Extension) : CommandParameters; -public record UninstallOptions : CommandOptions; +public sealed record UninstallOptions : CommandOptions;