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;