Skip to content

Commit

Permalink
Refactoring .NET capability handling
Browse files Browse the repository at this point in the history
This commit introduces a large, and intrusive refactor of the .NET
bindings' capability handling. It introduces a new class,
`RemoteSessionSettings`, for use with creating remote sessions via
`RemoteWebDriver`. Additionally, the `DesiredCapabilities` class is now
marked as deprecated and will generate a compile warning on its use.

The RemoteSessionSettings class is designed for use cases where the user
wants to create a remote session using RemoteWebDriver where all of the
nodes in the session creation support the W3C WebDriver Specification
dialect of the wire protocol. This class is designed to be used in
conjunction with the browser-specific driver options classes for matching
capabilities on the remote end.

For single-browser cases, it is still possible (though unnecessary) to
use a browser-specific driver options class (`ChromeOptions`,
`FirefoxOptions`, etc.) by calling the `ToCapabilities()` method, but
the capabilities returned are now read-only, and cannot be added to.
Users who feel the need to modify the options class after converting to
capabilities are encouraged to add the additional capabilites to the
options class before the conversion by appropriate use of the
`AddAdditionalCapability` method.
  • Loading branch information
jimevans committed Jul 1, 2018
1 parent 18f9b95 commit 0b310c1
Show file tree
Hide file tree
Showing 17 changed files with 1,015 additions and 107 deletions.
2 changes: 1 addition & 1 deletion dotnet/src/webdriver/Chrome/ChromeOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ public override ICapabilities ToCapabilities()
capabilities.SetCapability(pair.Key, pair.Value);
}

return capabilities;
return capabilities.AsReadOnly();
}

private Dictionary<string, object> BuildChromeOptionsDictionary()
Expand Down
96 changes: 93 additions & 3 deletions dotnet/src/webdriver/DriverOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
// limitations under the License.
// </copyright>

using Newtonsoft.Json;
using OpenQA.Selenium.Internal;
using OpenQA.Selenium.Remote;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -195,13 +197,67 @@ public Proxy Proxy
public abstract void AddAdditionalCapability(string capabilityName, object capabilityValue);

/// <summary>
/// Returns DesiredCapabilities for the specific browser driver with these
/// options included ascapabilities. This does not copy the options. Further
/// Returns the <see cref="ICapabilities"/> for the specific browser driver with these
/// options included as capabilities. This does not copy the options. Further
/// changes will be reflected in the returned capabilities.
/// </summary>
/// <returns>The DesiredCapabilities for browser driver with these options.</returns>
/// <returns>The <see cref="ICapabilities"/> for browser driver with these options.</returns>
public abstract ICapabilities ToCapabilities();

/// <summary>
/// Compares this <see cref="DriverOptions"/> object with another to see if there
/// are merge conflicts between them.
/// </summary>
/// <param name="other">The <see cref="DriverOptions"/> object to compare with.</param>
/// <returns>A <see cref="DriverOptionsMergeResult"/> object containing the status of the attempted merge.</returns>
public virtual DriverOptionsMergeResult GetMergeResult(DriverOptions other)
{
DriverOptionsMergeResult result = new DriverOptionsMergeResult();
if (this.browserName != null && other.BrowserName != null)
{
result.IsMergeConflict = true;
result.MergeConflictOptionName = "BrowserName";
return result;
}

if (this.browserVersion != null && other.BrowserVersion != null)
{
result.IsMergeConflict = true;
result.MergeConflictOptionName = "BrowserVersion";
return result;
}

if (this.platformName != null && other.PlatformName != null)
{
result.IsMergeConflict = true;
result.MergeConflictOptionName = "PlatformName";
return result;
}

if (this.proxy != null && other.Proxy != null)
{
result.IsMergeConflict = true;
result.MergeConflictOptionName = "Proxy";
return result;
}

if (this.unhandledPromptBehavior != UnhandledPromptBehavior.Default && other.UnhandledPromptBehavior != UnhandledPromptBehavior.Default)
{
result.IsMergeConflict = true;
result.MergeConflictOptionName = "UnhandledPromptBehavior";
return result;
}

if (this.pageLoadStrategy != PageLoadStrategy.Default && other.PageLoadStrategy != PageLoadStrategy.Default)
{
result.IsMergeConflict = true;
result.MergeConflictOptionName = "PageLoadStrategy";
return result;
}

return result;
}

/// <summary>
/// Sets the logging preferences for this driver.
/// </summary>
Expand All @@ -213,6 +269,25 @@ public void SetLoggingPreference(string logType, LogLevel logLevel)
this.loggingPreferences[logType] = logLevel;
}

/// <summary>
/// Returns a string representation of this <see cref="DriverOptions"/>.
/// </summary>
/// <returns>A string representation of this <see cref="DriverOptions"/>.</returns>
public override string ToString()
{
return JsonConvert.SerializeObject(this.ToDictionary(), Formatting.Indented);
}

/// <summary>
/// Returns the current options as a <see cref="Dictionary{TKey, TValue}"/>.
/// </summary>
/// <returns>The current options as a <see cref="Dictionary{TKey, TValue}"/>.</returns>
internal Dictionary<string, object> ToDictionary()
{
IHasCapabilitiesDictionary desired = this.ToCapabilities() as IHasCapabilitiesDictionary;
return desired.CapabilitiesDictionary;
}

/// <summary>
/// Adds a known capability to the list of known capabilities and associates it
/// with the type-safe property name of the options class to be used instead.
Expand All @@ -224,11 +299,21 @@ protected void AddKnownCapabilityName(string capabilityName, string typeSafeOpti
this.knownCapabilityNames[capabilityName] = typeSafeOptionName;
}

