From 251cd3805534ca239c65f91f3ea532a7b5380b3a Mon Sep 17 00:00:00 2001 From: Long Ly Date: Fri, 24 May 2019 11:22:32 -0700 Subject: [PATCH] Add support for the new MicrosoftEdge. Extracting Chrome into a separate Chromium package since the new Edge is also Chromium-based. Add the ability for EdgeDriver to launch the new MicrosoftEdge using MSEdgeDriver without breaking any existing Edge tests. Signed-off-by: Jim Evans --- dotnet/src/webdriver/Chrome/ChromeDriver.cs | 122 +--- .../webdriver/Chrome/ChromeDriverService.cs | 178 +---- dotnet/src/webdriver/Chrome/ChromeOptions.cs | 651 +---------------- .../src/webdriver/Chrome/ChromeWebElement.cs | 4 +- .../src/webdriver/Chromium/ChromiumDriver.cs | 154 ++++ .../Chromium/ChromiumDriverService.cs | 213 ++++++ .../ChromiumMobileEmulationDeviceSettings.cs} | 16 +- .../ChromiumNetworkConditions.cs} | 10 +- .../src/webdriver/Chromium/ChromiumOptions.cs | 686 ++++++++++++++++++ .../ChromiumPerformanceLoggingPreferences.cs} | 18 +- .../webdriver/Chromium/ChromiumWebElement.cs | 38 + dotnet/src/webdriver/DriverOptions.cs | 12 + dotnet/src/webdriver/Edge/EdgeDriver.cs | 18 +- .../src/webdriver/Edge/EdgeDriverService.cs | 134 +++- dotnet/src/webdriver/Edge/EdgeOptions.cs | 135 +++- dotnet/src/webdriver/Edge/EdgeWebElement.cs | 6 +- dotnet/test/common/AlertsTest.cs | 9 + dotnet/test/common/AvailableLogsTest.cs | 1 + dotnet/test/common/Browser.cs | 1 + dotnet/test/common/ClearTest.cs | 1 + dotnet/test/common/ClickScrollingTest.cs | 1 + dotnet/test/common/ClickTest.cs | 1 + dotnet/test/common/ContentEditableTest.cs | 3 + .../test/common/CookieImplementationTest.cs | 1 + dotnet/test/common/CorrectEventFiringTest.cs | 2 + .../IgnoreBrowserAttribute.cs | 6 + dotnet/test/common/ElementFindingTest.cs | 2 + .../test/common/Environment/DriverFactory.cs | 2 + .../common/ExecutingAsyncJavascriptTest.cs | 2 + dotnet/test/common/ExecutingJavascriptTest.cs | 3 + dotnet/test/common/FrameSwitchingTest.cs | 1 + .../test/common/HTML5/LocationContextTest.cs | 1 + dotnet/test/common/I18Test.cs | 1 + .../Interactions/BasicMouseInterfaceTest.cs | 2 + dotnet/test/common/MiscTest.cs | 1 + dotnet/test/common/PageLoadingTest.cs | 4 + dotnet/test/common/SvgDocumentTest.cs | 1 + dotnet/test/common/TakesScreenshotTest.cs | 5 + dotnet/test/common/TextPagesTest.cs | 1 + dotnet/test/common/TypingTest.cs | 1 + dotnet/test/common/UploadTest.cs | 1 + dotnet/test/common/WindowSwitchingTest.cs | 1 + dotnet/test/common/WindowTest.cs | 1 + dotnet/test/common/appconfig.json | 7 + dotnet/test/edge/ChromiumEdgeDriver.cs | 35 + 45 files changed, 1465 insertions(+), 1028 deletions(-) create mode 100644 dotnet/src/webdriver/Chromium/ChromiumDriver.cs create mode 100644 dotnet/src/webdriver/Chromium/ChromiumDriverService.cs rename dotnet/src/webdriver/{Chrome/ChromeMobileEmulationDeviceSettings.cs => Chromium/ChromiumMobileEmulationDeviceSettings.cs} (84%) rename dotnet/src/webdriver/{Chrome/ChromeNetworkConditions.cs => Chromium/ChromiumNetworkConditions.cs} (93%) create mode 100644 dotnet/src/webdriver/Chromium/ChromiumOptions.cs rename dotnet/src/webdriver/{Chrome/ChromePerformanceLoggingPreferences.cs => Chromium/ChromiumPerformanceLoggingPreferences.cs} (85%) create mode 100644 dotnet/src/webdriver/Chromium/ChromiumWebElement.cs create mode 100644 dotnet/test/edge/ChromiumEdgeDriver.cs diff --git a/dotnet/src/webdriver/Chrome/ChromeDriver.cs b/dotnet/src/webdriver/Chrome/ChromeDriver.cs index 41767a7ac88f6..7d1d6ba0ffae1 100644 --- a/dotnet/src/webdriver/Chrome/ChromeDriver.cs +++ b/dotnet/src/webdriver/Chrome/ChromeDriver.cs @@ -18,6 +18,7 @@ using System; using OpenQA.Selenium.Remote; +using OpenQA.Selenium.Chromium; using System.Collections.Generic; namespace OpenQA.Selenium.Chrome @@ -55,24 +56,14 @@ namespace OpenQA.Selenium.Chrome /// } /// /// - public class ChromeDriver : RemoteWebDriver + public class ChromeDriver : ChromiumDriver { + /// - /// Accept untrusted SSL Certificates + /// Initializes a new instance of the class. /// - public static readonly bool AcceptUntrustedCertificates = true; - - private const string GetNetworkConditionsCommand = "getNetworkConditions"; - private const string SetNetworkConditionsCommand = "setNetworkConditions"; - private const string DeleteNetworkConditionsCommand = "deleteNetworkConditions"; - private const string SendChromeCommand = "sendChromeCommand"; - private const string SendChromeCommandWithResult = "sendChromeCommandWithResult"; - - /// - /// Initializes a new instance of the class. - /// - public ChromeDriver() - : this(new ChromeOptions()) + public ChromeDriver() + : this(new ChromeOptions()) { } @@ -145,108 +136,9 @@ public ChromeDriver(ChromeDriverService service, ChromeOptions options) /// The to be used with the Chrome driver. /// The maximum amount of time to wait for each command. public ChromeDriver(ChromeDriverService service, ChromeOptions options, TimeSpan commandTimeout) - : base(new DriverServiceCommandExecutor(service, commandTimeout), ConvertOptionsToCapabilities(options)) - { - // Add the custom commands unique to Chrome - this.AddCustomChromeCommand(GetNetworkConditionsCommand, CommandInfo.GetCommand, "/session/{sessionId}/chromium/network_conditions"); - this.AddCustomChromeCommand(SetNetworkConditionsCommand, CommandInfo.PostCommand, "/session/{sessionId}/chromium/network_conditions"); - this.AddCustomChromeCommand(DeleteNetworkConditionsCommand, CommandInfo.DeleteCommand, "/session/{sessionId}/chromium/network_conditions"); - this.AddCustomChromeCommand(SendChromeCommand, CommandInfo.PostCommand, "/session/{sessionId}/chromium/send_command"); - this.AddCustomChromeCommand(SendChromeCommandWithResult, CommandInfo.PostCommand, "/session/{sessionId}/chromium/send_command_and_get_result"); - } - - /// - /// Gets or sets the responsible for detecting - /// sequences of keystrokes representing file paths and names. - /// - /// The Chrome driver does not allow a file detector to be set, - /// as the server component of the Chrome driver (ChromeDriver.exe) only - /// allows uploads from the local computer environment. Attempting to set - /// this property has no effect, but does not throw an exception. If you - /// are attempting to run the Chrome driver remotely, use - /// in conjunction with a standalone WebDriver server. - public override IFileDetector FileDetector + : base(service, options, commandTimeout) { - get { return base.FileDetector; } - set { } } - /// - /// Gets or sets the network condition emulation for Chrome. - /// - public ChromeNetworkConditions NetworkConditions - { - get - { - Response response = this.Execute(GetNetworkConditionsCommand, null); - return ChromeNetworkConditions.FromDictionary(response.Value as Dictionary); - } - - set - { - if (value == null) - { - throw new ArgumentNullException("value", "value must not be null"); - } - - Dictionary parameters = new Dictionary(); - parameters["network_conditions"] = value.ToDictionary(); - this.Execute(SetNetworkConditionsCommand, parameters); - } - } - - /// - /// Executes a custom Chrome command. - /// - /// Name of the command to execute. - /// Parameters of the command to execute. - public void ExecuteChromeCommand(string commandName, Dictionary commandParameters) - { - if (commandName == null) - { - throw new ArgumentNullException("commandName", "commandName must not be null"); - } - - Dictionary parameters = new Dictionary(); - parameters["cmd"] = commandName; - parameters["params"] = commandParameters; - this.Execute(SendChromeCommand, parameters); - } - - /// - /// Executes a custom Chrome command that returns a result. - /// - /// Name of the command to execute. - /// Parameters of the command to execute. - /// The JSON return value of the Chrome command, converted to a .NET object. - public object ExecuteChromeCommandWithResult(string commandName, Dictionary commandParameters) - { - if (commandName == null) - { - throw new ArgumentNullException("commandName", "commandName must not be null"); - } - - Dictionary parameters = new Dictionary(); - parameters["cmd"] = commandName; - parameters["params"] = commandParameters; - Response response = this.Execute(SendChromeCommandWithResult, parameters); - return response.Value; - } - - private static ICapabilities ConvertOptionsToCapabilities(ChromeOptions options) - { - if (options == null) - { - throw new ArgumentNullException("options", "options must not be null"); - } - - return options.ToCapabilities(); - } - - private void AddCustomChromeCommand(string commandName, string method, string resourcePath) - { - CommandInfo commandInfoToAdd = new CommandInfo(method, resourcePath); - this.CommandExecutor.CommandInfoRepository.TryAddCommand(commandName, commandInfoToAdd); - } } } diff --git a/dotnet/src/webdriver/Chrome/ChromeDriverService.cs b/dotnet/src/webdriver/Chrome/ChromeDriverService.cs index 7a9fc8275f390..1210c640ddf4f 100644 --- a/dotnet/src/webdriver/Chrome/ChromeDriverService.cs +++ b/dotnet/src/webdriver/Chrome/ChromeDriverService.cs @@ -20,24 +20,19 @@ using System.Globalization; using System.Text; using OpenQA.Selenium.Internal; +using OpenQA.Selenium.Chromium; namespace OpenQA.Selenium.Chrome { /// /// Exposes the service provided by the native ChromeDriver executable. /// - public sealed class ChromeDriverService : DriverService + public sealed class ChromeDriverService : ChromiumDriverService { private const string DefaultChromeDriverServiceExecutableName = "chromedriver"; private static readonly Uri ChromeDriverDownloadUrl = new Uri("http://chromedriver.storage.googleapis.com/index.html"); - private string logPath = string.Empty; - private string urlPathPrefix = string.Empty; - private string portServerAddress = string.Empty; - private string whitelistedIpAddresses = string.Empty; - private int adbPort = -1; - private bool enableVerboseLogging; - private bool enableAppendLog; + /// /// Initializes a new instance of the class. @@ -46,127 +41,8 @@ public sealed class ChromeDriverService : DriverService /// The file name of the ChromeDriver executable. /// The port on which the ChromeDriver executable should listen. private ChromeDriverService(string executablePath, string executableFileName, int port) - : base(executablePath, port, executableFileName, ChromeDriverDownloadUrl) - { - } - - /// - /// Gets or sets the location of the log file written to by the ChromeDriver executable. - /// - public string LogPath - { - get { return this.logPath; } - set { this.logPath = value; } - } - - /// - /// Gets or sets the base URL path prefix for commands (e.g., "wd/url"). - /// - public string UrlPathPrefix - { - get { return this.urlPathPrefix; } - set { this.urlPathPrefix = value; } - } - - /// - /// Gets or sets the address of a server to contact for reserving a port. - /// - public string PortServerAddress - { - get { return this.portServerAddress; } - set { this.portServerAddress = value; } - } - - /// - /// Gets or sets the port on which the Android Debug Bridge is listening for commands. - /// - public int AndroidDebugBridgePort + : base(executablePath, executableFileName, port, ChromeDriverDownloadUrl) { - get { return this.adbPort; } - set { this.adbPort = value; } - } - - /// - /// Gets or sets a value indicating whether to enable verbose logging for the ChromeDriver executable. - /// Defaults to . - /// - public bool EnableVerboseLogging - { - get { return this.enableVerboseLogging; } - set { this.enableVerboseLogging = value; } - } - - /// - /// Gets or sets a value indicating whether to enable appending to an existing ChromeDriver log file. - /// Defaults to . - /// - public bool EnableAppendLog - { - get { return this.enableAppendLog; } - set { this.enableAppendLog = value; } - } - - /// - /// Gets or sets the comma-delimited list of IP addresses that are approved to - /// connect to this instance of the Chrome driver. Defaults to an empty string, - /// which means only the local loopback address can connect. - /// - public string WhitelistedIPAddresses - { - get { return this.whitelistedIpAddresses; } - set { this.whitelistedIpAddresses = value; } - } - - /// - /// Gets the command-line arguments for the driver service. - /// - protected override string CommandLineArguments - { - get - { - StringBuilder argsBuilder = new StringBuilder(base.CommandLineArguments); - if (this.adbPort > 0) - { - argsBuilder.AppendFormat(CultureInfo.InvariantCulture, " --adb-port={0}", this.adbPort); - } - - if (this.SuppressInitialDiagnosticInformation) - { - argsBuilder.Append(" --silent"); - } - - if (this.enableVerboseLogging) - { - argsBuilder.Append(" --verbose"); - } - - if (this.enableAppendLog) - { - argsBuilder.Append(" --append-log"); - } - - if (!string.IsNullOrEmpty(this.logPath)) - { - argsBuilder.AppendFormat(CultureInfo.InvariantCulture, " --log-path=\"{0}\"", this.logPath); - } - - if (!string.IsNullOrEmpty(this.urlPathPrefix)) - { - argsBuilder.AppendFormat(CultureInfo.InvariantCulture, " --url-base={0}", this.urlPathPrefix); - } - - if (!string.IsNullOrEmpty(this.portServerAddress)) - { - argsBuilder.AppendFormat(CultureInfo.InvariantCulture, " --port-server={0}", this.portServerAddress); - } - - if (!string.IsNullOrEmpty(this.whitelistedIpAddresses)) - { - argsBuilder.Append(string.Format(CultureInfo.InvariantCulture, " -whitelisted-ips={0}", this.whitelistedIpAddresses)); - } - - return argsBuilder.ToString(); - } } /// @@ -175,7 +51,8 @@ protected override string CommandLineArguments /// A ChromeDriverService that implements default settings. public static ChromeDriverService CreateDefaultService() { - string serviceDirectory = DriverService.FindDriverServiceExecutable(ChromeDriverServiceFileName(), ChromeDriverDownloadUrl); + string serviceDirectory = DriverService.FindDriverServiceExecutable(ChromiumDriverServiceFileName(DefaultChromeDriverServiceExecutableName), + ChromeDriverDownloadUrl); return CreateDefaultService(serviceDirectory); } @@ -186,7 +63,7 @@ public static ChromeDriverService CreateDefaultService() /// A ChromeDriverService using a random port. public static ChromeDriverService CreateDefaultService(string driverPath) { - return CreateDefaultService(driverPath, ChromeDriverServiceFileName()); + return CreateDefaultService(driverPath, ChromiumDriverServiceFileName(DefaultChromeDriverServiceExecutableName)); } /// @@ -200,46 +77,5 @@ public static ChromeDriverService CreateDefaultService(string driverPath, string return new ChromeDriverService(driverPath, driverExecutableFileName, PortUtilities.FindFreePort()); } - /// - /// Returns the Chrome driver filename for the currently running platform - /// - /// The file name of the Chrome driver service executable. - private static string ChromeDriverServiceFileName() - { - string fileName = DefaultChromeDriverServiceExecutableName; - - // Unfortunately, detecting the currently running platform isn't as - // straightforward as you might hope. - // See: http://mono.wikia.com/wiki/Detecting_the_execution_platform - // and https://msdn.microsoft.com/en-us/library/3a8hyw88(v=vs.110).aspx - const int PlatformMonoUnixValue = 128; - - switch (Environment.OSVersion.Platform) - { - case PlatformID.Win32NT: - case PlatformID.Win32S: - case PlatformID.Win32Windows: - case PlatformID.WinCE: - fileName += ".exe"; - break; - - case PlatformID.MacOSX: - case PlatformID.Unix: - break; - - // Don't handle the Xbox case. Let default handle it. - // case PlatformID.Xbox: - // break; - default: - if ((int)Environment.OSVersion.Platform == PlatformMonoUnixValue) - { - break; - } - - throw new WebDriverException("Unsupported platform: " + Environment.OSVersion.Platform); - } - - return fileName; - } } } diff --git a/dotnet/src/webdriver/Chrome/ChromeOptions.cs b/dotnet/src/webdriver/Chrome/ChromeOptions.cs index 3a13b9ae71827..252ced40a7766 100644 --- a/dotnet/src/webdriver/Chrome/ChromeOptions.cs +++ b/dotnet/src/webdriver/Chrome/ChromeOptions.cs @@ -21,7 +21,7 @@ using System.Collections.ObjectModel; using System.Globalization; using System.IO; -using OpenQA.Selenium.Remote; +using OpenQA.Selenium.Chromium; namespace OpenQA.Selenium.Chrome { @@ -50,663 +50,18 @@ namespace OpenQA.Selenium.Chrome /// RemoteWebDriver driver = new RemoteWebDriver(new Uri("http://localhost:4444/wd/hub"), options.ToCapabilities()); /// /// - public class ChromeOptions : DriverOptions + public class ChromeOptions : ChromiumOptions { /// /// Gets the name of the capability used to store Chrome options in /// an object. /// public static readonly string Capability = "goog:chromeOptions"; - - // TODO: Remove this if block when chromedriver bug 2371 is fixed - // (https://bugs.chromium.org/p/chromedriver/issues/detail?id=2371) - internal static readonly string ForceAlwaysMatchCapabilityName = "se:forceAlwaysMatch"; - private const string BrowserNameValue = "chrome"; - private const string ArgumentsChromeOption = "args"; - private const string BinaryChromeOption = "binary"; - private const string ExtensionsChromeOption = "extensions"; - private const string LocalStateChromeOption = "localState"; - private const string PreferencesChromeOption = "prefs"; - private const string DetachChromeOption = "detach"; - private const string DebuggerAddressChromeOption = "debuggerAddress"; - private const string ExcludeSwitchesChromeOption = "excludeSwitches"; - private const string MinidumpPathChromeOption = "minidumpPath"; - private const string MobileEmulationChromeOption = "mobileEmulation"; - private const string PerformanceLoggingPreferencesChromeOption = "perfLoggingPrefs"; - private const string WindowTypesChromeOption = "windowTypes"; - private const string UseSpecCompliantProtocolOption = "w3c"; - - private bool leaveBrowserRunning; - private bool useSpecCompliantProtocol = true; - private string binaryLocation; - private string debuggerAddress; - private string minidumpPath; - private List arguments = new List(); - private List extensionFiles = new List(); - private List encodedExtensions = new List(); - private List excludedSwitches = new List(); - private List windowTypes = new List(); - private Dictionary additionalChromeOptions = new Dictionary(); - private Dictionary userProfilePreferences; - private Dictionary localStatePreferences; - - private string mobileEmulationDeviceName; - private ChromeMobileEmulationDeviceSettings mobileEmulationDeviceSettings; - private ChromePerformanceLoggingPreferences perfLoggingPreferences; - - /// - /// Initializes a new instance of the class. - /// - public ChromeOptions() : base() - { - this.BrowserName = BrowserNameValue; - this.AddKnownCapabilityName(ChromeOptions.Capability, "current ChromeOptions class instance"); - this.AddKnownCapabilityName(CapabilityType.LoggingPreferences, "SetLoggingPreference method"); - this.AddKnownCapabilityName(ChromeOptions.ArgumentsChromeOption, "AddArguments method"); - this.AddKnownCapabilityName(ChromeOptions.BinaryChromeOption, "BinaryLocation property"); - this.AddKnownCapabilityName(ChromeOptions.ExtensionsChromeOption, "AddExtensions method"); - this.AddKnownCapabilityName(ChromeOptions.LocalStateChromeOption, "AddLocalStatePreference method"); - this.AddKnownCapabilityName(ChromeOptions.PreferencesChromeOption, "AddUserProfilePreference method"); - this.AddKnownCapabilityName(ChromeOptions.DetachChromeOption, "LeaveBrowserRunning property"); - this.AddKnownCapabilityName(ChromeOptions.DebuggerAddressChromeOption, "DebuggerAddress property"); - this.AddKnownCapabilityName(ChromeOptions.ExcludeSwitchesChromeOption, "AddExcludedArgument property"); - this.AddKnownCapabilityName(ChromeOptions.MinidumpPathChromeOption, "MinidumpPath property"); - this.AddKnownCapabilityName(ChromeOptions.MobileEmulationChromeOption, "EnableMobileEmulation method"); - this.AddKnownCapabilityName(ChromeOptions.PerformanceLoggingPreferencesChromeOption, "PerformanceLoggingPreferences property"); - this.AddKnownCapabilityName(ChromeOptions.WindowTypesChromeOption, "AddWindowTypes method"); - this.AddKnownCapabilityName(ChromeOptions.UseSpecCompliantProtocolOption, "UseSpecCompliantProtocol property"); - this.AddKnownCapabilityName(ChromeOptions.ForceAlwaysMatchCapabilityName, ""); - } - - /// - /// Gets or sets the location of the Chrome browser's binary executable file. - /// - public string BinaryLocation + public ChromeOptions() : base(BrowserNameValue, Capability) { - get { return this.binaryLocation; } - set { this.binaryLocation = value; } } - /// - /// Gets or sets a value indicating whether Chrome should be left running after the - /// ChromeDriver instance is exited. Defaults to . - /// - public bool LeaveBrowserRunning - { - get { return this.leaveBrowserRunning; } - set { this.leaveBrowserRunning = value; } - } - - /// - /// Gets the list of arguments appended to the Chrome command line as a string array. - /// - public ReadOnlyCollection Arguments - { - get { return this.arguments.AsReadOnly(); } - } - - /// - /// Gets the list of extensions to be installed as an array of base64-encoded strings. - /// - public ReadOnlyCollection Extensions - { - get - { - List allExtensions = new List(this.encodedExtensions); - foreach (string extensionFile in this.extensionFiles) - { - byte[] extensionByteArray = File.ReadAllBytes(extensionFile); - string encodedExtension = Convert.ToBase64String(extensionByteArray); - allExtensions.Add(encodedExtension); - } - - return allExtensions.AsReadOnly(); - } - } - - /// - /// Gets or sets the address of a Chrome debugger server to connect to. - /// Should be of the form "{hostname|IP address}:port". - /// - public string DebuggerAddress - { - get { return this.debuggerAddress; } - set { this.debuggerAddress = value; } - } - - /// - /// Gets or sets the directory in which to store minidump files. - /// - public string MinidumpPath - { - get { return this.minidumpPath; } - set { this.minidumpPath = value; } - } - - /// - /// Gets or sets the performance logging preferences for the driver. - /// - public ChromePerformanceLoggingPreferences PerformanceLoggingPreferences - { - get { return this.perfLoggingPreferences; } - set { this.perfLoggingPreferences = value; } - } - - /// - /// Gets or sets a value indicating whether the instance - /// should use the legacy OSS protocol dialect or a dialect compliant with the W3C - /// WebDriver Specification. - /// - public bool UseSpecCompliantProtocol - { - get { return this.useSpecCompliantProtocol; } - set { this.useSpecCompliantProtocol = value; } - } - - /// - /// Adds a single argument to the list of arguments to be appended to the Chrome.exe command line. - /// - /// The argument to add. - public void AddArgument(string argument) - { - if (string.IsNullOrEmpty(argument)) - { - throw new ArgumentException("argument must not be null or empty", "argument"); - } - - this.AddArguments(argument); - } - - /// - /// Adds arguments to be appended to the Chrome.exe command line. - /// - /// An array of arguments to add. - public void AddArguments(params string[] argumentsToAdd) - { - this.AddArguments(new List(argumentsToAdd)); - } - - /// - /// Adds arguments to be appended to the Chrome.exe command line. - /// - /// An object of arguments to add. - public void AddArguments(IEnumerable argumentsToAdd) - { - if (argumentsToAdd == null) - { - throw new ArgumentNullException("argumentsToAdd", "argumentsToAdd must not be null"); - } - - this.arguments.AddRange(argumentsToAdd); - } - - /// - /// Adds a single argument to be excluded from the list of arguments passed by default - /// to the Chrome.exe command line by chromedriver.exe. - /// - /// The argument to exclude. - public void AddExcludedArgument(string argument) - { - if (string.IsNullOrEmpty(argument)) - { - throw new ArgumentException("argument must not be null or empty", "argument"); - } - - this.AddExcludedArguments(argument); - } - - /// - /// Adds arguments to be excluded from the list of arguments passed by default - /// to the Chrome.exe command line by chromedriver.exe. - /// - /// An array of arguments to exclude. - public void AddExcludedArguments(params string[] argumentsToExclude) - { - this.AddExcludedArguments(new List(argumentsToExclude)); - } - - /// - /// Adds arguments to be excluded from the list of arguments passed by default - /// to the Chrome.exe command line by chromedriver.exe. - /// - /// An object of arguments to exclude. - public void AddExcludedArguments(IEnumerable argumentsToExclude) - { - if (argumentsToExclude == null) - { - throw new ArgumentNullException("argumentsToExclude", "argumentsToExclude must not be null"); - } - - this.excludedSwitches.AddRange(argumentsToExclude); - } - - /// - /// Adds a path to a packed Chrome extension (.crx file) to the list of extensions - /// to be installed in the instance of Chrome. - /// - /// The full path to the extension to add. - public void AddExtension(string pathToExtension) - { - if (string.IsNullOrEmpty(pathToExtension)) - { - throw new ArgumentException("pathToExtension must not be null or empty", "pathToExtension"); - } - - this.AddExtensions(pathToExtension); - } - - /// - /// Adds a list of paths to packed Chrome extensions (.crx files) to be installed - /// in the instance of Chrome. - /// - /// An array of full paths to the extensions to add. - public void AddExtensions(params string[] extensions) - { - this.AddExtensions(new List(extensions)); - } - - /// - /// Adds a list of paths to packed Chrome extensions (.crx files) to be installed - /// in the instance of Chrome. - /// - /// An of full paths to the extensions to add. - public void AddExtensions(IEnumerable extensions) - { - if (extensions == null) - { - throw new ArgumentNullException("extensions", "extensions must not be null"); - } - - foreach (string extension in extensions) - { - if (!File.Exists(extension)) - { - throw new FileNotFoundException("No extension found at the specified path", extension); - } - - this.extensionFiles.Add(extension); - } - } - - /// - /// Adds a base64-encoded string representing a Chrome extension to the list of extensions - /// to be installed in the instance of Chrome. - /// - /// A base64-encoded string representing the extension to add. - public void AddEncodedExtension(string extension) - { - if (string.IsNullOrEmpty(extension)) - { - throw new ArgumentException("extension must not be null or empty", "extension"); - } - - this.AddEncodedExtensions(extension); - } - - /// - /// Adds a list of base64-encoded strings representing Chrome extensions to the list of extensions - /// to be installed in the instance of Chrome. - /// - /// An array of base64-encoded strings representing the extensions to add. - public void AddEncodedExtensions(params string[] extensions) - { - this.AddEncodedExtensions(new List(extensions)); - } - - /// - /// Adds a list of base64-encoded strings representing Chrome extensions to be installed - /// in the instance of Chrome. - /// - /// An of base64-encoded strings - /// representing the extensions to add. - public void AddEncodedExtensions(IEnumerable extensions) - { - if (extensions == null) - { - throw new ArgumentNullException("extensions", "extensions must not be null"); - } - - foreach (string extension in extensions) - { - // Run the extension through the base64 converter to test that the - // string is not malformed. - try - { - Convert.FromBase64String(extension); - } - catch (FormatException ex) - { - throw new WebDriverException("Could not properly decode the base64 string", ex); - } - - this.encodedExtensions.Add(extension); - } - } - - /// - /// Adds a preference for the user-specific profile or "user data directory." - /// If the specified preference already exists, it will be overwritten. - /// - /// The name of the preference to set. - /// The value of the preference to set. - public void AddUserProfilePreference(string preferenceName, object preferenceValue) - { - if (this.userProfilePreferences == null) - { - this.userProfilePreferences = new Dictionary(); - } - - this.userProfilePreferences[preferenceName] = preferenceValue; - } - - /// - /// Adds a preference for the local state file in the user's data directory for Chrome. - /// If the specified preference already exists, it will be overwritten. - /// - /// The name of the preference to set. - /// The value of the preference to set. - public void AddLocalStatePreference(string preferenceName, object preferenceValue) - { - if (this.localStatePreferences == null) - { - this.localStatePreferences = new Dictionary(); - } - - this.localStatePreferences[preferenceName] = preferenceValue; - } - - /// - /// Allows the Chrome browser to emulate a mobile device. - /// - /// The name of the device to emulate. The device name must be a - /// valid device name from the Chrome DevTools Emulation panel. - /// Specifying an invalid device name will not throw an exeption, but - /// will generate an error in Chrome when the driver starts. To unset mobile - /// emulation, call this method with as the argument. - public void EnableMobileEmulation(string deviceName) - { - this.mobileEmulationDeviceSettings = null; - this.mobileEmulationDeviceName = deviceName; - } - - /// - /// Allows the Chrome browser to emulate a mobile device. - /// - /// The - /// object containing the settings of the device to emulate. - /// Thrown if the device settings option does - /// not have a user agent string set. - /// Specifying an invalid device name will not throw an exeption, but - /// will generate an error in Chrome when the driver starts. To unset mobile - /// emulation, call this method with as the argument. - public void EnableMobileEmulation(ChromeMobileEmulationDeviceSettings deviceSettings) - { - this.mobileEmulationDeviceName = null; - if (deviceSettings != null && string.IsNullOrEmpty(deviceSettings.UserAgent)) - { - throw new ArgumentException("Device settings must include a user agent string.", "deviceSettings"); - } - - this.mobileEmulationDeviceSettings = deviceSettings; - } - - /// - /// Adds a type of window that will be listed in the list of window handles - /// returned by the Chrome driver. - /// - /// The name of the window type to add. - /// This method can be used to allow the driver to access {webview} - /// elements by adding "webview" as a window type. - public void AddWindowType(string windowType) - { - if (string.IsNullOrEmpty(windowType)) - { - throw new ArgumentException("windowType must not be null or empty", "windowType"); - } - - this.AddWindowTypes(windowType); - } - - /// - /// Adds a list of window types that will be listed in the list of window handles - /// returned by the Chrome driver. - /// - /// An array of window types to add. - public void AddWindowTypes(params string[] windowTypesToAdd) - { - this.AddWindowTypes(new List(windowTypesToAdd)); - } - - /// - /// Adds a list of window types that will be listed in the list of window handles - /// returned by the Chrome driver. - /// - /// An of window types to add. - public void AddWindowTypes(IEnumerable windowTypesToAdd) - { - if (windowTypesToAdd == null) - { - throw new ArgumentNullException("windowTypesToAdd", "windowTypesToAdd must not be null"); - } - - this.windowTypes.AddRange(windowTypesToAdd); - } - - /// - /// Provides a means to add additional capabilities not yet added as type safe options - /// for the Chrome driver. - /// - /// The name of the capability to add. - /// The value of the capability to add. - /// - /// thrown when attempting to add a capability for which there is already a type safe option, or - /// when is or the empty string. - /// - /// Calling - /// where has already been added will overwrite the - /// existing value with the new value in . - /// Calling this method adds capabilities to the Chrome-specific options object passed to - /// chromedriver.exe (property name 'goog:chromeOptions'). - public void AddAdditionalChromeOption(string optionName, object optionValue) - { - this.ValidateCapabilityName(optionName); - this.additionalChromeOptions[optionName] = optionValue; - } - - /// - /// Provides a means to add additional capabilities not yet added as type safe options - /// for the Chrome driver. - /// - /// The name of the capability to add. - /// The value of the capability to add. - /// - /// thrown when attempting to add a capability for which there is already a type safe option, or - /// when is or the empty string. - /// - /// Calling - /// where has already been added will overwrite the - /// existing value with the new value in . - /// Also, by default, calling this method adds capabilities to the options object passed to - /// chromedriver.exe. - [Obsolete("Use the temporary AddAdditionalOption method or the AddAdditionalChromeOption method for adding additional options")] - public override void AddAdditionalCapability(string capabilityName, object capabilityValue) - { - // Add the capability to the chromeOptions object by default. This is to handle - // the 80% case where the chromedriver team adds a new option in chromedriver.exe - // and the bindings have not yet had a type safe option added. - this.AddAdditionalCapability(capabilityName, capabilityValue, false); - } - - /// - /// Provides a means to add additional capabilities not yet added as type safe options - /// for the Chrome driver. - /// - /// The name of the capability to add. - /// The value of the capability to add. - /// Indicates whether the capability is to be set as a global - /// capability for the driver instead of a Chrome-specific option. - /// - /// thrown when attempting to add a capability for which there is already a type safe option, or - /// when is or the empty string. - /// - /// Calling - /// where has already been added will overwrite the - /// existing value with the new value in - [Obsolete("Use the temporary AddAdditionalOption method or the AddAdditionalChromeOption method for adding additional options")] - public void AddAdditionalCapability(string capabilityName, object capabilityValue, bool isGlobalCapability) - { - if (isGlobalCapability) - { - this.AddAdditionalOption(capabilityName, capabilityValue); - } - else - { - this.AddAdditionalChromeOption(capabilityName, capabilityValue); - } - } - - /// - /// Returns DesiredCapabilities for Chrome with these options included as - /// capabilities. This does not copy the options. Further changes will be - /// reflected in the returned capabilities. - /// - /// The DesiredCapabilities for Chrome with these options. - public override ICapabilities ToCapabilities() - { - Dictionary chromeOptions = this.BuildChromeOptionsDictionary(); - - IWritableCapabilities capabilities = this.GenerateDesiredCapabilities(false); - capabilities.SetCapability(ChromeOptions.Capability, chromeOptions); - - Dictionary loggingPreferences = this.GenerateLoggingPreferencesDictionary(); - if (loggingPreferences != null) - { - capabilities.SetCapability(CapabilityType.LoggingPreferences, loggingPreferences); - } - - return capabilities.AsReadOnly(); - } - - private Dictionary BuildChromeOptionsDictionary() - { - Dictionary chromeOptions = new Dictionary(); - if (this.Arguments.Count > 0) - { - chromeOptions[ArgumentsChromeOption] = this.Arguments; - } - - if (!string.IsNullOrEmpty(this.binaryLocation)) - { - chromeOptions[BinaryChromeOption] = this.binaryLocation; - } - - ReadOnlyCollection extensions = this.Extensions; - if (extensions.Count > 0) - { - chromeOptions[ExtensionsChromeOption] = extensions; - } - - if (this.localStatePreferences != null && this.localStatePreferences.Count > 0) - { - chromeOptions[LocalStateChromeOption] = this.localStatePreferences; - } - - if (this.userProfilePreferences != null && this.userProfilePreferences.Count > 0) - { - chromeOptions[PreferencesChromeOption] = this.userProfilePreferences; - } - - if (this.leaveBrowserRunning) - { - chromeOptions[DetachChromeOption] = this.leaveBrowserRunning; - } - - if (this.useSpecCompliantProtocol) - { - chromeOptions[UseSpecCompliantProtocolOption] = this.useSpecCompliantProtocol; - } - - if (!string.IsNullOrEmpty(this.debuggerAddress)) - { - chromeOptions[DebuggerAddressChromeOption] = this.debuggerAddress; - } - - if (this.excludedSwitches.Count > 0) - { - chromeOptions[ExcludeSwitchesChromeOption] = this.excludedSwitches; - } - - if (!string.IsNullOrEmpty(this.minidumpPath)) - { - chromeOptions[MinidumpPathChromeOption] = this.minidumpPath; - } - - if (!string.IsNullOrEmpty(this.mobileEmulationDeviceName) || this.mobileEmulationDeviceSettings != null) - { - chromeOptions[MobileEmulationChromeOption] = this.GenerateMobileEmulationSettingsDictionary(); - } - - if (this.perfLoggingPreferences != null) - { - chromeOptions[PerformanceLoggingPreferencesChromeOption] = this.GeneratePerformanceLoggingPreferencesDictionary(); - } - - if (this.windowTypes.Count > 0) - { - chromeOptions[WindowTypesChromeOption] = this.windowTypes; - } - - foreach (KeyValuePair pair in this.additionalChromeOptions) - { - chromeOptions.Add(pair.Key, pair.Value); - } - - return chromeOptions; - } - - private Dictionary GeneratePerformanceLoggingPreferencesDictionary() - { - Dictionary perfLoggingPrefsDictionary = new Dictionary(); - perfLoggingPrefsDictionary["enableNetwork"] = this.perfLoggingPreferences.IsCollectingNetworkEvents; - perfLoggingPrefsDictionary["enablePage"] = this.perfLoggingPreferences.IsCollectingPageEvents; - - string tracingCategories = this.perfLoggingPreferences.TracingCategories; - if (!string.IsNullOrEmpty(tracingCategories)) - { - perfLoggingPrefsDictionary["traceCategories"] = tracingCategories; - } - - perfLoggingPrefsDictionary["bufferUsageReportingInterval"] = Convert.ToInt64(this.perfLoggingPreferences.BufferUsageReportingInterval.TotalMilliseconds); - - return perfLoggingPrefsDictionary; - } - - private Dictionary GenerateMobileEmulationSettingsDictionary() - { - Dictionary mobileEmulationSettings = new Dictionary(); - - if (!string.IsNullOrEmpty(this.mobileEmulationDeviceName)) - { - mobileEmulationSettings["deviceName"] = this.mobileEmulationDeviceName; - } - else if (this.mobileEmulationDeviceSettings != null) - { - mobileEmulationSettings["userAgent"] = this.mobileEmulationDeviceSettings.UserAgent; - Dictionary deviceMetrics = new Dictionary(); - deviceMetrics["width"] = this.mobileEmulationDeviceSettings.Width; - deviceMetrics["height"] = this.mobileEmulationDeviceSettings.Height; - deviceMetrics["pixelRatio"] = this.mobileEmulationDeviceSettings.PixelRatio; - if (!this.mobileEmulationDeviceSettings.EnableTouchEvents) - { - deviceMetrics["touch"] = this.mobileEmulationDeviceSettings.EnableTouchEvents; - } - - mobileEmulationSettings["deviceMetrics"] = deviceMetrics; - } - - return mobileEmulationSettings; - } } } diff --git a/dotnet/src/webdriver/Chrome/ChromeWebElement.cs b/dotnet/src/webdriver/Chrome/ChromeWebElement.cs index 394e3d6bfb94c..9a77cd6cebf96 100644 --- a/dotnet/src/webdriver/Chrome/ChromeWebElement.cs +++ b/dotnet/src/webdriver/Chrome/ChromeWebElement.cs @@ -16,14 +16,14 @@ // limitations under the License. // -using OpenQA.Selenium.Remote; +using OpenQA.Selenium.Chromium; namespace OpenQA.Selenium.Chrome { /// /// Provides a mechanism to get elements off the page for test /// - public class ChromeWebElement : RemoteWebElement + public class ChromeWebElement : ChromiumWebElement { /// /// Initializes a new instance of the class. diff --git a/dotnet/src/webdriver/Chromium/ChromiumDriver.cs b/dotnet/src/webdriver/Chromium/ChromiumDriver.cs new file mode 100644 index 0000000000000..dc0459a92ddca --- /dev/null +++ b/dotnet/src/webdriver/Chromium/ChromiumDriver.cs @@ -0,0 +1,154 @@ +// +// 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 System; +using OpenQA.Selenium.Remote; +using System.Collections.Generic; + +namespace OpenQA.Selenium.Chromium +{ + public abstract class ChromiumDriver : RemoteWebDriver + { + /// + /// Accept untrusted SSL Certificates + /// + public static readonly bool AcceptUntrustedCertificates = true; + + private const string GetNetworkConditionsCommand = "getNetworkConditions"; + private const string SetNetworkConditionsCommand = "setNetworkConditions"; + private const string DeleteNetworkConditionsCommand = "deleteNetworkConditions"; + private const string SendChromeCommand = "sendChromeCommand"; + private const string SendChromeCommandWithResult = "sendChromeCommandWithResult"; + + /// + /// Initializes a new instance of the class using the specified + /// and options. + /// + /// The to use. + /// The used to initialize the driver. + public ChromiumDriver(ChromiumDriverService service, ChromiumOptions options) + : this(service, options, RemoteWebDriver.DefaultCommandTimeout) + { + } + + /// + /// Initializes a new instance of the class using the specified . + /// + /// The to use. + /// The to be used with the Chrome driver. + /// The maximum amount of time to wait for each command. + public ChromiumDriver(ChromiumDriverService service, ChromiumOptions options, TimeSpan commandTimeout) + : base(new DriverServiceCommandExecutor(service, commandTimeout), ConvertOptionsToCapabilities(options)) + { + // Add the custom commands unique to Chrome + this.AddCustomChromeCommand(GetNetworkConditionsCommand, CommandInfo.GetCommand, "/session/{sessionId}/chromium/network_conditions"); + this.AddCustomChromeCommand(SetNetworkConditionsCommand, CommandInfo.PostCommand, "/session/{sessionId}/chromium/network_conditions"); + this.AddCustomChromeCommand(DeleteNetworkConditionsCommand, CommandInfo.DeleteCommand, "/session/{sessionId}/chromium/network_conditions"); + this.AddCustomChromeCommand(SendChromeCommand, CommandInfo.PostCommand, "/session/{sessionId}/chromium/send_command"); + this.AddCustomChromeCommand(SendChromeCommandWithResult, CommandInfo.PostCommand, "/session/{sessionId}/chromium/send_command_and_get_result"); + } + + /// + /// Gets or sets the responsible for detecting + /// sequences of keystrokes representing file paths and names. + /// + /// The Chromium driver does not allow a file detector to be set, + /// as the server component of the Chromium driver only + /// allows uploads from the local computer environment. Attempting to set + /// this property has no effect, but does not throw an exception. If you + /// are attempting to run the Chromium driver remotely, use + /// in conjunction with a standalone WebDriver server. + public override IFileDetector FileDetector + { + get { return base.FileDetector; } + set { } + } + + /// + /// Gets or sets the network condition emulation for Chromium. + /// + public ChromiumNetworkConditions NetworkConditions + { + get + { + Response response = this.Execute(GetNetworkConditionsCommand, null); + return ChromiumNetworkConditions.FromDictionary(response.Value as Dictionary); + } + + set + { + if (value == null) + { + throw new ArgumentNullException("value", "value must not be null"); + } + + Dictionary parameters = new Dictionary(); + parameters["network_conditions"] = value.ToDictionary(); + this.Execute(SetNetworkConditionsCommand, parameters); + } + } + + /// + /// Executes a custom Chrome command. + /// + /// Name of the command to execute. + /// Parameters of the command to execute. + public void ExecuteChromeCommand(string commandName, Dictionary commandParameters) + { + if (commandName == null) + { + throw new ArgumentNullException("commandName", "commandName must not be null"); + } + + Dictionary parameters = new Dictionary(); + parameters["cmd"] = commandName; + parameters["params"] = commandParameters; + this.Execute(SendChromeCommand, parameters); + } + + public object ExecuteChromeCommandWithResult(string commandName, Dictionary commandParameters) + { + if (commandName == null) + { + throw new ArgumentNullException("commandName", "commandName must not be null"); + } + + Dictionary parameters = new Dictionary(); + parameters["cmd"] = commandName; + parameters["params"] = commandParameters; + Response response = this.Execute(SendChromeCommandWithResult, parameters); + return response.Value; + } + + private static ICapabilities ConvertOptionsToCapabilities(ChromiumOptions options) + { + if (options == null) + { + throw new ArgumentNullException("options", "options must not be null"); + } + + return options.ToCapabilities(); + } + + private void AddCustomChromeCommand(string commandName, string method, string resourcePath) + { + CommandInfo commandInfoToAdd = new CommandInfo(method, resourcePath); + this.CommandExecutor.CommandInfoRepository.TryAddCommand(commandName, commandInfoToAdd); + } + } +} diff --git a/dotnet/src/webdriver/Chromium/ChromiumDriverService.cs b/dotnet/src/webdriver/Chromium/ChromiumDriverService.cs new file mode 100644 index 0000000000000..a6995ec956160 --- /dev/null +++ b/dotnet/src/webdriver/Chromium/ChromiumDriverService.cs @@ -0,0 +1,213 @@ +// +// 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 System; +using System.Globalization; +using System.Text; +using OpenQA.Selenium.Internal; + +namespace OpenQA.Selenium.Chromium +{ + /// + /// Exposes the service provided by the native ChromiumDriver executable. + /// + public abstract class ChromiumDriverService : DriverService + { + private const string DefaultChromeDriverServiceExecutableName = "chromedriver"; + + private string logPath = string.Empty; + private string urlPathPrefix = string.Empty; + private string portServerAddress = string.Empty; + private string whitelistedIpAddresses = string.Empty; + private int adbPort = -1; + private bool enableVerboseLogging; + private bool enableAppendLog; + + /// + /// Initializes a new instance of the class. + /// + /// The full path to the ChromeDriver executable. + /// The file name of the ChromeDriver executable. + /// The port on which the ChromeDriver executable should listen. + /// The url that ChromiumDriver should be downloaded from. + protected ChromiumDriverService(string executablePath, string executableFileName, int port, Uri downloadUrl) + : base(executablePath, port, executableFileName, downloadUrl) + { + } + + /// + /// Gets or sets the location of the log file written to by the ChromeDriver executable. + /// + public string LogPath + { + get { return this.logPath; } + set { this.logPath = value; } + } + + /// + /// Gets or sets the base URL path prefix for commands (e.g., "wd/url"). + /// + public string UrlPathPrefix + { + get { return this.urlPathPrefix; } + set { this.urlPathPrefix = value; } + } + + /// + /// Gets or sets the address of a server to contact for reserving a port. + /// + public string PortServerAddress + { + get { return this.portServerAddress; } + set { this.portServerAddress = value; } + } + + /// + /// Gets or sets the port on which the Android Debug Bridge is listening for commands. + /// + public int AndroidDebugBridgePort + { + get { return this.adbPort; } + set { this.adbPort = value; } + } + + /// + /// Gets or sets a value indicating whether to enable verbose logging for the ChromeDriver executable. + /// Defaults to . + /// + public bool EnableVerboseLogging + { + get { return this.enableVerboseLogging; } + set { this.enableVerboseLogging = value; } + } + + /// + /// Gets or sets a value indicating whether to enable appending to an existing ChromeDriver log file. + /// Defaults to . + /// + public bool EnableAppendLog + { + get { return this.enableAppendLog; } + set { this.enableAppendLog = value; } + } + + /// + /// Gets or sets the comma-delimited list of IP addresses that are approved to + /// connect to this instance of the Chrome driver. Defaults to an empty string, + /// which means only the local loopback address can connect. + /// + public string WhitelistedIPAddresses + { + get { return this.whitelistedIpAddresses; } + set { this.whitelistedIpAddresses = value; } + } + + /// + /// Gets the command-line arguments for the driver service. + /// + protected override string CommandLineArguments + { + get + { + StringBuilder argsBuilder = new StringBuilder(base.CommandLineArguments); + if (this.adbPort > 0) + { + argsBuilder.AppendFormat(CultureInfo.InvariantCulture, " --adb-port={0}", this.adbPort); + } + + if (this.SuppressInitialDiagnosticInformation) + { + argsBuilder.Append(" --silent"); + } + + if (this.enableVerboseLogging) + { + argsBuilder.Append(" --verbose"); + } + + if (this.enableAppendLog) + { + argsBuilder.Append(" --append-log"); + } + + if (!string.IsNullOrEmpty(this.logPath)) + { + argsBuilder.AppendFormat(CultureInfo.InvariantCulture, " --log-path=\"{0}\"", this.logPath); + } + + if (!string.IsNullOrEmpty(this.urlPathPrefix)) + { + argsBuilder.AppendFormat(CultureInfo.InvariantCulture, " --url-base={0}", this.urlPathPrefix); + } + + if (!string.IsNullOrEmpty(this.portServerAddress)) + { + argsBuilder.AppendFormat(CultureInfo.InvariantCulture, " --port-server={0}", this.portServerAddress); + } + + if (!string.IsNullOrEmpty(this.whitelistedIpAddresses)) + { + argsBuilder.Append(string.Format(CultureInfo.InvariantCulture, " -whitelisted-ips={0}", this.whitelistedIpAddresses)); + } + + return argsBuilder.ToString(); + } + } + + /// + /// Returns the Chromium driver filename for the currently running platform + /// + /// The name of the Chromium executable. Defaulit is "chromedriver". + /// The file name of the Chromium driver service executable. + protected static string ChromiumDriverServiceFileName(string fileName = DefaultChromeDriverServiceExecutableName) + { + // Unfortunately, detecting the currently running platform isn't as + // straightforward as you might hope. + // See: http://mono.wikia.com/wiki/Detecting_the_execution_platform + // and https://msdn.microsoft.com/en-us/library/3a8hyw88(v=vs.110).aspx + const int PlatformMonoUnixValue = 128; + + switch (Environment.OSVersion.Platform) + { + case PlatformID.Win32NT: + case PlatformID.Win32S: + case PlatformID.Win32Windows: + case PlatformID.WinCE: + fileName += ".exe"; + break; + + case PlatformID.MacOSX: + case PlatformID.Unix: + break; + + // Don't handle the Xbox case. Let default handle it. + // case PlatformID.Xbox: + // break; + default: + if ((int)Environment.OSVersion.Platform == PlatformMonoUnixValue) + { + break; + } + + throw new WebDriverException("Unsupported platform: " + Environment.OSVersion.Platform); + } + + return fileName; + } + } +} diff --git a/dotnet/src/webdriver/Chrome/ChromeMobileEmulationDeviceSettings.cs b/dotnet/src/webdriver/Chromium/ChromiumMobileEmulationDeviceSettings.cs similarity index 84% rename from dotnet/src/webdriver/Chrome/ChromeMobileEmulationDeviceSettings.cs rename to dotnet/src/webdriver/Chromium/ChromiumMobileEmulationDeviceSettings.cs index 5190b492565bd..d607403c4ad5d 100644 --- a/dotnet/src/webdriver/Chrome/ChromeMobileEmulationDeviceSettings.cs +++ b/dotnet/src/webdriver/Chromium/ChromiumMobileEmulationDeviceSettings.cs @@ -1,4 +1,4 @@ -// +// // 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 @@ -16,13 +16,13 @@ // limitations under the License. // -namespace OpenQA.Selenium.Chrome +namespace OpenQA.Selenium.Chromium { /// /// Represents the type-safe options for setting settings for emulating a - /// mobile device in the Chrome browser. + /// mobile device in the Chromium browser. /// - public class ChromeMobileEmulationDeviceSettings + public class ChromiumMobileEmulationDeviceSettings { private string userAgent = string.Empty; private long width; @@ -31,18 +31,18 @@ public class ChromeMobileEmulationDeviceSettings private bool enableTouchEvents = true; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public ChromeMobileEmulationDeviceSettings() + public ChromiumMobileEmulationDeviceSettings() { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The user agent string to be used by the browser when emulating /// a mobile device. - public ChromeMobileEmulationDeviceSettings(string userAgent) + public ChromiumMobileEmulationDeviceSettings(string userAgent) { this.userAgent = userAgent; } diff --git a/dotnet/src/webdriver/Chrome/ChromeNetworkConditions.cs b/dotnet/src/webdriver/Chromium/ChromiumNetworkConditions.cs similarity index 93% rename from dotnet/src/webdriver/Chrome/ChromeNetworkConditions.cs rename to dotnet/src/webdriver/Chromium/ChromiumNetworkConditions.cs index 93eb3a47ff511..1fd64fb6706fc 100644 --- a/dotnet/src/webdriver/Chrome/ChromeNetworkConditions.cs +++ b/dotnet/src/webdriver/Chromium/ChromiumNetworkConditions.cs @@ -21,12 +21,12 @@ using System.Linq; using System.Text; -namespace OpenQA.Selenium.Chrome +namespace OpenQA.Selenium.Chromium { /// - /// Provides manipulation of getting and setting network conditions from Chrome. + /// Provides manipulation of getting and setting network conditions from Chromium. /// - public class ChromeNetworkConditions + public class ChromiumNetworkConditions { private bool offline; private TimeSpan latency = TimeSpan.Zero; @@ -69,9 +69,9 @@ public long UploadThroughput set { this.uploadThroughput = value; } } - static internal ChromeNetworkConditions FromDictionary(Dictionary dictionary) + static internal ChromiumNetworkConditions FromDictionary(Dictionary dictionary) { - ChromeNetworkConditions conditions = new ChromeNetworkConditions(); + ChromiumNetworkConditions conditions = new ChromiumNetworkConditions(); if (dictionary.ContainsKey("offline")) { conditions.IsOffline = (bool)dictionary["offline"]; diff --git a/dotnet/src/webdriver/Chromium/ChromiumOptions.cs b/dotnet/src/webdriver/Chromium/ChromiumOptions.cs new file mode 100644 index 0000000000000..effc4ab3c4759 --- /dev/null +++ b/dotnet/src/webdriver/Chromium/ChromiumOptions.cs @@ -0,0 +1,686 @@ +// +// 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 System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.IO; +using OpenQA.Selenium.Remote; + +namespace OpenQA.Selenium.Chromium +{ + public abstract class ChromiumOptions : DriverOptions + { + /// + /// Gets the name of the capability used to store Chromium options in + /// an object. + /// + private const string DefaultCapability = "goog:chromeOptions"; + + // TODO: Remove this if block when chromedriver bug 2371 is fixed + // (https://bugs.chromium.org/p/chromedriver/issues/detail?id=2371) + internal static readonly string ForceAlwaysMatchCapabilityName = "se:forceAlwaysMatch"; + + private const string DefaultBrowserNameValue = "chrome"; + + private const string ArgumentsChromeOption = "args"; + private const string BinaryChromeOption = "binary"; + private const string ExtensionsChromeOption = "extensions"; + private const string LocalStateChromeOption = "localState"; + private const string PreferencesChromeOption = "prefs"; + private const string DetachChromeOption = "detach"; + private const string DebuggerAddressChromeOption = "debuggerAddress"; + private const string ExcludeSwitchesChromeOption = "excludeSwitches"; + private const string MinidumpPathChromeOption = "minidumpPath"; + private const string MobileEmulationChromeOption = "mobileEmulation"; + private const string PerformanceLoggingPreferencesChromeOption = "perfLoggingPrefs"; + private const string WindowTypesChromeOption = "windowTypes"; + private const string UseSpecCompliantProtocolOption = "w3c"; + + private string Capability; + private bool leaveBrowserRunning; + private bool useSpecCompliantProtocol = true; + private string binaryLocation; + private string debuggerAddress; + private string minidumpPath; + private List arguments = new List(); + private List extensionFiles = new List(); + private List encodedExtensions = new List(); + private List excludedSwitches = new List(); + private List windowTypes = new List(); + private Dictionary additionalChromeOptions = new Dictionary(); + private Dictionary userProfilePreferences; + private Dictionary localStatePreferences; + + private string mobileEmulationDeviceName; + private ChromiumMobileEmulationDeviceSettings mobileEmulationDeviceSettings; + private ChromiumPerformanceLoggingPreferences perfLoggingPreferences; + + public ChromiumOptions(string browserName = DefaultBrowserNameValue, string capabilityKey = DefaultCapability) : base() + { + this.BrowserName = browserName; + this.Capability = capabilityKey; + this.AddKnownCapabilityName(capabilityKey, "current ChromeOptions class instance"); + this.AddKnownCapabilityName(CapabilityType.LoggingPreferences, "SetLoggingPreference method"); + this.AddKnownCapabilityName(ChromiumOptions.ArgumentsChromeOption, "AddArguments method"); + this.AddKnownCapabilityName(ChromiumOptions.BinaryChromeOption, "BinaryLocation property"); + this.AddKnownCapabilityName(ChromiumOptions.ExtensionsChromeOption, "AddExtensions method"); + this.AddKnownCapabilityName(ChromiumOptions.LocalStateChromeOption, "AddLocalStatePreference method"); + this.AddKnownCapabilityName(ChromiumOptions.PreferencesChromeOption, "AddUserProfilePreference method"); + this.AddKnownCapabilityName(ChromiumOptions.DetachChromeOption, "LeaveBrowserRunning property"); + this.AddKnownCapabilityName(ChromiumOptions.DebuggerAddressChromeOption, "DebuggerAddress property"); + this.AddKnownCapabilityName(ChromiumOptions.ExcludeSwitchesChromeOption, "AddExcludedArgument property"); + this.AddKnownCapabilityName(ChromiumOptions.MinidumpPathChromeOption, "MinidumpPath property"); + this.AddKnownCapabilityName(ChromiumOptions.MobileEmulationChromeOption, "EnableMobileEmulation method"); + this.AddKnownCapabilityName(ChromiumOptions.PerformanceLoggingPreferencesChromeOption, "PerformanceLoggingPreferences property"); + this.AddKnownCapabilityName(ChromiumOptions.WindowTypesChromeOption, "AddWindowTypes method"); + this.AddKnownCapabilityName(ChromiumOptions.UseSpecCompliantProtocolOption, "UseSpecCompliantProtocol property"); + this.AddKnownCapabilityName(ChromiumOptions.ForceAlwaysMatchCapabilityName, ""); + } + + /// + /// Gets or sets the location of the Chromium browser's binary executable file. + /// + public string BinaryLocation + { + get { return this.binaryLocation; } + set { this.binaryLocation = value; } + } + + /// + /// Gets or sets a value indicating whether Chromium should be left running after the + /// ChromeDriver instance is exited. Defaults to . + /// + public bool LeaveBrowserRunning + { + get { return this.leaveBrowserRunning; } + set { this.leaveBrowserRunning = value; } + } + + /// + /// Gets the list of arguments appended to the Chromium command line as a string array. + /// + public ReadOnlyCollection Arguments + { + get { return this.arguments.AsReadOnly(); } + } + + /// + /// Gets the list of extensions to be installed as an array of base64-encoded strings. + /// + public ReadOnlyCollection Extensions + { + get + { + List allExtensions = new List(this.encodedExtensions); + foreach (string extensionFile in this.extensionFiles) + { + byte[] extensionByteArray = File.ReadAllBytes(extensionFile); + string encodedExtension = Convert.ToBase64String(extensionByteArray); + allExtensions.Add(encodedExtension); + } + + return allExtensions.AsReadOnly(); + } + } + + /// + /// Gets or sets the address of a Chromium debugger server to connect to. + /// Should be of the form "{hostname|IP address}:port". + /// + public string DebuggerAddress + { + get { return this.debuggerAddress; } + set { this.debuggerAddress = value; } + } + + /// + /// Gets or sets the directory in which to store minidump files. + /// + public string MinidumpPath + { + get { return this.minidumpPath; } + set { this.minidumpPath = value; } + } + + /// + /// Gets or sets the performance logging preferences for the driver. + /// + public ChromiumPerformanceLoggingPreferences PerformanceLoggingPreferences + { + get { return this.perfLoggingPreferences; } + set { this.perfLoggingPreferences = value; } + } + + /// + /// Gets or sets a value indicating whether the instance + /// should use the legacy OSS protocol dialect or a dialect compliant with the W3C + /// WebDriver Specification. + /// + public bool UseSpecCompliantProtocol + { + get { return this.useSpecCompliantProtocol; } + set { this.useSpecCompliantProtocol = value; } + } + + /// + /// Adds a single argument to the list of arguments to be appended to the browser executable command line. + /// + /// The argument to add. + public void AddArgument(string argument) + { + if (string.IsNullOrEmpty(argument)) + { + throw new ArgumentException("argument must not be null or empty", "argument"); + } + + this.AddArguments(argument); + } + + /// + /// Adds arguments to be appended to the browser executable command line. + /// + /// An array of arguments to add. + public void AddArguments(params string[] argumentsToAdd) + { + this.AddArguments(new List(argumentsToAdd)); + } + + /// + /// Adds arguments to be appended to the browser executable command line. + /// + /// An object of arguments to add. + public void AddArguments(IEnumerable argumentsToAdd) + { + if (argumentsToAdd == null) + { + throw new ArgumentNullException("argumentsToAdd", "argumentsToAdd must not be null"); + } + + this.arguments.AddRange(argumentsToAdd); + } + + /// + /// Adds a single argument to be excluded from the list of arguments passed by default + /// to the browser executable command line by chromedriver.exe. + /// + /// The argument to exclude. + public void AddExcludedArgument(string argument) + { + if (string.IsNullOrEmpty(argument)) + { + throw new ArgumentException("argument must not be null or empty", "argument"); + } + + this.AddExcludedArguments(argument); + } + + /// + /// Adds arguments to be excluded from the list of arguments passed by default + /// to the browser executable command line by chromedriver.exe. + /// + /// An array of arguments to exclude. + public void AddExcludedArguments(params string[] argumentsToExclude) + { + this.AddExcludedArguments(new List(argumentsToExclude)); + } + + /// + /// Adds arguments to be excluded from the list of arguments passed by default + /// to the browser executable command line by chromedriver.exe. + /// + /// An object of arguments to exclude. + public void AddExcludedArguments(IEnumerable argumentsToExclude) + { + if (argumentsToExclude == null) + { + throw new ArgumentNullException("argumentsToExclude", "argumentsToExclude must not be null"); + } + + this.excludedSwitches.AddRange(argumentsToExclude); + } + + /// + /// Adds a path to a packed Chrome extension (.crx file) to the list of extensions + /// to be installed in the instance of Chrome. + /// + /// The full path to the extension to add. + public void AddExtension(string pathToExtension) + { + if (string.IsNullOrEmpty(pathToExtension)) + { + throw new ArgumentException("pathToExtension must not be null or empty", "pathToExtension"); + } + + this.AddExtensions(pathToExtension); + } + + /// + /// Adds a list of paths to packed Chrome extensions (.crx files) to be installed + /// in the instance of Chrome. + /// + /// An array of full paths to the extensions to add. + public void AddExtensions(params string[] extensions) + { + this.AddExtensions(new List(extensions)); + } + + /// + /// Adds a list of paths to packed Chrome extensions (.crx files) to be installed + /// in the instance of Chrome. + /// + /// An of full paths to the extensions to add. + public void AddExtensions(IEnumerable extensions) + { + if (extensions == null) + { + throw new ArgumentNullException("extensions", "extensions must not be null"); + } + + foreach (string extension in extensions) + { + if (!File.Exists(extension)) + { + throw new FileNotFoundException("No extension found at the specified path", extension); + } + + this.extensionFiles.Add(extension); + } + } + + /// + /// Adds a base64-encoded string representing a Chrome extension to the list of extensions + /// to be installed in the instance of Chrome. + /// + /// A base64-encoded string representing the extension to add. + public void AddEncodedExtension(string extension) + { + if (string.IsNullOrEmpty(extension)) + { + throw new ArgumentException("extension must not be null or empty", "extension"); + } + + this.AddEncodedExtensions(extension); + } + + /// + /// Adds a list of base64-encoded strings representing Chrome extensions to the list of extensions + /// to be installed in the instance of Chrome. + /// + /// An array of base64-encoded strings representing the extensions to add. + public void AddEncodedExtensions(params string[] extensions) + { + this.AddEncodedExtensions(new List(extensions)); + } + + /// + /// Adds a list of base64-encoded strings representing Chrome extensions to be installed + /// in the instance of Chrome. + /// + /// An of base64-encoded strings + /// representing the extensions to add. + public void AddEncodedExtensions(IEnumerable extensions) + { + if (extensions == null) + { + throw new ArgumentNullException("extensions", "extensions must not be null"); + } + + foreach (string extension in extensions) + { + // Run the extension through the base64 converter to test that the + // string is not malformed. + try + { + Convert.FromBase64String(extension); + } + catch (FormatException ex) + { + throw new WebDriverException("Could not properly decode the base64 string", ex); + } + + this.encodedExtensions.Add(extension); + } + } + + /// + /// Adds a preference for the user-specific profile or "user data directory." + /// If the specified preference already exists, it will be overwritten. + /// + /// The name of the preference to set. + /// The value of the preference to set. + public void AddUserProfilePreference(string preferenceName, object preferenceValue) + { + if (this.userProfilePreferences == null) + { + this.userProfilePreferences = new Dictionary(); + } + + this.userProfilePreferences[preferenceName] = preferenceValue; + } + + /// + /// Adds a preference for the local state file in the user's data directory for Chromium. + /// If the specified preference already exists, it will be overwritten. + /// + /// The name of the preference to set. + /// The value of the preference to set. + public void AddLocalStatePreference(string preferenceName, object preferenceValue) + { + if (this.localStatePreferences == null) + { + this.localStatePreferences = new Dictionary(); + } + + this.localStatePreferences[preferenceName] = preferenceValue; + } + + /// + /// Allows the Chromium browser to emulate a mobile device. + /// + /// The name of the device to emulate. The device name must be a + /// valid device name from the Chrome DevTools Emulation panel. + /// Specifying an invalid device name will not throw an exeption, but + /// will generate an error in Chrome when the driver starts. To unset mobile + /// emulation, call this method with as the argument. + public void EnableMobileEmulation(string deviceName) + { + this.mobileEmulationDeviceSettings = null; + this.mobileEmulationDeviceName = deviceName; + } + + /// + /// Allows the Chromium browser to emulate a mobile device. + /// + /// The + /// object containing the settings of the device to emulate. + /// Thrown if the device settings option does + /// not have a user agent string set. + /// Specifying an invalid device name will not throw an exeption, but + /// will generate an error in Chrome when the driver starts. To unset mobile + /// emulation, call this method with as the argument. + public void EnableMobileEmulation(ChromiumMobileEmulationDeviceSettings deviceSettings) + { + this.mobileEmulationDeviceName = null; + if (deviceSettings != null && string.IsNullOrEmpty(deviceSettings.UserAgent)) + { + throw new ArgumentException("Device settings must include a user agent string.", "deviceSettings"); + } + + this.mobileEmulationDeviceSettings = deviceSettings; + } + + /// + /// Adds a type of window that will be listed in the list of window handles + /// returned by the Chrome driver. + /// + /// The name of the window type to add. + /// This method can be used to allow the driver to access {webview} + /// elements by adding "webview" as a window type. + public void AddWindowType(string windowType) + { + if (string.IsNullOrEmpty(windowType)) + { + throw new ArgumentException("windowType must not be null or empty", "windowType"); + } + + this.AddWindowTypes(windowType); + } + + /// + /// Adds a list of window types that will be listed in the list of window handles + /// returned by the Chromium driver. + /// + /// An array of window types to add. + public void AddWindowTypes(params string[] windowTypesToAdd) + { + this.AddWindowTypes(new List(windowTypesToAdd)); + } + + /// + /// Adds a list of window types that will be listed in the list of window handles + /// returned by the Chromium driver. + /// + /// An of window types to add. + public void AddWindowTypes(IEnumerable windowTypesToAdd) + { + if (windowTypesToAdd == null) + { + throw new ArgumentNullException("windowTypesToAdd", "windowTypesToAdd must not be null"); + } + + this.windowTypes.AddRange(windowTypesToAdd); + } + + /// + /// Provides a means to add additional capabilities not yet added as type safe options + /// for the Chromium driver. + /// + /// The name of the capability to add. + /// The value of the capability to add. + /// + /// thrown when attempting to add a capability for which there is already a type safe option, or + /// when is or the empty string. + /// + /// Calling + /// where has already been added will overwrite the + /// existing value with the new value in . + /// Calling this method adds capabilities to the Chrome-specific options object passed to + /// webdriver executable (property name 'goog:chromeOptions'). + public void AddAdditionalChromeOption(string optionName, object optionValue) + { + this.ValidateCapabilityName(optionName); + this.additionalChromeOptions[optionName] = optionValue; + } + + /// + /// Provides a means to add additional capabilities not yet added as type safe options + /// for the Chromium driver. + /// + /// The name of the capability to add. + /// The value of the capability to add. + /// + /// thrown when attempting to add a capability for which there is already a type safe option, or + /// when is or the empty string. + /// + /// Calling + /// where has already been added will overwrite the + /// existing value with the new value in . + /// Also, by default, calling this method adds capabilities to the options object passed to + /// chromedriver.exe. + [Obsolete("Use the temporary AddAdditionalOption method or the AddAdditionalChromeOption method for adding additional options")] + public override void AddAdditionalCapability(string capabilityName, object capabilityValue) + { + // Add the capability to the chromeOptions object by default. This is to handle + // the 80% case where the chromedriver team adds a new option in chromedriver.exe + // and the bindings have not yet had a type safe option added. + this.AddAdditionalCapability(capabilityName, capabilityValue, false); + } + + /// + /// Provides a means to add additional capabilities not yet added as type safe options + /// for the Chromium driver. + /// + /// The name of the capability to add. + /// The value of the capability to add. + /// Indicates whether the capability is to be set as a global + /// capability for the driver instead of a Chromium-specific option. + /// + /// thrown when attempting to add a capability for which there is already a type safe option, or + /// when is or the empty string. + /// + /// Calling + /// where has already been added will overwrite the + /// existing value with the new value in + [Obsolete("Use the temporary AddAdditionalOption method or the AddAdditionalChromeOption method for adding additional options")] + public void AddAdditionalCapability(string capabilityName, object capabilityValue, bool isGlobalCapability) + { + if (isGlobalCapability) + { + this.AddAdditionalOption(capabilityName, capabilityValue); + } + else + { + this.AddAdditionalChromeOption(capabilityName, capabilityValue); + } + } + + /// + /// Returns DesiredCapabilities for Chromium with these options included as + /// capabilities. This does not copy the options. Further changes will be + /// reflected in the returned capabilities. + /// + /// The DesiredCapabilities for Chrome with these options. + public override ICapabilities ToCapabilities() + { + Dictionary chromeOptions = this.BuildChromeOptionsDictionary(); + + IWritableCapabilities capabilities = this.GenerateDesiredCapabilities(false); + capabilities.SetCapability(this.Capability, chromeOptions); + + Dictionary loggingPreferences = this.GenerateLoggingPreferencesDictionary(); + if (loggingPreferences != null) + { + capabilities.SetCapability(CapabilityType.LoggingPreferences, loggingPreferences); + } + + return capabilities.AsReadOnly(); + } + + private Dictionary BuildChromeOptionsDictionary() + { + Dictionary chromeOptions = new Dictionary(); + if (this.Arguments.Count > 0) + { + chromeOptions[ArgumentsChromeOption] = this.Arguments; + } + + if (!string.IsNullOrEmpty(this.binaryLocation)) + { + chromeOptions[BinaryChromeOption] = this.binaryLocation; + } + + ReadOnlyCollection extensions = this.Extensions; + if (extensions.Count > 0) + { + chromeOptions[ExtensionsChromeOption] = extensions; + } + + if (this.localStatePreferences != null && this.localStatePreferences.Count > 0) + { + chromeOptions[LocalStateChromeOption] = this.localStatePreferences; + } + + if (this.userProfilePreferences != null && this.userProfilePreferences.Count > 0) + { + chromeOptions[PreferencesChromeOption] = this.userProfilePreferences; + } + + if (this.leaveBrowserRunning) + { + chromeOptions[DetachChromeOption] = this.leaveBrowserRunning; + } + + if (this.useSpecCompliantProtocol) + { + chromeOptions[UseSpecCompliantProtocolOption] = this.useSpecCompliantProtocol; + } + + if (!string.IsNullOrEmpty(this.debuggerAddress)) + { + chromeOptions[DebuggerAddressChromeOption] = this.debuggerAddress; + } + + if (this.excludedSwitches.Count > 0) + { + chromeOptions[ExcludeSwitchesChromeOption] = this.excludedSwitches; + } + + if (!string.IsNullOrEmpty(this.minidumpPath)) + { + chromeOptions[MinidumpPathChromeOption] = this.minidumpPath; + } + + if (!string.IsNullOrEmpty(this.mobileEmulationDeviceName) || this.mobileEmulationDeviceSettings != null) + { + chromeOptions[MobileEmulationChromeOption] = this.GenerateMobileEmulationSettingsDictionary(); + } + + if (this.perfLoggingPreferences != null) + { + chromeOptions[PerformanceLoggingPreferencesChromeOption] = this.GeneratePerformanceLoggingPreferencesDictionary(); + } + + if (this.windowTypes.Count > 0) + { + chromeOptions[WindowTypesChromeOption] = this.windowTypes; + } + + foreach (KeyValuePair pair in this.additionalChromeOptions) + { + chromeOptions.Add(pair.Key, pair.Value); + } + + return chromeOptions; + } + + private Dictionary GeneratePerformanceLoggingPreferencesDictionary() + { + Dictionary perfLoggingPrefsDictionary = new Dictionary(); + perfLoggingPrefsDictionary["enableNetwork"] = this.perfLoggingPreferences.IsCollectingNetworkEvents; + perfLoggingPrefsDictionary["enablePage"] = this.perfLoggingPreferences.IsCollectingPageEvents; + + string tracingCategories = this.perfLoggingPreferences.TracingCategories; + if (!string.IsNullOrEmpty(tracingCategories)) + { + perfLoggingPrefsDictionary["traceCategories"] = tracingCategories; + } + + perfLoggingPrefsDictionary["bufferUsageReportingInterval"] = Convert.ToInt64(this.perfLoggingPreferences.BufferUsageReportingInterval.TotalMilliseconds); + + return perfLoggingPrefsDictionary; + } + + private Dictionary GenerateMobileEmulationSettingsDictionary() + { + Dictionary mobileEmulationSettings = new Dictionary(); + + if (!string.IsNullOrEmpty(this.mobileEmulationDeviceName)) + { + mobileEmulationSettings["deviceName"] = this.mobileEmulationDeviceName; + } + else if (this.mobileEmulationDeviceSettings != null) + { + mobileEmulationSettings["userAgent"] = this.mobileEmulationDeviceSettings.UserAgent; + Dictionary deviceMetrics = new Dictionary(); + deviceMetrics["width"] = this.mobileEmulationDeviceSettings.Width; + deviceMetrics["height"] = this.mobileEmulationDeviceSettings.Height; + deviceMetrics["pixelRatio"] = this.mobileEmulationDeviceSettings.PixelRatio; + if (!this.mobileEmulationDeviceSettings.EnableTouchEvents) + { + deviceMetrics["touch"] = this.mobileEmulationDeviceSettings.EnableTouchEvents; + } + + mobileEmulationSettings["deviceMetrics"] = deviceMetrics; + } + + return mobileEmulationSettings; + } + } +} diff --git a/dotnet/src/webdriver/Chrome/ChromePerformanceLoggingPreferences.cs b/dotnet/src/webdriver/Chromium/ChromiumPerformanceLoggingPreferences.cs similarity index 85% rename from dotnet/src/webdriver/Chrome/ChromePerformanceLoggingPreferences.cs rename to dotnet/src/webdriver/Chromium/ChromiumPerformanceLoggingPreferences.cs index 027329acf2065..0c74364a742b3 100644 --- a/dotnet/src/webdriver/Chrome/ChromePerformanceLoggingPreferences.cs +++ b/dotnet/src/webdriver/Chromium/ChromiumPerformanceLoggingPreferences.cs @@ -19,13 +19,13 @@ using System; using System.Collections.Generic; -namespace OpenQA.Selenium.Chrome +namespace OpenQA.Selenium.Chromium { /// /// Represents the type-safe options for setting preferences for performance - /// logging in the Chrome browser. + /// logging in the Chromium browser. /// - public class ChromePerformanceLoggingPreferences + public class ChromiumPerformanceLoggingPreferences { private bool isCollectingNetworkEvents = true; private bool isCollectingPageEvents = true; @@ -33,7 +33,7 @@ public class ChromePerformanceLoggingPreferences private List tracingCategories = new List(); /// - /// Gets or sets a value indicating whether Chrome will collect events from the Network domain. + /// Gets or sets a value indicating whether Chromium will collect events from the Network domain. /// Defaults to . /// public bool IsCollectingNetworkEvents @@ -43,7 +43,7 @@ public bool IsCollectingNetworkEvents } /// - /// Gets or sets a value indicating whether Chrome will collect events from the Page domain. + /// Gets or sets a value indicating whether Chromium will collect events from the Page domain. /// Defaults to . /// public bool IsCollectingPageEvents @@ -53,7 +53,7 @@ public bool IsCollectingPageEvents } /// - /// Gets or sets the interval between Chrome DevTools trace buffer usage events. + /// Gets or sets the interval between Chromium DevTools trace buffer usage events. /// Defaults to 1000 milliseconds. /// /// Thrown when an attempt is made to set @@ -93,7 +93,7 @@ public string TracingCategories } /// - /// Adds a single category to the list of Chrome tracing categories for which events should be collected. + /// Adds a single category to the list of Chromium tracing categories for which events should be collected. /// /// The category to add. public void AddTracingCategory(string category) @@ -107,7 +107,7 @@ public void AddTracingCategory(string category) } /// - /// Adds categories to the list of Chrome tracing categories for which events should be collected. + /// Adds categories to the list of Chromium tracing categories for which events should be collected. /// /// An array of categories to add. public void AddTracingCategories(params string[] categoriesToAdd) @@ -116,7 +116,7 @@ public void AddTracingCategories(params string[] categoriesToAdd) } /// - /// Adds categories to the list of Chrome tracing categories for which events should be collected. + /// Adds categories to the list of Chromium tracing categories for which events should be collected. /// /// An object of categories to add. public void AddTracingCategories(IEnumerable categoriesToAdd) diff --git a/dotnet/src/webdriver/Chromium/ChromiumWebElement.cs b/dotnet/src/webdriver/Chromium/ChromiumWebElement.cs new file mode 100644 index 0000000000000..3ea1f4f5c37a9 --- /dev/null +++ b/dotnet/src/webdriver/Chromium/ChromiumWebElement.cs @@ -0,0 +1,38 @@ +// +// 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.Remote; + +namespace OpenQA.Selenium.Chromium +{ + /// + /// Provides a mechanism to get elements off the page for test + /// + public abstract class ChromiumWebElement : RemoteWebElement + { + /// + /// Initializes a new instance of the class. + /// + /// Driver in use + /// Id of the element + public ChromiumWebElement(ChromiumDriver parent, string elementId) + : base(parent, elementId) + { + } + } +} diff --git a/dotnet/src/webdriver/DriverOptions.cs b/dotnet/src/webdriver/DriverOptions.cs index 73cde41d2921e..a70ae1371764f 100644 --- a/dotnet/src/webdriver/DriverOptions.cs +++ b/dotnet/src/webdriver/DriverOptions.cs @@ -365,6 +365,18 @@ protected void AddKnownCapabilityName(string capabilityName, string typeSafeOpti this.knownCapabilityNames[capabilityName] = typeSafeOptionName; } + /// + /// Remove a capability from the list of known capabilities + /// + /// The name of the capability to be removed. + protected void RemoveKnownCapabilityName(string capabilityName) + { + if (!string.IsNullOrEmpty(capabilityName) && this.knownCapabilityNames.ContainsKey(capabilityName)) + { + this.knownCapabilityNames.Remove(capabilityName); + } + } + /// /// Gets a value indicating whether the specified capability name is a known capability name which has a type-safe option. /// diff --git a/dotnet/src/webdriver/Edge/EdgeDriver.cs b/dotnet/src/webdriver/Edge/EdgeDriver.cs index 7c8b9954f0f82..0da8d7ed29d8a 100644 --- a/dotnet/src/webdriver/Edge/EdgeDriver.cs +++ b/dotnet/src/webdriver/Edge/EdgeDriver.cs @@ -1,4 +1,4 @@ -// +// // 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 @@ -17,6 +17,7 @@ // using System; +using OpenQA.Selenium.Chromium; using OpenQA.Selenium.Remote; namespace OpenQA.Selenium.Edge @@ -24,7 +25,7 @@ namespace OpenQA.Selenium.Edge /// /// Provides a mechanism to write tests against Edge /// - public class EdgeDriver : RemoteWebDriver + public class EdgeDriver : ChromiumDriver { /// /// Initializes a new instance of the class. @@ -39,7 +40,7 @@ public EdgeDriver() /// /// The to be used with the Edge driver. public EdgeDriver(EdgeOptions options) - : this(EdgeDriverService.CreateDefaultService(), options, RemoteWebDriver.DefaultCommandTimeout) + : this(EdgeDriverService.CreateDefaultService(), options) { } @@ -103,18 +104,9 @@ public EdgeDriver(EdgeDriverService service, EdgeOptions options) /// The to be used with the Edge driver. /// The maximum amount of time to wait for each command. public EdgeDriver(EdgeDriverService service, EdgeOptions options, TimeSpan commandTimeout) - : base(new DriverServiceCommandExecutor(service, commandTimeout), ConvertOptionsToCapabilities(options)) + : base(service, options, commandTimeout) { } - private static ICapabilities ConvertOptionsToCapabilities(EdgeOptions options) - { - if (options == null) - { - throw new ArgumentNullException("options", "options must not be null"); - } - - return options.ToCapabilities(); - } } } diff --git a/dotnet/src/webdriver/Edge/EdgeDriverService.cs b/dotnet/src/webdriver/Edge/EdgeDriverService.cs index e6a9beb2a59f1..8621ecb17d70d 100644 --- a/dotnet/src/webdriver/Edge/EdgeDriverService.cs +++ b/dotnet/src/webdriver/Edge/EdgeDriverService.cs @@ -20,20 +20,23 @@ using System.Globalization; using System.Text; using OpenQA.Selenium.Internal; +using OpenQA.Selenium.Chromium; namespace OpenQA.Selenium.Edge { /// - /// Exposes the service provided by the native MicrosoftWebDriver executable. + /// Exposes the service provided by the native WebDriver executable. /// - public sealed class EdgeDriverService : DriverService + public sealed class EdgeDriverService : ChromiumDriverService { private const string MicrosoftWebDriverServiceFileName = "MicrosoftWebDriver.exe"; - private static readonly Uri MicrosoftWebDriverDownloadUrl = new Uri("http://go.microsoft.com/fwlink/?LinkId=619687"); + private static readonly Uri MicrosoftWebDriverDownloadUrl = new Uri("https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/"); private string host; private string package; private bool useVerboseLogging; private bool? useSpecCompliantProtocol; + private const string MSEdgeDriverServiceFileName = "MSEdgeDriver.exe"; + private bool isLegacy; /// /// Initializes a new instance of the class. @@ -41,41 +44,95 @@ public sealed class EdgeDriverService : DriverService /// The full path to the EdgeDriver executable. /// The file name of the EdgeDriver executable. /// The port on which the EdgeDriver executable should listen. - private EdgeDriverService(string executablePath, string executableFileName, int port) - : base(executablePath, port, executableFileName, MicrosoftWebDriverDownloadUrl) + /// Whether to use legacy mode to launch Edge. + private EdgeDriverService(string executablePath, string executableFileName, int port, bool isLegacy) + : base(executablePath, executableFileName, port, MicrosoftWebDriverDownloadUrl) { + this.isLegacy = isLegacy; } /// /// Gets or sets the value of the host adapter on which the Edge driver service should listen for connections. + /// The property only exists in legacy mode. /// public string Host { - get { return this.host; } - set { this.host = value; } + get + { + if (!this.isLegacy) + { + throw new ArgumentException("Host property does not exist"); + } + + return this.host; + } + set + { + if (!this.isLegacy) + { + throw new ArgumentException("Host property does not exist"); + } + + this.host = value; + } } /// /// Gets or sets the value of the package the Edge driver service will launch and automate. + /// The property only exists in legacy mode. /// public string Package { - get { return this.package; } - set { this.package = value; } + get + { + if (!this.isLegacy) + { + throw new ArgumentException("Package property does not exist"); + } + + return this.package; + } + set + { + if (!this.isLegacy) + { + throw new ArgumentException("Package property does not exist"); + } + + this.package = value; + } } /// /// Gets or sets a value indicating whether the service should use verbose logging. + /// The property only exists in legacy mode. /// public bool UseVerboseLogging { - get { return this.useVerboseLogging; } - set { this.useVerboseLogging = value; } + get + { + if (!this.isLegacy) + { + throw new ArgumentException("UseVerboseLogging property does not exist"); + } + + return this.useVerboseLogging; + } + set + { + if (!this.isLegacy) + { + throw new ArgumentException("UseVerboseLogging property does not exist"); + } + + this.useVerboseLogging = value; + } } /// /// Gets or sets a value indicating whether the instance /// should use the a protocol dialect compliant with the W3C WebDriver Specification. + /// The property only exists in legacy mode. /// /// /// Setting this property to a non- value for driver @@ -87,8 +144,24 @@ public bool UseVerboseLogging /// public bool? UseSpecCompliantProtocol { - get { return this.useSpecCompliantProtocol; } - set { this.useSpecCompliantProtocol = value; } + get + { + if (!this.isLegacy) + { + throw new ArgumentException("UseVerboseLogging property does not exist"); + } + + return this.useSpecCompliantProtocol; + } + set + { + if (!this.isLegacy) + { + throw new ArgumentException("UseVerboseLogging property does not exist"); + } + + this.useSpecCompliantProtocol = value; + } } /// @@ -99,7 +172,7 @@ protected override bool HasShutdown { get { - if (this.useSpecCompliantProtocol.HasValue && !this.useSpecCompliantProtocol.Value) + if (!this.isLegacy || (this.useSpecCompliantProtocol.HasValue && !this.useSpecCompliantProtocol.Value)) { return base.HasShutdown; } @@ -119,7 +192,7 @@ protected override TimeSpan TerminationTimeout // gets us to the termination point much faster. get { - if (this.useSpecCompliantProtocol.HasValue && !this.useSpecCompliantProtocol.Value) + if (!this.isLegacy || (this.useSpecCompliantProtocol.HasValue && !this.useSpecCompliantProtocol.Value)) { return base.TerminationTimeout; } @@ -135,6 +208,9 @@ protected override string CommandLineArguments { get { + if (!this.isLegacy) + return base.CommandLineArguments; + StringBuilder argsBuilder = new StringBuilder(base.CommandLineArguments); if (!string.IsNullOrEmpty(this.host)) { @@ -175,11 +251,14 @@ protected override string CommandLineArguments /// /// Creates a default instance of the EdgeDriverService. /// + /// Wheter to use legacy mode. Default is to true. /// A EdgeDriverService that implements default settings. - public static EdgeDriverService CreateDefaultService() + public static EdgeDriverService CreateDefaultService(bool isLegacy = true) { - string serviceDirectory = DriverService.FindDriverServiceExecutable(MicrosoftWebDriverServiceFileName, MicrosoftWebDriverDownloadUrl); - EdgeDriverService service = CreateDefaultService(serviceDirectory); + string serviceDirectory = DriverService.FindDriverServiceExecutable( + isLegacy ? MicrosoftWebDriverServiceFileName : ChromiumDriverServiceFileName(MSEdgeDriverServiceFileName), + MicrosoftWebDriverDownloadUrl); + EdgeDriverService service = CreateDefaultService(serviceDirectory, isLegacy); return service; } @@ -187,21 +266,25 @@ public static EdgeDriverService CreateDefaultService() /// Creates a default instance of the EdgeDriverService using a specified path to the EdgeDriver executable. /// /// The directory containing the EdgeDriver executable. + /// Wheter to use legacy mode. Default is to true. /// A EdgeDriverService using a random port. - public static EdgeDriverService CreateDefaultService(string driverPath) + public static EdgeDriverService CreateDefaultService(string driverPath, bool isLegacy = true) { - return CreateDefaultService(driverPath, MicrosoftWebDriverServiceFileName); + return CreateDefaultService( + driverPath, + isLegacy ? MicrosoftWebDriverServiceFileName : ChromiumDriverServiceFileName(MSEdgeDriverServiceFileName), + isLegacy); } - /// + /// /// Creates a default instance of the EdgeDriverService using a specified path to the EdgeDriver executable with the given name. /// /// The directory containing the EdgeDriver executable. /// The name of the EdgeDriver executable file. /// A EdgeDriverService using a random port. - public static EdgeDriverService CreateDefaultService(string driverPath, string driverExecutableFileName) + public static EdgeDriverService CreateDefaultService(string driverPath, string driverExecutableFileName, bool isLegacy = true) { - return CreateDefaultService(driverPath, driverExecutableFileName, PortUtilities.FindFreePort()); + return CreateDefaultService(driverPath, driverExecutableFileName, PortUtilities.FindFreePort(), isLegacy); } /// @@ -210,10 +293,11 @@ public static EdgeDriverService CreateDefaultService(string driverPath, string d /// The directory containing the EdgeDriver executable. /// The name of the EdgeDriver executable file /// The port number on which the driver will listen + /// Wheter to use legacy mode. Default is to true. /// A EdgeDriverService using the specified port. - public static EdgeDriverService CreateDefaultService(string driverPath, string driverExecutableFileName, int port) + public static EdgeDriverService CreateDefaultService(string driverPath, string driverExecutableFileName, int port, bool isLegacy = true) { - return new EdgeDriverService(driverPath, driverExecutableFileName, port); + return new EdgeDriverService(driverPath, driverExecutableFileName, port, isLegacy); } } } diff --git a/dotnet/src/webdriver/Edge/EdgeOptions.cs b/dotnet/src/webdriver/Edge/EdgeOptions.cs index be2a50e5d7484..377985d9fc2af 100644 --- a/dotnet/src/webdriver/Edge/EdgeOptions.cs +++ b/dotnet/src/webdriver/Edge/EdgeOptions.cs @@ -19,7 +19,7 @@ using System; using System.Collections.Generic; using System.Globalization; -using OpenQA.Selenium.Remote; +using OpenQA.Selenium.Chromium; namespace OpenQA.Selenium.Edge { @@ -43,26 +43,69 @@ namespace OpenQA.Selenium.Edge /// RemoteWebDriver driver = new RemoteWebDriver(new Uri("http://localhost:4444/wd/hub"), options.ToCapabilities()); /// /// - public class EdgeOptions : DriverOptions + public class EdgeOptions : ChromiumOptions { private const string BrowserNameValue = "MicrosoftEdge"; private const string UseInPrivateBrowsingCapability = "ms:inPrivate"; private const string ExtensionPathsCapability = "ms:extensionPaths"; private const string StartPageCapability = "ms:startPage"; + private static readonly string[] ChromiumCapabilityNames = { "goog:chromeOptions", "se:forceAlwaysMatch", "args", + "binary", "extensions", "localState", "prefs", "detach", "debuggerAddress", "excludeSwitches", "minidumpPath", + "mobileEmulation", "perfLoggingPrefs", "windowTypes", "w3c"}; + private bool useInPrivateBrowsing; private string startPage; private List extensionPaths = new List(); + private bool isLegacy; /// /// Initializes a new instance of the class. /// - public EdgeOptions() : base() + public EdgeOptions() : this(true) { - this.BrowserName = BrowserNameValue; - this.AddKnownCapabilityName(UseInPrivateBrowsingCapability, "UseInPrivateBrowsing property"); - this.AddKnownCapabilityName(StartPageCapability, "StartPage property"); - this.AddKnownCapabilityName(ExtensionPathsCapability, "AddExtensionPaths method"); + } + + /// + /// Create an EdgeOption for ChromiumEdge + /// + /// Whether to use Legacy Mode. If so, remove all Chromium Capabilities + public EdgeOptions(bool isLegacy) : base(BrowserNameValue, "") + { + this.isLegacy = isLegacy; + + if (this.isLegacy) + { + foreach (string capabilityName in ChromiumCapabilityNames) + { + this.RemoveKnownCapabilityName(capabilityName); + } + + this.AddKnownCapabilityName(UseInPrivateBrowsingCapability, "UseInPrivateBrowsing property"); + this.AddKnownCapabilityName(StartPageCapability, "StartPage property"); + this.AddKnownCapabilityName(ExtensionPathsCapability, "AddExtensionPaths method"); + } + } + + /// + /// Gets or sets the location of the Chrome browser's binary executable file. + /// + public new string BinaryLocation + { + get + { + if (this.isLegacy) + throw new ArgumentException("BinaryLocation does not exist in Legacy Edge"); + + return base.BinaryLocation; + } + set + { + if (this.isLegacy) + throw new ArgumentException("BinaryLocation does not exist in Legacy Edge"); + + base.BinaryLocation = value; + } } /// @@ -71,8 +114,24 @@ public EdgeOptions() : base() /// public bool UseInPrivateBrowsing { - get { return this.useInPrivateBrowsing; } - set { this.useInPrivateBrowsing = value; } + get + { + if (!this.isLegacy) + { + throw new ArgumentException("UseInPrivateBrowsing property does not exist in Chromium Edge"); + } + + return this.useInPrivateBrowsing; + } + set + { + if (!this.isLegacy) + { + throw new ArgumentException("UseInPrivateBrowsing property does not exist in Chromium Edge"); + } + + this.useInPrivateBrowsing = value; + } } /// @@ -80,8 +139,24 @@ public bool UseInPrivateBrowsing /// public string StartPage { - get { return this.startPage; } - set { this.startPage = value; } + get + { + if (!this.isLegacy) + { + throw new ArgumentException("StartPage property does not exist in Chromium Edge"); + } + + return this.startPage; + } + set + { + if (!this.isLegacy) + { + throw new ArgumentException("StartPage property does not exist in Chromium Edge"); + } + + this.startPage = value; + } } @@ -91,6 +166,11 @@ public string StartPage /// The full path and file name of the extension. public void AddExtensionPath(string extensionPath) { + if (!this.isLegacy) + { + throw new ArgumentException("Property does not exist in Chromium Edge", "extensionPath"); + } + if (string.IsNullOrEmpty(extensionPath)) { throw new ArgumentException("extensionPath must not be null or empty", "extensionPath"); @@ -105,6 +185,11 @@ public void AddExtensionPath(string extensionPath) /// An array of full paths with file names of extensions to add. public void AddExtensionPaths(params string[] extensionPathsToAdd) { + if (!this.isLegacy) + { + throw new ArgumentException("Property does not exist in Chromium Edge", "extensionPathsToAdd"); + } + this.AddExtensionPaths(new List(extensionPathsToAdd)); } @@ -114,6 +199,11 @@ public void AddExtensionPaths(params string[] extensionPathsToAdd) /// An of full paths with file names of extensions to add. public void AddExtensionPaths(IEnumerable extensionPathsToAdd) { + if (!this.isLegacy) + { + throw new ArgumentException("Property does not exist in Chromium Edge", "extensionPathsToAdd"); + } + if (extensionPathsToAdd == null) { throw new ArgumentNullException("extensionPathsToAdd", "extensionPathsToAdd must not be null"); @@ -122,24 +212,6 @@ public void AddExtensionPaths(IEnumerable extensionPathsToAdd) this.extensionPaths.AddRange(extensionPathsToAdd); } - /// - /// Provides a means to add additional capabilities not yet added as type safe options - /// for the Edge driver. - /// - /// The name of the capability to add. - /// The value of the capability to add. - /// - /// thrown when attempting to add a capability for which there is already a type safe option, or - /// when is or the empty string. - /// - /// Calling where - /// has already been added will overwrite the existing value with the new value in - [Obsolete("Use the temporary AddAdditionalOption method for adding additional options")] - public override void AddAdditionalCapability(string capabilityName, object capabilityValue) - { - this.AddAdditionalOption(capabilityName, capabilityValue); - } - /// /// Returns DesiredCapabilities for Edge with these options included as /// capabilities. This copies the options. Further changes will not be @@ -148,6 +220,11 @@ public override void AddAdditionalCapability(string capabilityName, object capab /// The DesiredCapabilities for Edge with these options. public override ICapabilities ToCapabilities() { + if (!this.isLegacy) + { + return base.ToCapabilities(); + } + IWritableCapabilities capabilities = this.GenerateDesiredCapabilities(true); if (this.useInPrivateBrowsing) diff --git a/dotnet/src/webdriver/Edge/EdgeWebElement.cs b/dotnet/src/webdriver/Edge/EdgeWebElement.cs index e1c47b4eeab7a..d413444997780 100644 --- a/dotnet/src/webdriver/Edge/EdgeWebElement.cs +++ b/dotnet/src/webdriver/Edge/EdgeWebElement.cs @@ -1,4 +1,4 @@ -// +// // 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 @@ -16,14 +16,14 @@ // limitations under the License. // -using OpenQA.Selenium.Remote; +using OpenQA.Selenium.Chromium; namespace OpenQA.Selenium.Edge { /// /// Provides a mechanism to get elements off the page for test /// - public class EdgeWebElement : RemoteWebElement + public class EdgeWebElement : ChromiumWebElement { /// /// Initializes a new instance of the class diff --git a/dotnet/test/common/AlertsTest.cs b/dotnet/test/common/AlertsTest.cs index 76bf0288f3bc2..cfdbcaab365c5 100644 --- a/dotnet/test/common/AlertsTest.cs +++ b/dotnet/test/common/AlertsTest.cs @@ -66,6 +66,7 @@ public void ShouldAllowUsersToAcceptAnAlertWithNoTextManually() [Test] [IgnoreBrowser(Browser.Chrome, "This is the correct behavior, for the SwitchTo call to throw if it happens before the setTimeout call occurs in the browser and the alert is displayed.")] + [IgnoreBrowser(Browser.ChromiumEdge, "This is the correct behavior, for the SwitchTo call to throw if it happens before the setTimeout call occurs in the browser and the alert is displayed.")] [IgnoreBrowser(Browser.Edge, "This is the correct behavior, for the SwitchTo call to throw if it happens before the setTimeout call occurs in the browser and the alert is displayed.")] [IgnoreBrowser(Browser.IE, "This is the correct behavior, for the SwitchTo call to throw if it happens before the setTimeout call occurs in the browser and the alert is displayed.")] [IgnoreBrowser(Browser.Firefox, "This is the correct behavior, for the SwitchTo call to throw if it happens before the setTimeout call occurs in the browser and the alert is displayed.")] @@ -401,6 +402,7 @@ public void ShouldHandleAlertOnPageLoadUsingGet() [Test] [IgnoreBrowser(Browser.Chrome, "Test with onLoad alert hangs Chrome.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Test with onLoad alert hangs Edge.")] [IgnoreBrowser(Browser.Safari, "Safari driver does not allow commands in any window when an alert is active")] public void ShouldNotHandleAlertInAnotherWindow() { @@ -447,6 +449,7 @@ public void ShouldNotHandleAlertInAnotherWindow() [Test] [IgnoreBrowser(Browser.Firefox, "After version 27, Firefox does not trigger alerts on unload.")] [IgnoreBrowser(Browser.Chrome, "Chrome does not trigger alerts on unload.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge does not trigger alerts on unload.")] [IgnoreBrowser(Browser.Edge, "Edge does not trigger alerts on unload.")] public void ShouldHandleAlertOnPageUnload() { @@ -471,6 +474,7 @@ public void ShouldHandleAlertOnPageUnload() [Test] [IgnoreBrowser(Browser.Chrome, "Chrome does not implicitly handle onBeforeUnload alert")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge does not implicitly handle onBeforeUnload alert")] [IgnoreBrowser(Browser.Safari, "Safari driver does not implicitly (or otherwise) handle onBeforeUnload alerts")] [IgnoreBrowser(Browser.Edge, "Edge driver does not implicitly (or otherwise) handle onBeforeUnload alerts")] public void ShouldImplicitlyHandleAlertOnPageBeforeUnload() @@ -490,6 +494,7 @@ public void ShouldImplicitlyHandleAlertOnPageBeforeUnload() [Test] [IgnoreBrowser(Browser.IE, "Test as written does not trigger alert; also onbeforeunload alert on close will hang browser")] [IgnoreBrowser(Browser.Chrome, "Test as written does not trigger alert")] + [IgnoreBrowser(Browser.ChromiumEdge, "Test as written does not trigger alert")] [IgnoreBrowser(Browser.Firefox, "After version 27, Firefox does not trigger alerts on unload.")] [IgnoreBrowser(Browser.Edge, "Edge does not trigger alerts on unload.")] public void ShouldHandleAlertOnWindowClose() @@ -525,6 +530,7 @@ public void ShouldHandleAlertOnWindowClose() [Test] [IgnoreBrowser(Browser.Chrome, "Driver chooses not to return text from unhandled alert")] + [IgnoreBrowser(Browser.ChromiumEdge, "Driver chooses not to return text from unhandled alert")] [IgnoreBrowser(Browser.Edge, "Driver chooses not to return text from unhandled alert")] [IgnoreBrowser(Browser.Firefox, "Driver chooses not to return text from unhandled alert")] [IgnoreBrowser(Browser.Opera)] @@ -617,6 +623,7 @@ public void ShouldHandleAlertOnPageBeforeUnloadAlertAtQuit() // Disabling test for all browsers. Authentication API is not supported by any driver yet. // [Test] [IgnoreBrowser(Browser.Chrome)] + [IgnoreBrowser(Browser.ChromiumEdge)] [IgnoreBrowser(Browser.Edge)] [IgnoreBrowser(Browser.Firefox)] [IgnoreBrowser(Browser.IE)] @@ -635,6 +642,7 @@ public void ShouldBeAbleToHandleAuthenticationDialog() // Disabling test for all browsers. Authentication API is not supported by any driver yet. // [Test] [IgnoreBrowser(Browser.Chrome)] + [IgnoreBrowser(Browser.ChromiumEdge)] [IgnoreBrowser(Browser.Edge)] [IgnoreBrowser(Browser.Firefox)] [IgnoreBrowser(Browser.IE)] @@ -651,6 +659,7 @@ public void ShouldBeAbleToDismissAuthenticationDialog() // Disabling test for all browsers. Authentication API is not supported by any driver yet. // [Test] [IgnoreBrowser(Browser.Chrome)] + [IgnoreBrowser(Browser.ChromiumEdge)] [IgnoreBrowser(Browser.Edge)] [IgnoreBrowser(Browser.Firefox)] [IgnoreBrowser(Browser.Opera)] diff --git a/dotnet/test/common/AvailableLogsTest.cs b/dotnet/test/common/AvailableLogsTest.cs index 9f9f21ef46faf..b638122b80db8 100644 --- a/dotnet/test/common/AvailableLogsTest.cs +++ b/dotnet/test/common/AvailableLogsTest.cs @@ -69,6 +69,7 @@ public void ProfilerLogShouldBeDisabledByDefault() //[Test] [IgnoreBrowser(Browser.Chrome, "Chrome does not support profiler logs")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge does not support profiler logs")] public void ShouldBeAbleToEnableProfilerLog() { CreateWebDriverWithProfiling(); diff --git a/dotnet/test/common/Browser.cs b/dotnet/test/common/Browser.cs index 77de8b524b6fc..203abcc7d10f6 100644 --- a/dotnet/test/common/Browser.cs +++ b/dotnet/test/common/Browser.cs @@ -4,6 +4,7 @@ public enum Browser { All, IE, + ChromiumEdge, Edge, Firefox, Safari, diff --git a/dotnet/test/common/ClearTest.cs b/dotnet/test/common/ClearTest.cs index 7377613b5f8f1..123a5d9abf8d2 100644 --- a/dotnet/test/common/ClearTest.cs +++ b/dotnet/test/common/ClearTest.cs @@ -125,6 +125,7 @@ public void ShouldBeAbleToClearRangeInput() [Test] [IgnoreBrowser(Browser.Chrome, "Driver sees checkbox as not editable")] + [IgnoreBrowser(Browser.ChromiumEdge, "Driver sees checkbox as not editable")] [IgnoreBrowser(Browser.Edge, "Driver sees checkbox as not editable")] [IgnoreBrowser(Browser.Firefox, "Driver sees checkbox as not editable")] [IgnoreBrowser(Browser.IE, "Driver sees checkbox as not editable")] diff --git a/dotnet/test/common/ClickScrollingTest.cs b/dotnet/test/common/ClickScrollingTest.cs index 9c401822ca5cb..eeb195d277911 100644 --- a/dotnet/test/common/ClickScrollingTest.cs +++ b/dotnet/test/common/ClickScrollingTest.cs @@ -95,6 +95,7 @@ public void ShouldNotScrollOverflowElementsWhichAreVisible() [Test] [IgnoreBrowser(Browser.Chrome, "Webkit-based browsers apparently scroll anyway.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Webkit-based browsers apparently scroll anyway.")] public void ShouldNotScrollIfAlreadyScrolledAndElementIsInView() { driver.Url = EnvironmentManager.Instance.UrlBuilder.WhereIs("scroll3.html"); diff --git a/dotnet/test/common/ClickTest.cs b/dotnet/test/common/ClickTest.cs index 3c8193a81070c..89e1e4c43f67e 100644 --- a/dotnet/test/common/ClickTest.cs +++ b/dotnet/test/common/ClickTest.cs @@ -340,6 +340,7 @@ public void ShouldBeAbleToClickOnASpanThatWrapsToTheNextLine() [Test] [IgnoreBrowser(Browser.IE, "Element is properly seen as obscured.")] [IgnoreBrowser(Browser.Chrome, "Element is properly seen as obscured.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Element is properly seen as obscured.")] [IgnoreBrowser(Browser.Edge, "Element is properly seen as obscured.")] [IgnoreBrowser(Browser.Firefox, "Element is properly seen as obscured.")] [IgnoreBrowser(Browser.Safari, "Element is properly seen as obscured.")] diff --git a/dotnet/test/common/ContentEditableTest.cs b/dotnet/test/common/ContentEditableTest.cs index 453fbfd104c1d..135681cbe6c65 100644 --- a/dotnet/test/common/ContentEditableTest.cs +++ b/dotnet/test/common/ContentEditableTest.cs @@ -64,6 +64,7 @@ public void ShouldBeAbleToTypeIntoEmptyContentEditableElement() [Test] [IgnoreBrowser(Browser.Chrome, "Driver prepends text in contentEditable areas")] + [IgnoreBrowser(Browser.ChromiumEdge, "Driver prepends text in contentEditable areas")] [IgnoreBrowser(Browser.Firefox, "Driver prepends text in contentEditable areas")] [IgnoreBrowser(Browser.Safari, "Driver prepends text to contentEditable areas")] public void ShouldBeAbleToTypeIntoContentEditableElementWithExistingValue() @@ -93,6 +94,7 @@ public void ShouldBeAbleToTypeIntoTinyMCE() [Test] [IgnoreBrowser(Browser.Chrome, "Driver prepends text in contentEditable areas")] + [IgnoreBrowser(Browser.ChromiumEdge, "Driver prepends text in contentEditable areas")] [IgnoreBrowser(Browser.Firefox, "Driver prepends text in contentEditable areas")] [IgnoreBrowser(Browser.IE, "Prepends text")] [IgnoreBrowser(Browser.Safari, "Driver prepends text to contentEditable areas")] @@ -111,6 +113,7 @@ public void ShouldAppendToTinyMCE() [Test] [IgnoreBrowser(Browser.Chrome, "Driver prepends text in contentEditable areas")] + [IgnoreBrowser(Browser.ChromiumEdge, "Driver prepends text in contentEditable areas")] [IgnoreBrowser(Browser.Firefox, "Browser does not automatically focus body element in frame")] [IgnoreBrowser(Browser.Safari, "Driver prepends text to contentEditable areas")] public void AppendsTextToEndOfContentEditableWithMultipleTextNodes() diff --git a/dotnet/test/common/CookieImplementationTest.cs b/dotnet/test/common/CookieImplementationTest.cs index 7a56cbd58e3c8..64bcbdad7d808 100644 --- a/dotnet/test/common/CookieImplementationTest.cs +++ b/dotnet/test/common/CookieImplementationTest.cs @@ -181,6 +181,7 @@ public void AddCookiesWithDifferentPathsThatAreRelatedToOurs() [Test] [IgnoreBrowser(Browser.Chrome, "Chrome does not retrieve cookies when in frame.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge does not retrieve cookies when in frame.")] public void GetCookiesInAFrame() { driver.Url = EnvironmentManager.Instance.UrlBuilder.WhereIs("animals"); diff --git a/dotnet/test/common/CorrectEventFiringTest.cs b/dotnet/test/common/CorrectEventFiringTest.cs index 1234d22398a4a..d4f8fd2514219 100644 --- a/dotnet/test/common/CorrectEventFiringTest.cs +++ b/dotnet/test/common/CorrectEventFiringTest.cs @@ -462,6 +462,7 @@ public void ClickOverlappingElements() [Test] [IgnoreBrowser(Browser.Chrome, "Driver checks for overlapping elements")] + [IgnoreBrowser(Browser.ChromiumEdge, "Driver checks for overlapping elements")] [IgnoreBrowser(Browser.Edge, "Driver checks for overlapping elements")] [IgnoreBrowser(Browser.Firefox, "Driver checks for overlapping elements")] [IgnoreBrowser(Browser.IE, "Driver checks for overlapping elements")] @@ -494,6 +495,7 @@ public void ClickPartiallyOverlappingElements() [Test] [IgnoreBrowser(Browser.Chrome, "Driver checks for overlapping elements")] + [IgnoreBrowser(Browser.ChromiumEdge, "Driver checks for overlapping elements")] [IgnoreBrowser(Browser.Edge, "Driver checks for overlapping elements")] [IgnoreBrowser(Browser.Firefox, "Driver checks for overlapping elements")] [IgnoreBrowser(Browser.IE, "Driver checks for overlapping elements")] diff --git a/dotnet/test/common/CustomTestAttributes/IgnoreBrowserAttribute.cs b/dotnet/test/common/CustomTestAttributes/IgnoreBrowserAttribute.cs index 27e9afc64c107..e6cd046a41b42 100644 --- a/dotnet/test/common/CustomTestAttributes/IgnoreBrowserAttribute.cs +++ b/dotnet/test/common/CustomTestAttributes/IgnoreBrowserAttribute.cs @@ -104,6 +104,12 @@ private bool IsRemoteInstanceOfBrowser(Browser desiredBrowser) isRemoteInstance = true; } break; + case Browser.ChromiumEdge: + if (EnvironmentManager.Instance.RemoteCapabilities == "MicrosoftEdge") + { + isRemoteInstance = true; + } + break; } return isRemoteInstance; } diff --git a/dotnet/test/common/ElementFindingTest.cs b/dotnet/test/common/ElementFindingTest.cs index 16d12a4585bfb..9147413fe6614 100644 --- a/dotnet/test/common/ElementFindingTest.cs +++ b/dotnet/test/common/ElementFindingTest.cs @@ -360,6 +360,7 @@ public void FindingASingleElementByInvalidClassNameShouldThrow() [IgnoreBrowser(Browser.Edge, "Class name is perfectly legal when using CSS selector, if properly escaped.")] [IgnoreBrowser(Browser.Safari, "Class name is perfectly legal when using CSS selector, if properly escaped.")] [IgnoreBrowser(Browser.Chrome, "Class name is perfectly legal when using CSS selector, if properly escaped.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Class name is perfectly legal when using CSS selector, if properly escaped.")] [IgnoreBrowser(Browser.Opera, "Throws WebDriverException")] public void FindingMultipleElementsByInvalidClassNameShouldThrow() { @@ -445,6 +446,7 @@ public void ShouldBeAbleToFindElementByXPathWithNamespace() [Test] [IgnoreBrowser(Browser.IE, "Driver does not support finding elements on XML documents.")] [IgnoreBrowser(Browser.Chrome, "Driver does not support finding elements on XML documents.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Driver does not support finding elements on XML documents.")] [IgnoreBrowser(Browser.Edge, "Driver does not support finding elements on XML documents.")] [IgnoreBrowser(Browser.Safari, "Not yet implemented")] public void ShouldBeAbleToFindElementByXPathInXmlDocument() diff --git a/dotnet/test/common/Environment/DriverFactory.cs b/dotnet/test/common/Environment/DriverFactory.cs index 978423ae17ecd..70ed0a91c00cd 100644 --- a/dotnet/test/common/Environment/DriverFactory.cs +++ b/dotnet/test/common/Environment/DriverFactory.cs @@ -39,6 +39,7 @@ private void PopulateOptionsTypes() { this.optionsTypes[Browser.Chrome] = typeof(ChromeOptions); this.optionsTypes[Browser.Edge] = typeof(EdgeOptions); + this.optionsTypes[Browser.ChromiumEdge] = typeof(EdgeOptions); this.optionsTypes[Browser.Firefox] = typeof(FirefoxOptions); this.optionsTypes[Browser.IE] = typeof(InternetExplorerOptions); this.optionsTypes[Browser.Opera] = typeof(OperaOptions); @@ -49,6 +50,7 @@ private void PopulateServiceTypes() { this.serviceTypes[Browser.Chrome] = typeof(ChromeDriverService); this.serviceTypes[Browser.Edge] = typeof(EdgeDriverService); + this.serviceTypes[Browser.ChromiumEdge] = typeof(EdgeDriverService); this.serviceTypes[Browser.Firefox] = typeof(FirefoxDriverService); this.serviceTypes[Browser.IE] = typeof(InternetExplorerDriverService); this.serviceTypes[Browser.Opera] = typeof(OperaDriverService); diff --git a/dotnet/test/common/ExecutingAsyncJavascriptTest.cs b/dotnet/test/common/ExecutingAsyncJavascriptTest.cs index b20067963045f..5aa4520813bc2 100644 --- a/dotnet/test/common/ExecutingAsyncJavascriptTest.cs +++ b/dotnet/test/common/ExecutingAsyncJavascriptTest.cs @@ -194,6 +194,7 @@ public void ShouldNotTimeoutWithMultipleCallsTheFirstOneBeingSynchronous() [Test] [IgnoreBrowser(Browser.Chrome, ".NET language bindings do not properly parse JavaScript stack trace")] + [IgnoreBrowser(Browser.ChromiumEdge, ".NET language bindings do not properly parse JavaScript stack trace")] [IgnoreBrowser(Browser.Firefox, ".NET language bindings do not properly parse JavaScript stack trace")] [IgnoreBrowser(Browser.IE, ".NET language bindings do not properly parse JavaScript stack trace")] [IgnoreBrowser(Browser.Edge, ".NET language bindings do not properly parse JavaScript stack trace")] @@ -339,6 +340,7 @@ public void ThrowsIfAlertHappensDuringScriptWhichTimesOut() [Test] [IgnoreBrowser(Browser.Chrome, "Driver chooses not to return text from unhandled alert")] + [IgnoreBrowser(Browser.ChromiumEdge, "Driver chooses not to return text from unhandled alert")] [IgnoreBrowser(Browser.Edge, "Driver chooses not to return text from unhandled alert")] [IgnoreBrowser(Browser.Firefox, "Driver chooses not to return text from unhandled alert")] [IgnoreBrowser(Browser.Safari, "Does not alerts thrown during async JavaScript; driver hangs until alert dismissed")] diff --git a/dotnet/test/common/ExecutingJavascriptTest.cs b/dotnet/test/common/ExecutingJavascriptTest.cs index d0a48fd79b232..e03de1f83b12d 100644 --- a/dotnet/test/common/ExecutingJavascriptTest.cs +++ b/dotnet/test/common/ExecutingJavascriptTest.cs @@ -226,6 +226,7 @@ public void ShouldThrowAnExceptionWhenTheJavascriptIsBad() [Test] [IgnoreBrowser(Browser.Chrome, ".NET language bindings do not properly parse JavaScript stack trace")] + [IgnoreBrowser(Browser.ChromiumEdge, ".NET language bindings do not properly parse JavaScript stack trace")] [IgnoreBrowser(Browser.Firefox, ".NET language bindings do not properly parse JavaScript stack trace")] [IgnoreBrowser(Browser.IE, ".NET language bindings do not properly parse JavaScript stack trace")] [IgnoreBrowser(Browser.Edge, ".NET language bindings do not properly parse JavaScript stack trace")] @@ -526,6 +527,7 @@ public void ShouldThrowAnExceptionWhenArgumentsWithStaleElementPassed() [Test] [IgnoreBrowser(Browser.Chrome, "Browser does not return Date object.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Browser does not return Date object.")] public void ShouldBeAbleToReturnADateObject() { driver.Url = simpleTestPage; @@ -536,6 +538,7 @@ public void ShouldBeAbleToReturnADateObject() [Test] [IgnoreBrowser(Browser.Chrome, "Driver returns object that allows getting text.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Driver returns object that allows getting text.")] [IgnoreBrowser(Browser.Firefox, "Driver does not return the documentElement object.")] [IgnoreBrowser(Browser.IE, "Driver does not return the documentElement object.")] [IgnoreBrowser(Browser.Safari, "Driver does not return the documentElement object.")] diff --git a/dotnet/test/common/FrameSwitchingTest.cs b/dotnet/test/common/FrameSwitchingTest.cs index d3575d55ad898..0da721ab18e57 100644 --- a/dotnet/test/common/FrameSwitchingTest.cs +++ b/dotnet/test/common/FrameSwitchingTest.cs @@ -448,6 +448,7 @@ public void ShouldBeAbleToSwitchToTheTopIfTheFrameIsDeletedFromUnderUsWithWebele [Test] [IgnoreBrowser(Browser.Chrome, "Chrome driver throws NoSuchElementException, spec is unclear")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge driver throws NoSuchElementException, spec is unclear")] [IgnoreBrowser(Browser.Firefox, "Marionette throws 'Cannot access dead object' in subsequent tests when frame is deleted")] [IgnoreBrowser(Browser.IE, "IE driver throws NoSuchElementException, spec is unclear")] public void ShouldNotBeAbleToDoAnythingTheFrameIsDeletedFromUnderUs() diff --git a/dotnet/test/common/HTML5/LocationContextTest.cs b/dotnet/test/common/HTML5/LocationContextTest.cs index 197035ec49aa8..b846d628bae6a 100644 --- a/dotnet/test/common/HTML5/LocationContextTest.cs +++ b/dotnet/test/common/HTML5/LocationContextTest.cs @@ -9,6 +9,7 @@ public class LocationContextTest : DriverTestFixture [IgnoreBrowser(Browser.Edge, "Driver incorrectly reports location capability")] [IgnoreBrowser(Browser.Firefox, "Firefox driver incorrectly reports capability of geolocation.")] [IgnoreBrowser(Browser.Chrome, "Chrome driver does not support setting altitude value.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge driver does not support setting altitude value.")] public void ShouldSetAndGetLocation() { driver.Url = html5Page; diff --git a/dotnet/test/common/I18Test.cs b/dotnet/test/common/I18Test.cs index 908805942739b..5c5d88531e378 100644 --- a/dotnet/test/common/I18Test.cs +++ b/dotnet/test/common/I18Test.cs @@ -46,6 +46,7 @@ public void ShouldBeAbleToEnterHebrewTextFromRightToLeft() [Test] [IgnoreBrowser(Browser.Chrome, "ChromeDriver only supports characters in the BMP")] + [IgnoreBrowser(Browser.ChromiumEdge, "EdgeDriver only supports characters in the BMP")] public void ShouldBeAbleToEnterSupplementaryCharacters() { if (TestUtilities.IsOldIE(driver)) diff --git a/dotnet/test/common/Interactions/BasicMouseInterfaceTest.cs b/dotnet/test/common/Interactions/BasicMouseInterfaceTest.cs index 88d67392c4c3c..01b163ae0dbb5 100644 --- a/dotnet/test/common/Interactions/BasicMouseInterfaceTest.cs +++ b/dotnet/test/common/Interactions/BasicMouseInterfaceTest.cs @@ -144,6 +144,7 @@ public void ShouldNotMoveToANullLocator() [Test] [IgnoreBrowser(Browser.Chrome, "Drivers correctly click at current mouse position without another move, preserving mouse position.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Drivers correctly click at current mouse position without another move, preserving mouse position.")] [IgnoreBrowser(Browser.Edge, "Drivers correctly click at current mouse position without another move, preserving mouse position.")] [IgnoreBrowser(Browser.Firefox, "Drivers correctly click at current mouse position without another move, preserving mouse position.")] [IgnoreBrowser(Browser.IE, "Drivers correctly click at current mouse position without another move, preserving mouse position.")] @@ -180,6 +181,7 @@ public void MovingIntoAnImageEnclosedInALink() [Test] [IgnoreBrowser(Browser.Chrome, "Moving outside of view port throws exception in spec-compliant driver")] + [IgnoreBrowser(Browser.ChromiumEdge, "Moving outside of view port throws exception in spec-compliant driver")] [IgnoreBrowser(Browser.Edge, "Moving outside of view port throws exception in spec-compliant driver")] [IgnoreBrowser(Browser.Firefox, "Moving outside of view port throws exception in spec-compliant driver")] [IgnoreBrowser(Browser.IE, "Moving outside of view port throws exception in spec-compliant driver")] diff --git a/dotnet/test/common/MiscTest.cs b/dotnet/test/common/MiscTest.cs index 6b9ee9af4d0a0..42f280cb6a149 100644 --- a/dotnet/test/common/MiscTest.cs +++ b/dotnet/test/common/MiscTest.cs @@ -55,6 +55,7 @@ public void ShouldReturnTheSourceOfAPage() [Test] [IgnoreBrowser(Browser.Chrome, "returns XML content formatted for display as HTML document")] + [IgnoreBrowser(Browser.ChromiumEdge, "returns XML content formatted for display as HTML document")] [IgnoreBrowser(Browser.Safari, "returns XML content formatted for display as HTML document")] [IgnoreBrowser(Browser.IE, "returns XML content formatted for display as HTML document")] [IgnoreBrowser(Browser.Edge, "returns XML content formatted for display as HTML document")] diff --git a/dotnet/test/common/PageLoadingTest.cs b/dotnet/test/common/PageLoadingTest.cs index 1ea64aa4a835a..d45392762d704 100644 --- a/dotnet/test/common/PageLoadingTest.cs +++ b/dotnet/test/common/PageLoadingTest.cs @@ -65,6 +65,7 @@ public void NoneStrategyShouldNotWaitForPageToRefresh() [Test] [IgnoreBrowser(Browser.Chrome, "Chrome driver does not support eager page load strategy")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge driver does not support eager page load strategy")] public void EagerStrategyShouldNotWaitForResources() { InitLocalDriver(PageLoadStrategy.Eager); @@ -86,6 +87,7 @@ public void EagerStrategyShouldNotWaitForResources() [Test] [IgnoreBrowser(Browser.Chrome, "Chrome driver does not support eager page load strategy")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge driver does not support eager page load strategy")] public void EagerStrategyShouldNotWaitForResourcesOnRefresh() { InitLocalDriver(PageLoadStrategy.Eager); @@ -112,6 +114,7 @@ public void EagerStrategyShouldNotWaitForResourcesOnRefresh() [Test] [IgnoreBrowser(Browser.Chrome, "Chrome driver does not support eager page load strategy")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge driver does not support eager page load strategy")] public void EagerStrategyShouldWaitForDocumentToBeLoaded() { InitLocalDriver(PageLoadStrategy.Eager); @@ -415,6 +418,7 @@ public void ShouldTimeoutIfAPageTakesTooLongToRefresh() [Test] [IgnoreBrowser(Browser.Edge, "Test hangs browser.")] [IgnoreBrowser(Browser.Chrome, "Chrome driver does, in fact, stop loading page after a timeout.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge driver does, in fact, stop loading page after a timeout.")] [IgnoreBrowser(Browser.Opera, "Not implemented for browser")] [IgnoreBrowser(Browser.Safari, "Safari behaves correctly with page load timeout, but getting text does not propertly trim, leading to a test run time of over 30 seconds")] [NeedsFreshDriver(IsCreatedAfterTest = true)] diff --git a/dotnet/test/common/SvgDocumentTest.cs b/dotnet/test/common/SvgDocumentTest.cs index 7b072c4b95605..c1bee8ac30fcf 100644 --- a/dotnet/test/common/SvgDocumentTest.cs +++ b/dotnet/test/common/SvgDocumentTest.cs @@ -8,6 +8,7 @@ public class SvgDocumentTest : DriverTestFixture [Test] [IgnoreBrowser(Browser.Opera, "Not tested")] [IgnoreBrowser(Browser.Chrome, "Chrome driver does not support clicking on SVG element yet")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge driver does not support clicking on SVG element yet")] public void ClickOnSvgElement() { if (TestUtilities.IsOldIE(driver)) diff --git a/dotnet/test/common/TakesScreenshotTest.cs b/dotnet/test/common/TakesScreenshotTest.cs index 62d3bd844a28d..05e592df95560 100644 --- a/dotnet/test/common/TakesScreenshotTest.cs +++ b/dotnet/test/common/TakesScreenshotTest.cs @@ -113,6 +113,7 @@ public void ShouldTakeScreenshotsOfAnElement() [Test] [IgnoreBrowser(Browser.Chrome, "Chrome driver only captures visible viewport.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge driver only captures visible viewport.")] [IgnoreBrowser(Browser.Firefox, "Firfox driver only captures visible viewport.")] [IgnoreBrowser(Browser.IE, "IE driver only captures visible viewport.")] [IgnoreBrowser(Browser.Edge, "Edge driver only captures visible viewport.")] @@ -142,6 +143,7 @@ public void ShouldCaptureScreenshotOfPageWithLongX() [Test] [IgnoreBrowser(Browser.Chrome, "Chrome driver only captures visible viewport.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge driver only captures visible viewport.")] [IgnoreBrowser(Browser.Firefox, "Firfox driver only captures visible viewport.")] [IgnoreBrowser(Browser.IE, "IE driver only captures visible viewport.")] [IgnoreBrowser(Browser.Edge, "Edge driver only captures visible viewport.")] @@ -170,6 +172,7 @@ public void ShouldCaptureScreenshotOfPageWithLongY() [Test] [IgnoreBrowser(Browser.Chrome, "Chrome driver only captures visible viewport.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge driver only captures visible viewport.")] [IgnoreBrowser(Browser.Firefox, "Firfox driver only captures visible viewport.")] [IgnoreBrowser(Browser.IE, "IE driver only captures visible viewport.")] [IgnoreBrowser(Browser.Edge, "Edge driver only captures visible viewport.")] @@ -198,6 +201,7 @@ public void ShouldCaptureScreenshotOfPageWithTooLongX() [Test] [IgnoreBrowser(Browser.Chrome, "Chrome driver only captures visible viewport.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge driver only captures visible viewport.")] [IgnoreBrowser(Browser.Firefox, "Firfox driver only captures visible viewport.")] [IgnoreBrowser(Browser.IE, "IE driver only captures visible viewport.")] [IgnoreBrowser(Browser.Edge, "Edge driver only captures visible viewport.")] @@ -226,6 +230,7 @@ public void ShouldCaptureScreenshotOfPageWithTooLongY() [Test] [IgnoreBrowser(Browser.Chrome, "Chrome driver only captures visible viewport.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge driver only captures visible viewport.")] [IgnoreBrowser(Browser.Firefox, "Firfox driver only captures visible viewport.")] [IgnoreBrowser(Browser.IE, "IE driver only captures visible viewport.")] [IgnoreBrowser(Browser.Edge, "Edge driver only captures visible viewport.")] diff --git a/dotnet/test/common/TextPagesTest.cs b/dotnet/test/common/TextPagesTest.cs index e2fe85fe4bc70..4be979ba6ce88 100644 --- a/dotnet/test/common/TextPagesTest.cs +++ b/dotnet/test/common/TextPagesTest.cs @@ -19,6 +19,7 @@ public void ShouldBeAbleToLoadASimplePageOfText() [Test] [IgnoreBrowser(Browser.IE, "IE allows addition of cookie on text pages")] [IgnoreBrowser(Browser.Chrome, "Chrome allows addition of cookie on text pages")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge allows addition of cookie on text pages")] [IgnoreBrowser(Browser.Firefox, "Firefox allows addition of cookie on text pages")] [IgnoreBrowser(Browser.Edge, "Edge allows addition of cookie on text pages")] [IgnoreBrowser(Browser.Safari, "Safari allows addition of cookie on text pages")] diff --git a/dotnet/test/common/TypingTest.cs b/dotnet/test/common/TypingTest.cs index a6e4a1b46b30b..53bab87465968 100644 --- a/dotnet/test/common/TypingTest.cs +++ b/dotnet/test/common/TypingTest.cs @@ -715,6 +715,7 @@ public void ShouldBeAbleToTypeIntoEmptyContentEditableElement() [Test] [IgnoreBrowser(Browser.Chrome, "Driver prepends text in contentEditable")] + [IgnoreBrowser(Browser.ChromiumEdge, "Driver prepends text in contentEditable")] [IgnoreBrowser(Browser.Firefox, "Driver prepends text in contentEditable")] public void ShouldBeAbleToTypeIntoContentEditableElementWithExistingValue() { diff --git a/dotnet/test/common/UploadTest.cs b/dotnet/test/common/UploadTest.cs index 7fbf01c8c53a6..3bf4164ab30ce 100644 --- a/dotnet/test/common/UploadTest.cs +++ b/dotnet/test/common/UploadTest.cs @@ -57,6 +57,7 @@ public void CleanFileInput() [Test] [IgnoreBrowser(Browser.Chrome, "Chrome driver does not throw exception.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge driver does not throw exception.")] public void ClickFileInput() { driver.Url = uploadPage; diff --git a/dotnet/test/common/WindowSwitchingTest.cs b/dotnet/test/common/WindowSwitchingTest.cs index 6045c20e2e6a3..b977ea3fb85b4 100644 --- a/dotnet/test/common/WindowSwitchingTest.cs +++ b/dotnet/test/common/WindowSwitchingTest.cs @@ -426,6 +426,7 @@ public void CloseShouldCloseCurrentHandleOnly() [Test] [IgnoreBrowser(Browser.Chrome, "Driver does not yet support new window command")] + [IgnoreBrowser(Browser.ChromiumEdge, "Driver does not yet support new window command")] [IgnoreBrowser(Browser.Edge, "Driver does not yet support new window command")] public void ShouldBeAbleToCreateANewWindow() { diff --git a/dotnet/test/common/WindowTest.cs b/dotnet/test/common/WindowTest.cs index cf079701b0131..461eb049dda25 100644 --- a/dotnet/test/common/WindowTest.cs +++ b/dotnet/test/common/WindowTest.cs @@ -200,6 +200,7 @@ public void ShouldBeAbleToFullScreenTheCurrentWindow() [Test] [IgnoreBrowser(Browser.Chrome, "Chrome window size does not report zero when minimized.")] + [IgnoreBrowser(Browser.ChromiumEdge, "Edge window size does not report zero when minimized.")] [IgnoreBrowser(Browser.Opera, "Not implemented in driver")] public void ShouldBeAbleToMinimizeTheCurrentWindow() { diff --git a/dotnet/test/common/appconfig.json b/dotnet/test/common/appconfig.json index 8125146733e56..bd490ef82028e 100644 --- a/dotnet/test/common/appconfig.json +++ b/dotnet/test/common/appconfig.json @@ -61,6 +61,13 @@ "RemoteCapabilities": "MicrosoftEdge" }, + "ChromiumEdgeSpec": { + "DriverTypeName": "OpenQA.Selenium.Edge.ChromiumEdgeDriver", + "AssemblyName": "WebDriver.Edge.Tests", + "BrowserValue": "ChromiumEdge", + "RemoteCapabilities": "MicrosoftEdge" + }, + "Firefox": { "DriverTypeName": "OpenQA.Selenium.Firefox.ReleaseFirefoxWebDriver", "AssemblyName": "WebDriver.Firefox.Tests", diff --git a/dotnet/test/edge/ChromiumEdgeDriver.cs b/dotnet/test/edge/ChromiumEdgeDriver.cs new file mode 100644 index 0000000000000..870221d00a37c --- /dev/null +++ b/dotnet/test/edge/ChromiumEdgeDriver.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OpenQA.Selenium.Edge +{ + public class ChromiumEdgeDriver : EdgeDriver + { + public ChromiumEdgeDriver() + : this(DefaultService, DefaultOptions) + { + } + + public ChromiumEdgeDriver(EdgeDriverService service, EdgeOptions options) + : base(service, options) + { + } + + public static EdgeOptions DefaultOptions + { + get { return new EdgeOptions(false) { UseSpecCompliantProtocol = true }; } + } + + public static EdgeDriverService DefaultService + { + get + { + EdgeDriverService service = EdgeDriverService.CreateDefaultService(false); + return service; + } + } + } +}