Cannot pass DesiredCapabilities to ChromeDriver:s constructor? - c#

When I try to use
var dc = DesiredCapabilities.Chrome();
var driver = new ChromeDriver(dc);
I get "Cannot resolve constructor".
It seems like I have to pass ChromeOptions instead.
Why?
Every single tutorial/help page on the subject suggests that I pass DesiredCapabilities.
I am using Selenium.WebDriver.ChromeDriver version 2.21.0.0.

You can use ChromeOptions to set any specific options.
ChromeOptions options = new ChromeOptions();
options.AddArguments("--disable-extensions");
options.AddArguments("--start-maximized");
options.ToCapabilities();
ChromeDriverService service = ChromeDriverService.CreateDefaultService(Environment.GetEnvironmentVariable("USERPROFILE") + "\\Downloads");
IWebDriver chromeDriver = new ChromeDriver(service, options);
You can use- options.ToCapabilities(); to get see the capabilities.
You can use ChromeOptions to set any specific type of capabilities- peter.sh/experiments/chromium-command-line-switches . It seems the DesiredCapabilities can be added only in Java or if you are dealing with InternetExplorerDriver- Selenium c#: How to launch Internet Explorer driver in a specific version (IE8 for example)

Using dotpeek and looking at the chromedriver constructors (which there are 7 overloads) 6 of them invoke the constructor below on the ChromeDriver itself
public ChromeDriver(ChromeDriverService service, ChromeOptions options, TimeSpan commandTimeout)
: base((ICommandExecutor) new DriverServiceCommandExecutor((DriverService) service, commandTimeout), ChromeDriver.ConvertOptionsToCapabilities(options))
{
}
Which in turn calls the base constructor on the RemoteWebdriver. This passes in the last parameter as ChromeDriver.ConvertOptionsToCapabilities(options)
Looking at the you can see this:
private static ICapabilities ConvertOptionsToCapabilities(ChromeOptions options)
{
if (options == null)
throw new ArgumentNullException("options", "options must not be null");
return options.ToCapabilities();
}
Then into options.ToCapabilities:
public override ICapabilities ToCapabilities()
{
Dictionary<string, object> dictionary = this.BuildChromeOptionsDictionary();
DesiredCapabilities desiredCapabilities = DesiredCapabilities.Chrome();
desiredCapabilities.SetCapability(ChromeOptions.Capability, (object) dictionary);
if (this.proxy != null)
desiredCapabilities.SetCapability(CapabilityType.Proxy, (object) this.proxy);
Dictionary<string, object> preferencesDictionary = this.GenerateLoggingPreferencesDictionary();
if (preferencesDictionary != null)
desiredCapabilities.SetCapability(CapabilityType.LoggingPreferences, (object) preferencesDictionary);
foreach (KeyValuePair<string, object> additionalCapability in this.additionalCapabilities)
desiredCapabilities.SetCapability(additionalCapability.Key, additionalCapability.Value);
You can see under the hood it appears its already using DesiredCapabilities.Chrome() and you don't need to pass it in. Perhaps the tutorials you have seen are outdated?

Related

BrowserStack: Unexpected error. Authorization required

I have two simple tests that are using RemoteWebDriver with ChromeOptions and EdgeOptions. Both these tests are using common code to set capabilities, including the browserstack.user and browserstack.key capabilities.
Because I am using DriverOptions (instead of DesiredCapabilities) I have used AddAdditionalCapability(...) to add these capabilities to the Driver.
The Edge test is working but the Chrome test is failing before the test even starts with;
OpenQA.Selenium.WebDriverException: Unexpected error. Authorization required
These tests were previously working with DesiredCapabalities before I upgraded my Selenium Driver to v3.14 (where DesiredCapabalities have been depracated).
Update
I have downgraded to Selenium.WebDriver v3.4.
An example of the code that is passing (EdgeOptions) and failing (with ChromeOptions):
[TestClass]
public class Simple_GridTest_Chrome
{
private static IWebDriver driver;
private string _bsUsername = "<username>";
private string _bsAccessKey = "<myaccesskey>";
private string _bsProjectName = "TestProject";
private string _bsBuildName = "Build-0.0.1";
private void SetOptions(bool useEdge = false)
{
DriverOptions options;
if (useEdge)
{
options = new EdgeOptions(); // this works OK
} else
{
options = new ChromeOptions(); // this fails with OpenQA.Selenium.WebDriverException: Unexpected error. Authorization required
}
// the account that is running the test
options.AddAdditionalCapability("browserstack.user", _bsUsername);
options.AddAdditionalCapability("browserstack.key", _bsAccessKey);
options.AddAdditionalCapability("project", _bsProjectName);
options.AddAdditionalCapability("build", _bsBuildName);
// gather additional data during the test run (screen shots etc)
options.AddAdditionalCapability("browserstack.debug", "true");
driver = new RemoteWebDriver(
new Uri("https://hub-cloud.browserstack.com/wd/hub/"), options
);
//driver = new RemoteWebDriver(
// new Uri($"https://{_bsUsername}:{_bsAccessKey}#hub-cloud.browserstack.com/wd/hub/"), options
//);
}
[ClassInitialize()]
public static void MyClassInitialise(TestContext context)
{
}
[TestMethod]
[TestCategory("grid.BrowserStack.Google")]
public void NavigateToGoogle_Windows7_Chrome()
{
SetOptions(false); // use Chrome
GoogleTest(driver);
}
[TestMethod]
[TestCategory("grid.BrowserStack.Google")]
public void NavigateToGoogle_Windows10_Edge()
{
SetOptions(true); // use Edge
GoogleTest(driver);
}
private void GoogleTest(IWebDriver driver)
{
driver.Navigate().GoToUrl("https://www.google.com/?q=test");
Console.WriteLine(driver.Title);
driver.WaitForWebElement(By.XPath("//*[#name=\"btnK\"]")).Click();
Console.WriteLine(driver.Title);
}
}
I have the following packages installed:
<packages>
<package id="Selenium.Firefox.WebDriver" version="0.21.0" targetFramework="net45" />
<package id="Selenium.Support" version="3.4.0" targetFramework="net45" />
<package id="Selenium.WebDriver" version="3.4.0" targetFramework="net45" />
<package id="Selenium.WebDriver.ChromeDriver" version="2.41.0" targetFramework="net45" />
<package id="Selenium.WebDriver.IEDriver" version="3.14.0" targetFramework="net45" />
</packages>
This seems an issue specific to how the selenium language bindings generate payload and how browserstack parses it at their end.
Based on the error message you shared, it is quite likely that while parsing the request payload, browserstack is not able to find your username and access key
You may follow the steps mentioned below to debug this:
Change the line driver = new RemoteWebDriver(new Uri("https://hub-cloud.browserstack.com/wd/hub/"), options); to
driver = new RemoteWebDriver(
new Uri("http://localhost:4444/wd/hub/"), options
);. You are not required to start selenium-standalone jar locally.
Start a proxy that reads traffic on localhost:4444. (You may use a node based implementation for the same if needed. Here is one such implementation: https://gist.github.com/hanikhan/f817bd64b063129cb78dc7ed0b66fdb7)
Observe the request payload generated by the selenium client bindings you are using(v3.14 as you mentioned). For example, my java based selenium client generates this when only browser is passed is desiredcapabitlies {"desiredCapabilities":{"browserName":"Chrome"},"capabilities":{"firstMatch":[{"browserName":"Chrome"}]}}
Now downgrade your selenium bindings(to a version where it was working) and observe the payload it generates.
Check if the client bindings use strict checks due to which some required capabilities are getting discarded at your end.
If this is true then you will be required to do one of the following:
Raise an issue with selenium C# bindings to remove strict checks for your case
Contact Browserstack and ask them to provide a capability that passes the strict check
You can pass the capabilities as below for both Edge and Chrome using EdgeOptions and ChromeOptions to initiate session on BrowserStack. This is in Java. Port your test accordingly for other languages.
For Edge
EdgeOptions options = new EdgeOptions();
options.setCapability("browserstack.user","<userName>");
options.setCapability("browserstack.key","<accessKey>");
options.setCapability("os_version", "10"); //desired os_version
options.setCapability("browser", "chrome"); //desired browser
driver = new RemoteWebDriver(new URL("https://hub-cloud.browserstack.com/wd/hub"), options);
For Chrome
ChromeOptions options = new ChromeOptions();
options.setCapability("browserstack.user","<userName>");
options.setCapability("browserstack.key","<accessKey>");
options.setCapability("os_version", "10");
options.setCapability("browser", "chrome");
driver = new RemoteWebDriver(new URL("https://hub-cloud.browserstack.com/wd/hub"), options);
I ran into this same issue and resolved it by setting the "isGlobalCapability" to true on every "AddAdditionalCapability" method for ChromeOptions (using Selenium 3.14). If just one of them doesn't have it set, the test fails.
chromeOptions.AddAdditionalCapability("browserstack.user", <user>, true);
chromeOptions.AddAdditionalCapability("browserstack.key", <key>, true);
chromeOptions.AddAdditionalCapability("browser", "chrome", true);
chromeOptions.AddAdditionalCapability("os", "Windows", true);
chromeOptions.AddAdditionalCapability("os_version", "10", true);
_Driver = new RemoteWebDriver(new Uri("http://hub-cloud.browserstack.com/wd/hub/"), chromeOptions);
Did you try to add options as options.ToCapabilities()?
driver = new RemoteWebDriver(
new Uri("https://hub-cloud.browserstack.com/wd/hub/"), options.ToCapabilities()
);
Also try to set as global capability:
options.AddAdditionalCapability("browserstack.user", _bsUsername, true);
The issue is that AddAdditionalCapability(string capabilityName, object capabilityValue) does not set the capabilities globally when called on ChromeOptions, FirefoxOptions, and InternetExplorerOptions. Rather, it puts them inside the specific browser options in the JSON. For more information see https://github.com/SeleniumHQ/selenium/issues/6563.
As you have noticed, EdgeOption does set them globally which is why that was working for you (SafariOptions would have worked the same BTW).
Now, the reason you don't see the AddAdditionalCapability(string capabilityName, object capabilityValue, bool isGlobalCapability) overload is that your options variable is of type DriverOptions, which does not contain this overload. As a workaround, you could to do something like this:
static void AddGlobalCapability(this DriverOptions options, string name, object value)
{
switch (options)
{
case ChromeOptions chromeOptions:
chromeOptions.AddAdditionalCapability(name, value, true);
break;
case FirefoxOptions firefoxOptions:
firefoxOptions.AddAdditionalCapability(name, value, true);
break;
case InternetExplorerOptions internetExplorerOptions:
internetExplorerOptions.AddAdditionalCapability(name, value, true);
break;
default:
options.AddAdditionalCapability(name, value);
break;
}
}
We had this same issue. We were trying to use the credentials in our URL, as we do in our Java project.
var browserstackUrl = string.Format(
"https://{0}:{1}#hub-cloud.browserstack.com/wd/hub",
browserstackUsername,
browserstackAccessKey
);
var webdriver = new RemoteWebDriver(new Uri(BrowserStackUrl), options);
By moving them to capabilities, we were able to get past this issue:
capabilities.SetCapability("browserstack.user", browserstackUsername);
capabilities.SetCapability("browserstack.key", browserstackAccessKey);
var browserstackUrl = "https://hub-cloud.browserstack.com/wd/hub";
var webdriver = new RemoteWebDriver(new Uri(BrowserStackUrl), options);

Unable to launch Chrome in incognito mode using Selenium WebDriver using C#

I am trying to launch Chrome using Selenium WebDriver in incognito mode, but not able to accomplish. I tried all options but not able to launch. Below is my code snippet
case "chrome":
ChromeOptions options = new ChromeOptions();
options.AddArgument("--incognito"); //Line XYZ
desiredCapabilities = DesiredCapabilities.Chrome();
desiredCapabilities.SetCapability(ChromeOptions.Capability, options);
break;
var capabilities = BuildDesiredCapabilities();
webDriver = new RemoteWebDriver(new Uri(gridHubURL), capabilities,
TimeSpan.FromSeconds(ApplicationConfiguration.RemoteDriverTimeOutValue));
Can anyone please help me what I am doing wrong here? I also tried the below code options in Line XYZ
Any pointers will be much helpful.
EDIT1
Please find the updated code here.
public IWebDriver CreateDriver()
{
var capabilities = BuildDesiredCapabilities();
webDriver = new RemoteWebDriver(new Uri(gridHubURL), capabilities,
TimeSpan.FromSeconds(ApplicationConfiguration.RemoteDriverTimeOutValue));
webDriver.Manage().Window.Maximize();
webDriver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(ApplicationConfiguration.TimeOutValue));
webDriver.Manage().Timeouts().SetPageLoadTimeout(TimeSpan.FromSeconds(ApplicationConfiguration.TimeOutValue));
return webDriver;
}
private DesiredCapabilities BuildDesiredCapabilities()
{
DesiredCapabilities desiredCapabilities;
switch (browserName.ToLower())
{
case "firefox":
desiredCapabilities = DesiredCapabilities.Firefox();
break;
case "chrome":
desiredCapabilities = DesiredCapabilities.Chrome();
desiredCapabilities.SetCapability("chrome.switches", "--incognito");
break;
case "ie":
desiredCapabilities = DesiredCapabilities.InternetExplorer();
desiredCapabilities.SetCapability("ie.ensureCleanSession", true);
break;
default:
desiredCapabilities = DesiredCapabilities.Firefox();
break;
}
return desiredCapabilities;
}
The .NET bindings have introduced browser-specific Options classes to avoid having to know or understand arbitrary capability values. You were using just such a class, ChromeOptions, in your original code. You missed one extra step, though, in how to use the ChromeOptions class with RemoteWebDriver. The missing piece is that you should use the ToCapabilities() method to convert the ChromeOptions object to the ICapabilities object that RemoteWebDriver expects. Your code would look something like the following:
var options = new ChromeOptions();
options.AddArgument("incognito");
var capabilities = options.ToCapabilities();
var driver = new RemoteWebDriver(new URI(gridHubURL), capabilities);
You should pass parameters to the executable like this:
desiredCapabilities = DesiredCapabilities.Chrome();
desiredCapabilities.SetCapability("chrome.switches", "--incognito");
So passing the parameter --incognito to the chrome.switches capability should work.
NOTE:
The chrome.switches capability has been deprecated for over two years. A list of the current supported capabilities can be found at the official chromedriver Google Sites page. Additionally, use of arbitrary capabilities has been discouraged by the Selenium project for some time, particularly when using the .NET bindings

Pass to chromedriver capabilities as desiredCapabilities c#

I have software which does automated testing via chrome browser, but now this program failed with error message "Vector smash protection is enabled."
I've found a solution for this case, but this solution implemented via java API.
DesiredCapabilities capabilities = DesiredCapabilities.chrome();
capabilities.setCapability("chrome.switches", Arrays.asList("--incognito"));
ChromeOptions options = new ChromeOptions();
options.addArguments("test-type");
WebDriver driver = new ChromeDriver(capabilities);
How to implement a code the same as above via c#?
You need a Dictionary
// Capabilities Values
var imageSetting = new Dictionary<string, object> {{"images", 2}};
var content = new Dictionary<string, object> {{"profile.default_content_settings", imageSetting}};
var prefs = new Dictionary<string, object> {{"prefs", content}};
// List of Chromium Command Line Switches
var options = new ChromeOptions();
options.AddArguments(
"--disable-extensions",
"--disable-features",
"--disable-popup-blocking",
"--disable-settings-window");
// Add the Capabilities
var field = options.GetType().GetField("additionalCapabilities", BindingFlags.Instance | BindingFlags.NonPublic);
if (field != null)
{
var dict = field.GetValue(options) as IDictionary<string, object>;
if (dict != null) dict.Add(ChromeOptions.Capability, prefs);
}
// Create the Chrome Driver
var chromeDriver = new ChromeDriver(options);
Also you can send the driver path when you create the ChromeDriver object.

Disable images in Selenium Google ChromeDriver

How does one disable images in Google chrome when using it through Selenium and c#?
I've attempted 6 ways and none worked. I've even tried the answer on this StackOverflow question, however I think the info in it is out of date.
Chrome driver: V2.2
Chrome version: V29.0.1547.66 m
Selenium: V2.35
All the attempts I've made don't cause exceptions, they run normally but still display images:
Attempt 1:
ChromeOptions co = new ChromeOptions();
co.AddArgument("--disable-images");
IWebDriver driver = new ChromeDriver(co);
Attempt 2:
DesiredCapabilities capabilities = DesiredCapabilities.Chrome();
capabilities.SetCapability("chrome.switches", new string[1] { "disable-images" });
Attempt 3:
ChromeOptions co = new ChromeOptions();
co.AddAdditionalCapability("chrome.switches", new string[1] { "disable-images" });
Attempt 4:
var imageSetting = new Dictionary<string, object>();
imageSetting.Add("images", 2);
Dictionary<string, object> content = new Dictionary<string, object>();
content.Add("profile.default_content_settings", imageSetting);
var prefs = new Dictionary<string, object>();
prefs.Add("prefs", content);
var options = new ChromeOptions();
var field = options.GetType().GetField("additionalCapabilities", BindingFlags.Instance | BindingFlags.NonPublic);
if (field != null)
{
var dict = field.GetValue(options) as IDictionary<string, object>;
if (dict != null)
dict.Add(ChromeOptions.Capability, prefs);
}
Attempt 5:
ChromeOptions options = new ChromeOptions();
options.AddAdditionalCapability("profile.default_content_settings", 2);
Attempt 6:
Dictionary<String, Object> contentSettings = new Dictionary<String, Object>();
contentSettings.Add("images", 2);
Dictionary<String, Object> preferences = new Dictionary<String, Object>();
preferences.Add("profile.default_content_settings", contentSettings);
DesiredCapabilities caps = DesiredCapabilities.Chrome();
caps.SetCapability("chrome.prefs", preferences);
This is my solution
IWebDriver driver;
ChromeOptions options = new ChromeOptions();
options.AddUserProfilePreference("profile.default_content_setting_values.images", 2);
driver = new ChromeDriver(options);
You should use --blink-settings instead of --disable-images by:
options.add_argument('--blink-settings=imagesEnabled=false')
which also works in headless mode. Setting profile doesn't work in headless mode. You can verify it by screenshot:
driver.get_screenshot_as_file('headless.png')
Note: I was using python with selenium, but I think it should be easy to transfer to c#.
For your method 1-3, I don't see a Chrome switch called --disable-images listed here. So even if the code snippets are correct, they won't work no matter what. Where did you get that switch? Any references?
For the methods 4-6, I assume you got the idea from this chromdriver issue. I don't know if this {'profile.default_content_settings': {'images': 2}} is still valid or not, but you can give it a try with the following code (which was originally the answer to How to set Chrome preferences using Selenium Webdriver .NET binding?, answer provided by Martin Devillers).
public class ChromeOptionsWithPrefs: ChromeOptions {
public Dictionary<string,object> prefs { get; set; }
}
public static void Initialize() {
var options = new ChromeOptionsWithPrefs();
options.prefs = new Dictionary<string, object> {
{ "profile.default_content_settings", new Dictionary<string, object>() { "images", 2 } }
};
var driver = new ChromeDriver(options);
}
Use http://chrome-extension-downloader.com/ to download the "Block Image" extension (https://chrome.google.com/webstore/detail/block-image/pehaalcefcjfccdpbckoablngfkfgfgj?hl=en-GB). The extension prevents the image from being downloaded in the first place. Now it's just a matter of loading it using the following statement:
var options = new ChromeOptions();
//use the block image extension to prevent images from downloading.
options.AddExtension("Block-image_v1.0.crx");
var driver = new ChromeDriver(options);
An easier approach would be solely:
ChromeOptions options = new ChromeOptions();
options.addArguments("headless","--blink-settings=imagesEnabled=false");
I found out simple solution. This idea referred from Python:Disable images in Selenium Google ChromeDriver
var service = ChromeDriverService.CreateDefaultService(#WebDriverPath);
var options = net ChromeOptions();
options.AddUserProfilePreference("profile.managed_default_content_settings.images", 2);
IWebDriver Driver = new ChromeDriver(service, options);
I recommend that you create a new profile, customize this profile so that it does not load the images, and use this profile as a chromeOption to set up your driver.
See: this article

How to get the Browser info in C# WebDriver?

I see a ICapabilities interface to get the Browser info;Did couple of googling with no luck for any code example; Can anybody please share anything how I can get the browser info for a particular IWebDriver instance ? I am using C# webdriver.
In order to get info defined in ICapabilities interface, you need to cast IWebDriver instance to RemoteWebDriver. Then you can get the info about BrowserName, IsJavaScriptEnabled, Platform and Version.
IWebDriver driver = new FirefoxDriver();
ICapabilities capabilities = ((RemoteWebDriver)driver).Capabilities;
// then you have
// capabilities.BrowserName;
// capabilities.IsJavaScriptEnabled;
// capabilities.Platform;
// capabilities.Version;
Based on the old Yi Zeng answer, I was able to acces with the next code:
IWebDriver driver = new FirefoxDriver();
ICapabilities capabilities = ((WebDriver)driver).Capabilities;
// then you have
// capabilities.GetCapability("browserName");
// ...
I use below code to get Chrome driver version
IWebDriver driver = new ChromeDriver();
ICapabilities capabilities = ((OpenQA.Selenium.WebDriver)driver).Capabilities;
var SeleniumWebDriverName = driver.GetType().ToString();
var SeleniumWebDriverVersion = (capabilities.GetCapability("chrome") as Dictionary<string, object>)["chromedriverVersion"];
Console.WriteLine( "DRIVER NAME ====" + SeleniumWebDriverName );
Console.WriteLine( "VERSION ====" + SeleniumWebDriverVersion + Environment.NewLine);
I've stumbled across an easier way if you just need to know which driver is running to get around a hack:
Driver.GetType().ToString();

Categories