Skip to content

Commit

Permalink
[dotnet] support installing unsigned Firefox add-ons including from d…
Browse files Browse the repository at this point in the history
…irectory
  • Loading branch information
titusfortner committed Sep 13, 2022
1 parent 106c89a commit 1b20938
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 14 deletions.
51 changes: 38 additions & 13 deletions dotnet/src/webdriver/Firefox/FirefoxDriver.cs
Expand Up @@ -21,6 +21,7 @@
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using OpenQA.Selenium.DevTools;
using OpenQA.Selenium.Remote;

Expand Down Expand Up @@ -256,11 +257,35 @@ public void SetContext(FirefoxCommandContext context)
this.Execute(SetContextCommand, parameters);
}

/// <summary>
/// Installs a Firefox add-on from a directory.
/// </summary>
/// <param name="addOnDirectoryToInstall">Full path of the directory of the add-on to install.</param>
/// <param name="temporary">Whether the add-on is temporary; required for unsigned add-ons.</param>
public string InstallAddOnFromDirectory(string addOnDirectoryToInstall, bool temporary = false)
{
if (string.IsNullOrEmpty(addOnDirectoryToInstall))
{
throw new ArgumentNullException(nameof(addOnDirectoryToInstall), "Add-on file name must not be null or the empty string");
}

if (!Directory.Exists(addOnDirectoryToInstall))
{
throw new ArgumentException("Directory " + addOnDirectoryToInstall + " does not exist", nameof(addOnDirectoryToInstall));
}

string addOnFileToInstall = Path.Combine(Path.GetTempPath(), "addon" + new Random().Next() + ".zip");
ZipFile.CreateFromDirectory(addOnDirectoryToInstall, addOnFileToInstall);

return this.InstallAddOn(addOnFileToInstall, temporary);
}

/// <summary>
/// Installs a Firefox add-on from a file, typically a .xpi file.
/// </summary>
/// <param name="addOnFileToInstall">Full path and file name of the add-on to install.</param>
public void InstallAddOnFromFile(string addOnFileToInstall)
/// <param name="temporary">Whether the add-on is temporary; required for unsigned add-ons.</param>
public string InstallAddOnFromFile(string addOnFileToInstall, bool temporary = false)
{
if (string.IsNullOrEmpty(addOnFileToInstall))
{
Expand All @@ -272,31 +297,31 @@ public void InstallAddOnFromFile(string addOnFileToInstall)
throw new ArgumentException("File " + addOnFileToInstall + " does not exist", nameof(addOnFileToInstall));
}

// Implementation note: There is a version of the install add-on
// command that can be used with a file name directly, by passing
// a "path" property in the parameters object of the command. If
// delegating to the "use the base64-encoded blob" version causes
// issues, we can change this method to use the file name directly
// instead.
byte[] addOnBytes = File.ReadAllBytes(addOnFileToInstall);
string base64AddOn = Convert.ToBase64String(addOnBytes);
this.InstallAddOn(base64AddOn);
string base64EncodedAddOn = Convert.ToBase64String(addOnBytes);

return this.InstallAddOn(base64EncodedAddOn, temporary);
}

/// <summary>
/// Installs a Firefox add-on.
/// </summary>
/// <param name="base64EncodedAddOn">The base64-encoded string representation of the add-on binary.</param>
public void InstallAddOn(string base64EncodedAddOn)
/// <param name="temporary">Whether the add-on is temporary; required for unsigned add-ons.</param>
public string InstallAddOn(string base64EncodedAddOn, bool temporary = false)
{
if (string.IsNullOrEmpty(base64EncodedAddOn))
{
throw new ArgumentNullException(nameof(base64EncodedAddOn), "Base64 encoded add-on must not be null or the empty string");
}

Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters["addon"] = base64EncodedAddOn;
this.Execute(InstallAddOnCommand, parameters);
Dictionary<string, object> parameters = new Dictionary<string, object>
{
["addon"] = base64EncodedAddOn,
["temporary"] = temporary
};
Response response = this.Execute(InstallAddOnCommand, parameters);
return (string)response.Value;
}

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions dotnet/test/common/DriverTestFixture.cs
Expand Up @@ -8,6 +8,7 @@ namespace OpenQA.Selenium
public abstract class DriverTestFixture
{
public string alertsPage = EnvironmentManager.Instance.UrlBuilder.WhereIs("alerts.html");
public string blankPage = EnvironmentManager.Instance.UrlBuilder.WhereIs("blank.html");
public string macbethPage = EnvironmentManager.Instance.UrlBuilder.WhereIs("macbeth.html");
public string macbethTitle = "Macbeth: Entire Play";

Expand Down
104 changes: 103 additions & 1 deletion dotnet/test/firefox/FirefoxDriverTest.cs
Expand Up @@ -39,7 +39,7 @@ public void ShouldWaitUntilBrowserHasClosedProperly()

driver.Url = formsPage;
IWebElement textarea = driver.FindElement(By.Id("withText"));
string expectedText = "I like cheese" + System.Environment.NewLine
string expectedText = "I like cheese" + System.Environment.NewLine
+ System.Environment.NewLine + "It's really nice";
textarea.Clear();
textarea.SendKeys(expectedText);
Expand Down Expand Up @@ -252,6 +252,108 @@ public void ShouldAllowUserToSuccessfullyOverrideTheHomePage()
}
}

