Skip to content

Commit

Permalink
fix: Include missing AppiumOptionsDictionary into ToDictionary (#727)
Browse files Browse the repository at this point in the history
* fix: Include missing AppiumOptionsDictionary into ToDictionary
chore: Add missing XML docs
chore: Format fixes

* chore: Simplify member access

* test: Add OptionsTest

* chore: Update XML docs

* fix: use LINQ instead of foreach when merging dictionaries
test: improve tests
  • Loading branch information
Dor-bl authored Jan 25, 2024
1 parent 0b58d13 commit d0e16dd
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 28 deletions.
88 changes: 60 additions & 28 deletions src/Appium.Net/Appium/AppiumOptions.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using OpenQA.Selenium.Remote;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace OpenQA.Selenium.Appium
{
/// <summary>
/// Generic browser options
/// Generic driver options
/// </summary>
public class AppiumOptions : DriverOptions
{
Expand All @@ -23,11 +25,11 @@ public class AppiumOptions : DriverOptions
/// </summary>
public AppiumOptions() : base()
{
this.AddKnownCapabilityName(AppiumOptions.AutomationNameOption, "AutomationName property");
this.AddKnownCapabilityName(AppiumOptions.DeviceNameOption, "DeviceName property");
this.AddKnownCapabilityName(AppiumOptions.AppOption, "Application property");
this.AddKnownCapabilityName(AppiumOptions.PlatformVersionOption, "PlatformVersion property");
this.AddKnownCapabilityName("app", "Application property");
AddKnownCapabilityName(AutomationNameOption, "AutomationName property");
AddKnownCapabilityName(DeviceNameOption, "DeviceName property");
AddKnownCapabilityName(AppOption, "Application property");
AddKnownCapabilityName(PlatformVersionOption, "PlatformVersion property");
AddKnownCapabilityName("app", "Application property");
}

/// <summary>
Expand All @@ -54,10 +56,10 @@ public AppiumOptions() : base()
/// <summary>
/// Gets or sets the Browser name of the Appium browser's (e.g. Chrome, Safari and so on) setting.
/// </summary>
public new string BrowserName
{
get { return base.BrowserName; }
set { base.BrowserName = value; }
public new string BrowserName
{
get { return base.BrowserName; }
set { base.BrowserName = value; }
}

/// <summary>
Expand All @@ -77,76 +79,106 @@ public AppiumOptions() : base()
/// webdriver executable.</remarks>
public void AddAdditionalAppiumOption(string optionName, object optionValue)
{
string name = optionName.Contains(":") ? optionName : $"{VendorPrefix}:{optionName}";
this.ValidateCapabilityName(name);
this.additionalAppiumOptions[name] = optionValue;
string name = optionName.Contains(':') ? optionName : $"{VendorPrefix}:{optionName}";
ValidateCapabilityName(name);
additionalAppiumOptions[name] = optionValue;
}

/// <summary>
/// This method is overridden to provide a clear exception indicating that
/// the <see cref="AddAdditionalAppiumOption"/> method should be used for adding additional options.
/// </summary>
/// <param name="optionName">The name of the additional option.</param>
/// <param name="optionValue">The value of the additional option.</param>
/// <exception cref="NotImplementedException">
/// Thrown to indicate that <see cref="AddAdditionalAppiumOption"/> should be used for adding additional options.
/// </exception>
public override void AddAdditionalOption(string optionName, object optionValue)
{
throw new NotImplementedException("Use the AddAdditionalAppiumOption method for adding additional options");
}

/// <summary
/// <summary>
/// Turn the capabilities into a desired capability
/// </summary>
/// <returns>A desired capability</returns>
public override ICapabilities ToCapabilities()
{
var capabilities = this.GenerateDesiredCapabilities(true);
var capabilities = GenerateDesiredCapabilities(true);

foreach (var option in this.BuildAppiumOptionsDictionary())
foreach (var option in BuildAppiumOptionsDictionary())
{
capabilities.SetCapability(option.Key, option.Value);
}

return capabilities;
}

/// <summary>
/// Builds a dictionary containing known Appium options with their corresponding values.
/// </summary>
/// <returns>A dictionary representing known Appium options and their values.</returns>
protected virtual Dictionary<string, object> BuildAppiumKnownOptionsDictionary()
{
Dictionary<string, object> knownOptions = new Dictionary<string, object>();

if (!string.IsNullOrEmpty(this.App))
if (!string.IsNullOrEmpty(App))
{
knownOptions[AppOption] = this.App;
knownOptions[AppOption] = App;
}

if (!string.IsNullOrEmpty(this.AutomationName))
if (!string.IsNullOrEmpty(AutomationName))
{
knownOptions[AutomationNameOption] = this.AutomationName;
knownOptions[AutomationNameOption] = AutomationName;
}

if (!string.IsNullOrEmpty(this.DeviceName))
if (!string.IsNullOrEmpty(DeviceName))
{
knownOptions[DeviceNameOption] = this.DeviceName;
knownOptions[DeviceNameOption] = DeviceName;
}

if (!string.IsNullOrEmpty(this.PlatformVersion))
if (!string.IsNullOrEmpty(PlatformVersion))
{
knownOptions[PlatformVersionOption] = this.PlatformVersion;
knownOptions[PlatformVersionOption] = PlatformVersion;
}

return knownOptions;

}

private Dictionary<string, object> BuildAppiumOptionsDictionary()
{
var appiumOptions = BuildAppiumKnownOptionsDictionary();

foreach (KeyValuePair<string, object> pair in this.additionalAppiumOptions)
foreach (KeyValuePair<string, object> pair in additionalAppiumOptions)
{
appiumOptions.Add(pair.Key, pair.Value);
}

return appiumOptions;
}

/// <summary>
/// Converts the current instance of <see cref="AppiumOptions"/> to a ReadOnlyDictionary.
/// </summary>
/// <returns>A ReadOnlyDictionary representation of the <see cref="AppiumOptions"/>.</returns>
public IDictionary<string, object> ToDictionary()
{
var writeable = this.GenerateDesiredCapabilities(true);
return (writeable.AsReadOnly() as ReadOnlyDesiredCapabilities).ToDictionary();
IWritableCapabilities writeable = GenerateDesiredCapabilities(true);
var baseDict = (writeable.AsReadOnly() as ReadOnlyDesiredCapabilities).ToDictionary();
return MergeOptionsDictionary(baseDict);
}

/// <summary>
/// Merges the provided <see cref="IWritableCapabilities"/> dictionary with the <see cref="AppiumOptions"/> dictionary.
/// </summary>
/// <param name="baseDict">The base <see cref="IWritableCapabilities"/> dictionary.</param>
/// <returns>A ReadOnlyDictionary representing the merged <see cref="AppiumOptions"/> dictionary.</returns>
private IDictionary<string, object> MergeOptionsDictionary(IDictionary<string, object> baseDict)
{
Dictionary<string, object> appiumOptionsDict = BuildAppiumOptionsDictionary();
var mergedDict = appiumOptionsDict.Concat(baseDict).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
return new ReadOnlyDictionary<string, object>(mergedDict);
}

}
}
53 changes: 53 additions & 0 deletions test/integration/Options/OptionsTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//See the NOTICE file distributed with this work for additional
//information regarding copyright ownership.
//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 Appium.Net.Integration.Tests.helpers;
using NUnit.Framework;
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Enums;

namespace Appium.Net.Integration.Tests.ServerTests
{
public class OptionsTest
{

[Test]
public void CheckToDictionaryContainsAppiumOptions()
{
var capabilities = new AppiumOptions();
capabilities.AddAdditionalAppiumOption(AndroidMobileCapabilityType.Avd, "Android_Emulator");
capabilities.AddAdditionalAppiumOption(AndroidMobileCapabilityType.AppPackage, Apps.GetId(Apps.androidApiDemos));
var capsDict = capabilities.ToDictionary();
Assert.That(capsDict, Is.Not.Empty);
Assert.That(capsDict, Has.Count.GreaterThan(1));
}

[Test]
public void CheckToDictionaryContainsBothOptions()
{
var capabilities = new AppiumOptions
{
AutomationName = AutomationName.Appium,
App = Apps.androidApiDemos,
PlatformName = MobilePlatform.Android
};
capabilities.AddAdditionalAppiumOption(AndroidMobileCapabilityType.Avd, "Android_Emulator");
capabilities.AddAdditionalAppiumOption(AndroidMobileCapabilityType.AppPackage, Apps.GetId(Apps.androidApiDemos));
var capsDict = capabilities.ToDictionary();
Assert.That(capsDict, Is.Not.Empty);
Assert.That(capsDict, Has.Count.EqualTo(5));
}
}
}

0 comments on commit d0e16dd

Please sign in to comment.