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);
Related
It looks like Selenium doesn't apply any options to the new browser instance, since neither the extension nor the arguments that were defined in code are applied, it just launches a regular Chrome window without extensions, with an infobar and no incognito mode
void ChromeSession()
{
const string siteUrl = "https://www.google.com/";
var options = new ChromeOptions();
options.AddArgument("--disable-infobars");
options.AddArgument("--incognito");
options.AddExtension(#"C:\Users\kiespetch1\Downloads\Solver.crx");
new DriverManager().SetUpDriver(new ChromeConfig());
var driver = new ChromeDriver();
driver.Url = siteUrl;
}
How I can add extensions and launch arguments?
You can add profiles
options.AddArgument = ("user-data-dir':'/Users/Application/Chrome/Default'}
I'm writing tests with Selenium + C# and I face an important issue because I didn't found solution when I test my site with secure connection (HTTPS). All solutions I found on stackoverflow are out of date or doesn't work.
I tried to exercise all solutions from below question:
Selenium Why setting acceptuntrustedcertificates to true for firefox driver doesn't work?
But they did not help me solve the problem
Nor is it the solution of using Nightly FireFox.
Still, when the selenium loading Firfox browser, I see the page: "Your connection is not secure".
Configuration:
Firefox v56.0
Selenium.Firefox.WebDriver v0.19.0
Selenium.WebDriver v3.6.0
my code is:
FirefoxOptions options = new FirefoxOptions();
FirefoxProfile profile = new FirefoxProfile();
profile.AcceptUntrustedCertificates = true;
profile.AssumeUntrustedCertificateIssuer = false;
options.Profile = profile;
driver = new FirefoxDriver(FirefoxDriverService.CreateDefaultService() , options , TimeSpan.FromSeconds(5));
Drivers.Add(Browsers.Firefox.ToString() , driver);
Thank for your help!
Updates to my question here:
Note 1: To anyone who has marked my question as a duplicate of this question:
Firefox selenium webdriver gives “Insecure Connection”
I thought that it is same issue, but I need solution for C#, I try match your JAVA code to my above code
First, I changed to TRUE the below statment:
profile.AssumeUntrustedCertificateIssuer = true;
second, I create new FF profile ("AutomationTestsProfile")
and try to use it:
Try 1:
FirefoxProfile profile = new FirefoxProfileManager().GetProfile("AutomationTestsProfile");
try 2:
FirefoxProfile profile = new FirefoxProfile("AutomationTestsProfile");
I Run 2 options, but still the issue exists.
Note 2: I attached screenshot of my problem, it appears when the driver try to enter text to user-name on login page.
I noticed that when I open my site with FF, Firefox displays a lock icon with red strike-through red strikethrough icon in the address bar,
but near the username textbox not appears the msg:
"This connection is not secure. Logins entered here could be compromised. Learn More" (as you writed on the duplicate question),
So maybe there is a different problem?
You are setting the properties on the profile. The FirefoxOptions has a property AcceptInsecureCertificates, set that to true.
Forget the profile, this is what you want:
var op = new FirefoxOptions
{
AcceptInsecureCertificates = true
};
Instance = new FirefoxDriver(op);
For me, the profile setting AcceptUntrustedCertificates was not enough, I also had to set option security.cert_pinning.enforcement_level. My startup looks like
// no idea why FirefoxWebDriver needs this, but it will throw without
// https://stackoverflow.com/questions/56802715/firefoxwebdriver-no-data-is-available-for-encoding-437
CodePagesEncodingProvider.Instance.GetEncoding(437);
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
var service = FirefoxDriverService.CreateDefaultService(Environment.CurrentDirectory);
service.FirefoxBinaryPath = Config.GetConfigurationString("FirefoxBinaryPath"); // path in appsettings
var options = new FirefoxOptions();
options.SetPreference("security.cert_pinning.enforcement_level", 0);
options.SetPreference("security.enterprise_roots.enabled", true);
var profile = new FirefoxProfile()
{
AcceptUntrustedCertificates = true,
AssumeUntrustedCertificateIssuer = false,
};
options.Profile = profile;
var driver = new FirefoxDriver(service, options);
It works for me for following settings (same as above):
My env:
win 7
firefox 61.0.2 (64-bit)
Selenium C# webdriver : 3.14.0
geckodriver-v0.21.0-win32.zip
==============================
FirefoxOptions options = new FirefoxOptions();
options.BrowserExecutableLocation = #"C:\Program Files\Mozilla Firefox\firefox.exe";
options.AcceptInsecureCertificates = true;
new FirefoxDriver(RelativePath,options);
I have two instances of the ChromiumWebBrowser in my WinForms project (Visual Studio 2012). My goal is to have the second browser instance "copy" the behavior of the user input in the first browser instance. I can successfully retrieve the input from the first browser, and I managed to hook up Selenium in the project as well.
However, I'm having one issue. Whenever Selenium sends its commands, the first browser is the one that responds to them. For the life of me, I can't seem to figure out how to make the second browser respond. Whenever I completely remove the first browser, the second one starts responding correctly, but adding the first browser again will make only have the first browser use the Selenium commands. I even tried to switch out the moments the browsers are added to the form, but to no avail: whenever there are two available, the wrong one is responsive.
Relevant code:
public BrowserManager(Controller controller, string startingUrl)
{
_controller = controller;
var settings = new CefSettings { RemoteDebuggingPort = 9515 };
Cef.Initialize(settings);
// Input browser
inputBrowser = new ChromiumWebBrowser(startingUrl);
var obj = new XPathHelper(this);
inputBrowser.RegisterJsObject("bound", obj); //Standard object registration
inputBrowser.FrameLoadEnd += obj.OnFrameLoadEnd;
// Output browser
var browserSettings = new BrowserSettings();
var requestContextSettings = new RequestContextSettings { CachePath = "" };
var requestContext = new RequestContext(requestContextSettings);
outputBrowser = new ChromiumWebBrowser(startingUrl);
outputBrowser.RequestContext = requestContext;
outputBrowser.AddressChanged += InitializeOutputBrowser;
outputBrowser.Enabled = false;
outputBrowser.Name = "outputBrowser";
}
The selenium part:
public class SeleniumHelper
{
public SeleniumHelper()
{
DoWorkAsync();
}
private Task DoWorkAsync()
{
Task.Run(() =>
{
string chromeDriverDir = #"ActionRecorder\bin\x64\Debug\Drivers";
var chromeDriverService = ChromeDriverService.CreateDefaultService(chromeDriverDir);
chromeDriverService.HideCommandPromptWindow = true;
ChromeOptions options = new ChromeOptions();
options.BinaryLocation = #"ActionRecorder\bin\x64\Debug\ActionRecorder.exe";
options.DebuggerAddress = "127.0.0.1:9515";
options.AddArguments("--enable-logging");
using (IWebDriver driver = new OpenQA.Selenium.Chrome.ChromeDriver(chromeDriverService, options))
{
driver.Navigate().GoToUrl("http://www.google.com");
var query = driver.FindElement(By.Name("q"));
query.SendKeys("A google search test");
query.Submit();
}
});
return null;
}
}
And finally, a screenshot for some visualization:
Some help with the issue would be very much appreciated. If i missed some crucial info, feel free to ask for it. Thanks in advance!
Greetz,
Tybs
The behavior is correct. You have one debug address and you can only have one debug address for CEF. Which means when you use Selenium it is only seeing one browser.
By default Selenium will send an command to current active Tab or Window. Now in your case you have multiple Chrome view embedded, but they are technically Chrome Tab/Windows which you have placed on the same form.
So if you are in luck below code in should be able to move you to the Window you are interested in
driver.SwitchTo().Window(driver.WindowHandles.Last());
See if it works. If it doesn't then your only other workaround would be to change the order of Adding ChromiumWebBrowser and that should reverse the window it works on.
Below are some important threads that you should read from top to bottom. Very relevant to your issue/request
https://code.google.com/archive/p/chromiumembedded/issues/421
https://github.com/cefsharp/CefSharp/issues/1076
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?
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