/// <summary>
/// Gets a value indicating whether the specified capability name is a known capability name which has a type-safe option.
/// </summary>
/// <param name="capabilityName">The name of the capability to check.</param>
/// <returns><see langword="true"/> if the capability name is known; otherwise <see langword="false"/>.</returns>
protected bool IsKnownCapabilityName(string capabilityName)
{
return this.knownCapabilityNames.ContainsKey(capabilityName);
}

/// <summary>
/// Gets the name of the type-safe option for a given capability name.
/// </summary>
/// <param name="capabilityName">The name of the capability to check.</param>
/// <returns>The name of the type-safe option for the given capability name.</returns>
protected string GetTypeSafeOptionName(string capabilityName)
{
if (this.IsKnownCapabilityName(capabilityName))
Expand Down Expand Up @@ -259,6 +344,11 @@ protected string GetTypeSafeOptionName(string capabilityName)
return loggingPreferenceCapability;
}

/// <summary>
/// Generates the current options as a capabilities object for further processing.
/// </summary>
/// <param name="isSpecificationCompliant">A value indicating whether to generate capabilities compliant with the W3C WebDriver Specification.</param>
/// <returns>A <see cref="DesiredCapabilities"/> object representing the current options for further processing.</returns>
protected DesiredCapabilities GenerateDesiredCapabilities(bool isSpecificationCompliant)
{
DesiredCapabilities capabilities = new DesiredCapabilities();
Expand Down
20 changes: 20 additions & 0 deletions dotnet/src/webdriver/DriverOptionsMergeResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OpenQA.Selenium.Remote
{
public class DriverOptionsMergeResult
{
/// <summary>
/// Gets or sets a value indicating whether the DriverOptions would conflict when merged with another option
/// </summary>
public bool IsMergeConflict { get; set; }

/// <summary>
/// Gets or sets the name of the name of the option that is in conflict.
/// </summary>
public string MergeConflictOptionName { get; set; }
}
}
2 changes: 1 addition & 1 deletion dotnet/src/webdriver/Edge/EdgeOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ public override ICapabilities ToCapabilities()
capabilities.SetCapability(pair.Key, pair.Value);
}

return capabilities;
return capabilities.AsReadOnly();
}
}
}
2 changes: 1 addition & 1 deletion dotnet/src/webdriver/Firefox/FirefoxOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ public override ICapabilities ToCapabilities()
capabilities.SetCapability(pair.Key, pair.Value);
}

return capabilities;
return capabilities.AsReadOnly();
}

private Dictionary<string, object> GenerateFirefoxOptionsDictionary()
Expand Down
24 changes: 11 additions & 13 deletions dotnet/src/webdriver/ICapabilities.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// <copyright file="ICapabilities.cs" company="WebDriver Committers">
// <copyright file="ICapabilities.cs" company="WebDriver Committers">
// 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
Expand All @@ -16,6 +16,9 @@
// limitations under the License.
// </copyright>

using System;
using System.Collections.Generic;

namespace OpenQA.Selenium
{
/// <summary>
Expand All @@ -24,19 +27,14 @@ namespace OpenQA.Selenium
public interface ICapabilities
{
/// <summary>
/// Gets the browser name
/// </summary>
string BrowserName { get; }

/// <summary>
/// Gets the platform
/// </summary>
Platform Platform { get; }

/// <summary>
/// Gets the browser version
/// Gets the capability value with the specified name.
/// </summary>
string Version { get; }
/// <param name="capabilityName">The name of the capability to get.</param>
/// <returns>The value of the capability.</returns>
/// <exception cref="ArgumentException">
/// The specified capability name is not in the set of capabilities.
/// </exception>
object this[string capabilityName] { get; }

/// <summary>
/// Gets a value indicating whether the browser has a given capability.
Expand Down
28 changes: 1 addition & 27 deletions dotnet/src/webdriver/IE/InternetExplorerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,32 +44,6 @@ public enum InternetExplorerElementScrollBehavior
Bottom
}

/// <summary>
/// Specifies the behavior of handling unexpected alerts in the IE driver.
/// </summary>
public enum InternetExplorerUnexpectedAlertBehavior
{
/// <summary>
/// Indicates the behavior is not set.
/// </summary>
Default,

/// <summary>
/// Ignore unexpected alerts, such that the user must handle them.
/// </summary>
Ignore,

/// <summary>
/// Accept unexpected alerts.
/// </summary>
Accept,

/// <summary>
/// Dismiss unexpected alerts.
/// </summary>
Dismiss
}

/// <summary>
/// Class to manage options specific to <see cref="InternetExplorerDriver"/>
/// </summary>
Expand Down Expand Up @@ -386,7 +360,7 @@ public override ICapabilities ToCapabilities()
capabilities.SetCapability(pair.Key, pair.Value);
}

return capabilities;
return capabilities.AsReadOnly();
}

private Dictionary<string, object> BuildInternetExplorerOptionsDictionary()
Expand Down
33 changes: 33 additions & 0 deletions dotnet/src/webdriver/Internal/IHasCapabilitiesDictionary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// <copyright file="IHasCapabilitiesDictionary.cs" company="WebDriver Committers">
// 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.
// </copyright>

using System.Collections.Generic;

namespace OpenQA.Selenium.Internal
{
/// <summary>
/// Defines the interface through which the user can access the driver used to find an element.
/// </summary>
internal interface IHasCapabilitiesDictionary
{
/// <summary>
/// Gets the underlying Dictionary for a given set of capabilities.
/// </summary>
Dictionary<string, object> CapabilitiesDictionary { get; }
}
}
Loading

0 comments on commit 0b310c1

Please sign in to comment.