[Test]
public void ShouldInstallAndUninstallXpiAddon()
{
FirefoxDriver firefoxDriver = driver as FirefoxDriver;

string extension = GetPath("webextensions-selenium-example.xpi");
string id = firefoxDriver.InstallAddOnFromFile(extension);

driver.Url = blankPage;

IWebElement injected = firefoxDriver.FindElement(By.Id("webextensions-selenium-example"));
Assert.That(injected.Text, Is.EqualTo("Content injected by webextensions-selenium-example"));

firefoxDriver.UninstallAddOn(id);

driver.Navigate().Refresh();
Assert.That(driver.FindElements(By.Id("webextensions-selenium-example")).Count, Is.Zero);
}

[Test]
public void ShouldInstallAndUninstallUnSignedZipAddon()
{
FirefoxDriver firefoxDriver = driver as FirefoxDriver;

string extension = GetPath("webextensions-selenium-example-unsigned.zip");
string id = firefoxDriver.InstallAddOnFromFile(extension, true);

driver.Url = blankPage;

IWebElement injected = firefoxDriver.FindElement(By.Id("webextensions-selenium-example"));
Assert.That(injected.Text, Is.EqualTo("Content injected by webextensions-selenium-example"));

firefoxDriver.UninstallAddOn(id);

driver.Navigate().Refresh();
Assert.That(driver.FindElements(By.Id("webextensions-selenium-example")).Count, Is.Zero);
}

[Test]
public void ShouldInstallAndUninstallSignedZipAddon()
{
FirefoxDriver firefoxDriver = driver as FirefoxDriver;

string extension = GetPath("webextensions-selenium-example.zip");
string id = firefoxDriver.InstallAddOnFromFile(extension);

driver.Url = blankPage;

IWebElement injected = firefoxDriver.FindElement(By.Id("webextensions-selenium-example"));
Assert.That(injected.Text, Is.EqualTo("Content injected by webextensions-selenium-example"));

firefoxDriver.UninstallAddOn(id);

driver.Navigate().Refresh();
Assert.That(driver.FindElements(By.Id("webextensions-selenium-example")).Count, Is.Zero);
}

[Test]
public void ShouldInstallAndUninstallSignedDirAddon()
{
FirefoxDriver firefoxDriver = driver as FirefoxDriver;

string extension = GetPath("webextensions-selenium-example-signed");
string id = firefoxDriver.InstallAddOnFromDirectory(extension);

driver.Url = blankPage;

IWebElement injected = firefoxDriver.FindElement(By.Id("webextensions-selenium-example"));
Assert.That(injected.Text, Is.EqualTo("Content injected by webextensions-selenium-example"));

firefoxDriver.UninstallAddOn(id);

driver.Navigate().Refresh();
Assert.That(driver.FindElements(By.Id("webextensions-selenium-example")).Count, Is.Zero);
}

[Test]
public void ShouldInstallAndUninstallUnSignedDirAddon()
{
FirefoxDriver firefoxDriver = driver as FirefoxDriver;

string extension = GetPath("webextensions-selenium-example");
string id = firefoxDriver.InstallAddOnFromDirectory(extension, true);

driver.Url = blankPage;

IWebElement injected = firefoxDriver.FindElement(By.Id("webextensions-selenium-example"));
Assert.That(injected.Text, Is.EqualTo("Content injected by webextensions-selenium-example"));

firefoxDriver.UninstallAddOn(id);

driver.Navigate().Refresh();
Assert.That(driver.FindElements(By.Id("webextensions-selenium-example")).Count, Is.Zero);
}

private string GetPath(string name)
{
string sCurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;
string sFile = Path.Combine(sCurrentDirectory, "../../../../common/extensions/" + name);
return Path.GetFullPath(sFile);
}

private static bool PlatformHasNativeEvents()
{
return true;
Expand Down

0 comments on commit 1b20938

Please sign in to comment.