Selenium WebDriver Factory picking same driver - c#

I am making an WinForms application, using Visual Studio with Selenium webdriver. I am running some tests using different browser for each test, that are launch at the click of different winforms buttons.
I have created an Webdriver Factory class as follows:
class BrowserFactory
{
private static readonly IDictionary<string, IWebDriver> Drivers = new Dictionary<string, IWebDriver>();
private static IWebDriver driver;
public static IWebDriver Driver
{
get
{
if (driver == null)
throw new NullReferenceException("The WebDriver browser instance was not initialized. You should first call the method InitBrowser.");
return driver;
}
private set
{
driver = value;
}
}
public static void InitBrowser(string browserName)
{
switch (browserName)
{
case "Firefox":
if (driver == null)
{
FirefoxProfile profile = new FirefoxProfile();
FirefoxOptions options = new FirefoxOptions();
options.Profile = profile;
options.BrowserExecutableLocation = $#"{EcrisAdreseFrameW.Properties.Settings.Default["caleAppData"]}\Internet JS4\App\firefox64\firefox.exe";
FirefoxDriverService service = FirefoxDriverService.CreateDefaultService($#"{EcrisAdreseFrameW.Properties.Settings.Default["caleAppData"]}");
driver = new FirefoxDriver(service, options);
Drivers.Add("Firefox", driver);
}
break;
case "Chrome":
if (driver == null)
{
var service = ChromeDriverService.CreateDefaultService($#"{EcrisAdreseFrameW.Properties.Settings.Default["caleAppData"]}\ChromeDriver");
var options = new ChromeOptions();
service.HideCommandPromptWindow = true;
options.BinaryLocation = $#"{EcrisAdreseFrameW.Properties.Settings.Default["caleAppData"]}\GoogleChromePortable\App\Chrome-bin\chrome.exe";
options.AddUserProfilePreference("disable-popup-blocking", "true");
driver = new ChromeDriver(service, options);
Drivers.Add("ChromeAscuns", driver);
}
break;
}
}
The code for first button:
BrowserFactory.InitBrowser("Firefox");
BrowserFactory.Driver.Navigate().GoToUrl("http://www.google.com");
The code for the second button:
BrowserFactory.InitBrowser("Chrome");
BrowserFactory.driver.Navigate().GoToUrl("http://www.bing.com");
When I click any of the buttons, it launches the correct webdriver (Firefox for first button and Chrome for the second). However, when I click the other button, it uses the same webdriver browser as the first occurence.
What am I missing in the code?

You appear to want to cache web drivers and reuse them. The problem is you are checking to see if a "driver" is already created, and if not create one, and cache that instance in a dictionary.
You need to consult the dictionary first before entering the switch statement and exit the method prematurely if a web driver by that name already exists. You also need to assume that when you fall in to the switch statement you will always be creating a new web driver.
public static void InitBrowser(string browserName)
{
if (Drivers.ContainsKey(browserName))
{
// Switch to existing web driver
driver = Drivers[browserName];
return;
}
// Initialize new web driver
switch (browserName)
{
case "Firefox":
FirefoxProfile profile = new FirefoxProfile();
FirefoxOptions options = new FirefoxOptions();
options.Profile = profile;
options.BrowserExecutableLocation = $#"{EcrisAdreseFrameW.Properties.Settings.Default["caleAppData"]}\Internet JS4\App\firefox64\firefox.exe";
FirefoxDriverService service = FirefoxDriverService.CreateDefaultService($#"{EcrisAdreseFrameW.Properties.Settings.Default["caleAppData"]}");
driver = new FirefoxDriver(service, options);
Drivers.Add("Firefox", driver);
break;
case "Chrome":
var service = ChromeDriverService.CreateDefaultService($#"{EcrisAdreseFrameW.Properties.Settings.Default["caleAppData"]}\ChromeDriver");
var options = new ChromeOptions();
service.HideCommandPromptWindow = true;
options.BinaryLocation = $#"{EcrisAdreseFrameW.Properties.Settings.Default["caleAppData"]}\GoogleChromePortable\App\Chrome-bin\chrome.exe";
options.AddUserProfilePreference("disable-popup-blocking", "true");
driver = new ChromeDriver(service, options);
Drivers.Add("ChromeAscuns", driver);
break;
}
}

Related

IDevTools instance does not contain CreateDevToolsSession method

I'm trying to intercept URLs containing a substring in C# using selenium chrome webdriver 4.0.0-beta4.
This is what I found and changed a little bit:
using V89 = OpenQA.Selenium.DevTools.V89;
using V89Net = OpenQA.Selenium.DevTools.V89.Network;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.DevTools;
ChromeOptions options = new ChromeOptions();
ChromeDriver webDriver;
IDevTools devTools;
public void InterceptRequestWithFetch(string url)
{
options.BinaryLocation = #"C:\Program Files\Google\Chrome Beta\Application\chrome.exe";
var service = ChromeDriverService.CreateDefaultService();
service.LogPath = AppDomain.CurrentDomain.BaseDirectory + "chromedriver.log";
service.EnableVerboseLogging = true;
webDriver = new ChromeDriver(service, options);
devTools = webDriver as IDevTools;
var devToolsSession = devTools.CreateDevToolsSession();
var fetch = devToolsSession.GetVersionSpecificDomains<V89.DevToolsSessionDomains>().Fetch;
var enableCommandSettings = new V89.Fetch.EnableCommandSettings();
var requestPattern = new V89.Fetch.RequestPattern();
requestPattern.RequestStage = V89.Fetch.RequestStage.Response;
requestPattern.ResourceType = V89Net.ResourceType.XHR;
requestPattern.UrlPattern = "*://*/*.jpg*";
enableCommandSettings.Patterns = new V89.Fetch.RequestPattern[] { requestPattern };
fetch.Enable(enableCommandSettings);
fetch.RequestPaused += RequestIntercepted;
webDriver.Navigate().GoToUrl(url);
}
void RequestIntercepted(object sender, V89.Fetch.RequestPausedEventArgs e)
{
richTextBox1.AppendText(e.Request.Url);
webDriver.Quit();
}
The problem is CreateDevToolsSession() does not exists and it seems like GetDevToolsSession() is the only option which does totally different job, but I tried it anyway and then my form froze, and codes past that line never executed.
I searched last three days for a solution but its just CreateDevToolsSession(). How can I use the DevTools if I won't be able to create a session?
This worked for me. Might not be exactly what you want, but it sets up devtools and can do whatever you normally would.
using OpenQA.Selenium.DevTools;
using OpenQA.Selenium.DevTools.V96.Network;
using DevToolsSessionDomains = OpenQA.Selenium.DevTools.V96.DevToolsSessionDomains;
public void DevtoolsExample()
{
IDevToolsSession session;
DevToolsSessionDomains devToolsSession;
//Setup WebDriver and devtools
driver = new ChromeDriver();
var baseUrl = ConfigurationHelper.Get<string>("TargetUrl");
//*this appears to create devtools session or get existing
IDevTools devTools = driver as IDevTools;
session = devTools.GetDevToolsSession();
devToolsSession = session.GetVersionSpecificDomains<DevToolsSessionDomains>();
devToolsSession.Network.Enable(new EnableCommandSettings());
devToolsSession.Network.SetBlockedURLs(new SetBlockedURLsCommandSettings()
{
Urls = new string[] { "*://*/*.css", "*://*/*.jpg", "*://*/*.png" }
//Urls = new string[] { }
});
driver.Navigate().GoToUrl("https://someUrl.com");
}

Selenium WebDriver doesn't start on IIS 10, but works fine if app is hosted InProcess

I have an ASP.NET MVC CORE 3.0 app, my requirement is to run Selenium on IIS 10. When I host my app InProcess it works, as soon as I switch to IIS it stops working (without any error message and regardless of app pool profile). I have the following code, but I believe that the code is irrelevant to this particular issue.
public void OpenOrReuseDriver(bool headlessMode = false, bool reuse = true)
{
if (!_driver.IsClosed()) return;
if (reuse && _drivers.Any() && _drivers.Last().IsOpen())
_driver = _drivers.Last();
else
{
var chromeService = ChromeDriverService.CreateDefaultService($#"{AppDomain.CurrentDomain.BaseDirectory}"); // Directory.GetCurrentDirectory() // AppDomain.CurrentDomain.BaseDirectory // Directory.GetCurrentDirectory()}\wwwroot
var chromeOptions = new ChromeOptions
{
BinaryLocation = #"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
};
if (headlessMode)
{
chromeOptions.AddArguments(new List<string>
{
"--silent-launch",
"--no-startup-window",
"no-sandbox",
"headless"
});
chromeService.HideCommandPromptWindow = true;
}
_driver = new ChromeDriver(chromeService, chromeOptions);
var size = new Size(1240, 720);
_driver.Manage().Window.Size = size;
_driver.Manage().Window.Position = PointUtils.CenteredWindowTopLeft(size).ToDrawingPoint();
_driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(60);
_driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(30);
_drivers.Add(_driver);
}
}
I would like to know the steps that will make Selenium work with IIS.

Starting a specific Firefox Profile with Selenium 3

I am trying to upgrade from Selenium 2 to Selenium 3 but the old handling, which was pretty easy and fast doesn't work anymore (and the documentation is nonexisting as it seems)
This is the program at the moment and what I want is to open a Firefox driver with the profile: SELENIUM
Sadly it doesn't work and always shuts down with the Error:
An unhandled exception of type 'System.InvalidOperationException' > occurred in WebDriver.dll
Additional information: corrupt deflate stream
This is my program at the moment:
public Program()
{
FirefoxOptions _options = new FirefoxOptions();
FirefoxProfileManager _profileIni = new FirefoxProfileManager();
FirefoxDriverService _service = FirefoxDriverService.CreateDefaultService(#"C:\Programme\IMaT\Output\Release\Bin");
_service.FirefoxBinaryPath = #"C:\Program Files (x86)\Mozilla Firefox\firefox.exe";
try
{
if ((_options.Profile = _profileIni.GetProfile("SELENIUM")) == null)
{
Console.WriteLine("SELENIUM PROFILE NOT FOUND");
_profile.SetPreference("network.proxy.type", 0); // disable proxy
_profile = new FirefoxProfile();
}
}
catch
{
throw new Exception("Firefox needs a Profile with \"SELENIUM\"");
}
IWebDriver driver = new FirefoxDriver(_service,_options,new System.TimeSpan(0,0,30));
driver.Navigate().GoToUrl("ld-hybrid.fronius.com");
Console.Write("rtest");
}
static void Main(string[] args)
{
new Program();
}
Without Loading the Profile it works with just new FirefoxDriver(_service) but the profile is mandatory.
In Selenium 2 I handled it with this code:
FirefoxProfileManager _profileIni = new FirefoxProfileManager();
// use custom temporary profile
try {
if ((_profile = _profileIni.GetProfile("SELENIUM")) == null)
{
Console.WriteLine("SELENIUM PROFILE NOT FOUND");
_profile.SetPreference("network.proxy.type", 0); // disable proxy
_profile = new FirefoxProfile();
}
}
catch
{
throw new Exception("Firefox needs a Profile with \"SELENIUM\"");
}
_profile.SetPreference("intl.accept_languages", _languageConfig);
_driver = new FirefoxDriver(_profile);
Fast and simple, but as the Driver doesn't support a Constructor with service and profile I don't really know how to get this to work, any help would be appreciated
This exception is due to a bug in the .Net library. The code generating the Zip of the profile is failing to provide a proper Zip.
One way to overcome this issue would be to overload FirefoxOptions and use the archiver from .Net framework (System.IO.Compression.ZipArchive) instead of the faulty ZipStorer:
var options = new FirefoxOptionsEx();
options.Profile = #"C:\Users\...\AppData\Roaming\Mozilla\Firefox\Profiles\ez3krw80.Selenium";
options.SetPreference("network.proxy.type", 0);
var service = FirefoxDriverService.CreateDefaultService(#"C:\downloads", "geckodriver.exe");
var driver = new FirefoxDriver(service, options, TimeSpan.FromMinutes(1));
class FirefoxOptionsEx : FirefoxOptions {
public new string Profile { get; set; }
public override ICapabilities ToCapabilities() {
var capabilities = (DesiredCapabilities)base.ToCapabilities();
var options = (IDictionary)capabilities.GetCapability("moz:firefoxOptions");
var mstream = new MemoryStream();
using (var archive = new ZipArchive(mstream, ZipArchiveMode.Create, true)) {
foreach (string file in Directory.EnumerateFiles(Profile, "*", SearchOption.AllDirectories)) {
string name = file.Substring(Profile.Length + 1).Replace('\\', '/');
if (name != "parent.lock") {
using (Stream src = File.OpenRead(file), dest = archive.CreateEntry(name).Open())
src.CopyTo(dest);
}
}
}
options["profile"] = Convert.ToBase64String(mstream.GetBuffer(), 0, (int)mstream.Length);
return capabilities;
}
}
And to get the directory for a profile by name:
var manager = new FirefoxProfileManager();
var profiles = (Dictionary<string, string>)manager.GetType()
.GetField("profiles", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(manager);
string directory;
if (profiles.TryGetValue("Selenium", out directory))
options.Profile = directory;

How to Initialize a C# Selenium webdriver test to pass in different browser types?

I want to pass into my unit tests which browser to use (Firefox, Chrome, IE).
[TestInitialize()]
public void Initialize(string URL, string Country, string Browser)
{
this.URL = URL;
this.Country = Country;
this.Browser = Browser;
}
Something like:
public DefaultDriver _webDriver = new DefaultDriver();
Then assign the Default Driver to the correct Browser type:
if (Browser == "Firefox")
_webDriver = _firefoxDriver;
else if (Browser == "Chrome")
_webDriver = new ChromeDriver();
else if (Browser == "IE")
_webDriver = new InternetExplorerDriver();
But this doesnt work as there is no DefaultDriver that is compatible with ChromeDriver, FireFoxDriver, and InternetExplorerDriver that I can find. What would be a good way to do this or another way to accomplish sending in the browser type in C#? I'm using a form application to run the tests and want to pass in different browsers to the same test.
The WebDriver project makes extensive use of interfaces. While all current browser-specific implementations descend from RemoteWebDriver, that's not a requirement. What you really want is to use the IWebDriver interface.
public IWebDriver _webdriver = null;
Then in your factory method do something like:
switch (browser)
{
case "IE":
_webdriver = new InternetExplorerDriver();
break;
case "Firefox":
_webdriver = new FirefoxDriver();
break;
case "Chrome":
_webdriver = new ChromeDriver();
break;
}
Do something like this:
WebDriver _webDriver = null;
if (Browser == "Firefox")
_webDriver = _firefoxDriver;
else if (URL == "Chrome")
_webDriver = new ChromeDriver();
else if (URL == "IE")
_webDriver = new InternetExplorerDriver();

Run Selenium grid 2 with custom firefox profile

How to run Selenium grid 2 with custom firefox profile from code.
Here is code I'm having now:
DesiredCapabilities capabilities = DesiredCapabilities.Firefox();
capabilities.SetCapability(CapabilityType.AcceptSslCertificates, true);
capabilities.SetCapability(CapabilityType.HasNativeEvents, false);
capabilities.SetCapability(CapabilityType.Platform, new Platform(PlatformType.Windows));
capabilities.IsJavaScriptEnabled = true;
Uri url = new Uri("http://localhost:4444/wd/hub");
RemoteWebDriver driver = new RemoteWebDriver(url, capabilities);
return driver;
The only thing I left is to force Selenium grid use my custom profile.
Found solution:
var firefoxProfile = new FirefoxProfile();
// configure firefoxProfile ...
DesiredCapabilities capabilities = DesiredCapabilities.Firefox();
capabilities.SetCapability(CapabilityType.AcceptSslCertificates, true);
capabilities.SetCapability(CapabilityType.HasNativeEvents, false);
capabilities.SetCapability(CapabilityType.Platform, new Platform(PlatformType.Windows));
capabilities.IsJavaScriptEnabled = true;
capabilities.SetCapability(FirefoxDriver.ProfileCapabilityName, firefoxProfile.ToBase64String());
Uri url = new Uri("http://localhost:4444/wd/hub");
RemoteWebDriver driver = new RemoteWebDriver(url, capabilities);
return driver;

Categories