Why does instance of a IWebDriver class throws an exception in Iteration? - c#

I am developing an application using selenium web driver. I am putting a set of task in the 'for' loop. The task is:
Open a URL using driver object of IWebDriver class.
Traverse to different different URLs
At the for loop, I am killing the instance of IWebDriver class with following:
driver.Close(); driver.Quit();
Now when the second iteration starts, the program does not perform the above task, rather it gives an exception.
When I research on the exception, I found the issue is with the driver.Close(); driver.Quit();. It's not even closing the browser, but its also removing the instance of a IWebDriver class. How can I handle this situation?
Here is the Sample code:
class callingfunction
{
public static IWebDriver driver = new ChromeDriver(Cpath);
public void function1()
{
for (int i = 0; i < 10; i++ )
{
driver.Navigate().GoToUrl("http://www.aaa.org");
driver.Navigate().GoToUrl("http://www.aaa.org/contactus");
driver.FindElement(By.Name("contact")).SendKeys(contact);
driver.Navigate().GoToUrl("http://www.aaa.org/aboutus");
//Code logic
driver.Close();
driver.Quit();
}
}
}

You're calling quit() on the WebDriver inside your loop, so on the second iteration you will indeed get errors.
The only place you need it is right at the very end of your test. The close() call is also unnecessary.
Furthermore, you're not waiting for anything to load, so without proper waits your driver.FindElement(By.Name("contact")).SendKeys(contact); will likely fail often.
Finally you're not doing anything with the 1st or 3rd page requests, so - given the lack of waits - those pages are likely never allowed to fully load.

I don't understand the scenario you are trying to accomplish but I'm hoping that in the process of simplifying the code, you've removed the bits that make this scenario make a little more sense. Having said that...
The problem is that you are closing and quitting the browser driver inside the for loop but never instantiate another browser instance. The browser instance is created when you do new ChromeDriver() so you will want that inside the for loop. Something like this should work.
class callingfunction
{
public static IWebDriver driver = null;
public void function1()
{
for (int i = 0; i < 10; i++)
{
driver = new ChromeDriver(Cpath); // launch browser
driver.Navigate().GoToUrl("http://www.aaa.org");
driver.Navigate().GoToUrl("http://www.aaa.org/contactus");
driver.FindElement(By.Name("contact")).SendKeys(contact);
driver.Navigate().GoToUrl("http://www.aaa.org/aboutus");
//Code logic
driver.Close(); // close browser
}
driver.Quit(); // close browser driver
}
}
Is there some reason you need to close the browser between runs? You can't just reuse the existing browser instance? Your test will run much faster... but sometimes there is a need to close it. Only you would know...

Related

C# Call a thread multiple times but once at a time

I have a kind of Web-Server in C#(for CGI). When I open the web page, it basically executes a method(that writes some text to a file). But the problem is if 2nd persons opened the page before the previous method ended, the server would call the method again and both would conflict. The web server calls the method as a thread. Thread.Join works for 2 threads.
Simplified - In my c# code, there is one method(thread) that can be called even when its one instance is already running and not completed. I need to wait till it exits and run again with new variables provided.
Code -
private readonly object xyz = new object();
public string module1(string txt, string phno)
{
lock (xyz)
{
ChromeOptions options = new ChromeOptions();
string crd = Directory.GetCurrentDirectory();
string udd = String.Format(#"--user-data-dir={0}\\Chrome Profile", crd);
options.AddArgument(String.Format(udd));
IWebDriver driver = new ChromeDriver(options);
driver.Url = String.Format("https://google.com");
thread.sleep(5000);
driver.Quit();
return "ok";
}
}
This method can be run only once at a time or it will give error as Selenium only supports one chrome browser per user data directory. And since this method is called by API, it can be called multiple times. In reality, this method takes around 30 seconds.

Selenium WebDriver - Wait for long running queues

I have an application which is used to trigger long running data queues. By long running, I mean around 12-16 hours per queue and either of them cannot be executed in parallel. Each queue has individual steps which need to succeed before the next one runs.
I have already increased the timeouts while initializing ChromeDriver upto 1000 minutes
webDriver == new ChromeDriver(path,options,TimeSpan.FromMinutes(1000));
I am using WebDriverWait for checking after 1000 mins that all steps have been succeeded. In case of a failure, I still have to wait for 1000 minutes before I can tell the dev team about the failure.
Is there a better approach to solve this problem? It is also keeping my browser open for 1000 mins
Regarding your question -- is there a better way to solve this problem? With Selenium, not really. You'd have better luck taking a different approach, such as API, than through UI testing. However, it's still possible, just not ideal.
My best idea for this problem would be to set up some sort of controller that can manage your WebDriver instances and also keep track of the 12-16 hour queue time. Since I don't have any specific information about your project architecture or the queues you are testing, this will be a very generic implementation.
Here's a simple DriverManager class, that controls creating & terminating WebDriver sessions:
public class DriverManager
{
public IWebDriver CreateDriver
{
// code to initialize your WebDriver instance here
}
public void CloseWebDriverSession
{
Driver.Close();
Driver.Quit();
}
}
Next, here's a test case implementation that utilizes DriverManager to close & reopen WebDriver as needed.
public class TestBothQueues
{
// this driver instance will keep track of your session throughout the test case
public IWebDriver driver;
[Test]
public void ShouldRunBothQueues
{
// declare instance of DriverManager class
DriverManager manager = new DriverManager();
// start a webdriver instance
driver = manager.CreateDriver();
// run the first queue
RunFirstQueue();
// terminate the WebDriver so we don't have browser open for 12 hours
manager.CloseWebDriverSession();
// wait 12 hours
Thread.Sleep(TimeSpan.FromHours(12));
// start another WebDriver session to start the second queue
driver = manager.CreateDriver();
// run the second queue
RunSecondQueue();
// terminate when we are finished
manager.CloseWebDriverSession();
}
}
A few notes on this:
You can also convert this code into a while loop if you would like to start a WebDriver instance to check the queue on a time interval. For example, if the queue takes 12-16 hours to finish, you may want to wait 12 hours, then check the queue once per hour until you can verify it is completed. That would look something like this:
// first, wait initial 12 hours
Thread.Sleep(TimeSpan.FromHours(12));
// keep track of whether or not queue is finished
bool isQueueFinished = false;
while (!isQueueFinished);
{
// start webdriver instance to check the queue
IWebDriver driver = manager.CreateDriver();
// check if queue is finished
isQueueFinished = CheckIfQueueFinished(driver);
// if queue is finished, while loop will break
// if queue is not finished, close the WebDriver instance, and start again
if (!isQueueFinished)
{
// close the WebDriver since we won't need it
manager.CloseWebDriverSession();
// wait another hour
Thread.Sleep(TimeSpan.FromHours(1));
}
}
Hope this helps.

Selenium - How to handle popup with event listener (C#)

I'm using selenium with C# (default browser - FireFoX).
There are some sites that popup message after unknown time (if any).
I can't use wait or sleep, because I don't know on which screen the popup will appear. Using 'try-Catch' on each page is not very smart....
The solution I thought of, is to use an event listener to listen to the popup/s and then it will clicks the 'X' button. Of course the listener has to be in a Thread, and each test might have an array of Threads that gets the list of events and xpath/ ID's.
Did anyone do such things? Is there any example / article / tutorial to help me with it ?
10X,
Gil
Thinking of an old Chinese proverb, when faced with such questions, I go to the SeleniumHQ github repository and look at the tests.
You want your wait time to be small so that you don't waste too much time waiting when no alert is present. You can call the pop-up handling code when a page opens or just before your test leaves that page; depends on your application's behavior.
I would simply override the FirefoxDriver to automatically accept the alert and silence the alert exception:
class FirefoxDriverEx : FirefoxDriver {
private static DesiredCapabilities Capabilities() {
var capa = DesiredCapabilities.Firefox();
capa.SetCapability(CapabilityType.UnexpectedAlertBehavior, "accept");
return capa;
}
public FirefoxDriverEx()
: base(Capabilities()) { }
protected override Response Execute(string driverCommandToExecute, Dictionary<string, object> parameters) {
try{
return base.Execute(driverCommandToExecute, parameters);
} catch (UnhandledAlertException) {
return base.Execute(driverCommandToExecute, parameters);
}
}
}
Here is a usage example:
var driver = new FirefoxDriverEx();
driver.Navigate().GoToUrl("http://the-internet.herokuapp.com/javascript_alerts");
driver.FindElementByXPath("//button[.='Click for JS Alert']").Click();
string text = driver.FindElementById("result").Text;

C# Webdriver - Page Title assert fails before page loads

This issue began when I switched from testing on the www website to my localhost version of it. Working in VS 2012, I will begin debugging so the localhost is active, detach the process so I can test on it, then run any test I like. For a very basic example:
[Test]
public void CanGoToHomePage()
{
Pages.HomePage.Goto();
Assert.IsTrue(Pages.HomePage.IsAt());
}
And the functions it references are here:
public class HomePage
{
const string Url = "http://localhost:3738";
const string HomepageTitle = "FunnelFire - Home Page";
public void Goto()
{
Browser.Goto(Url);
}
public bool IsAt()
{
return Browser.Title == HomepageTitle;
}
}
And the actual selenium code here:
public static class Browser
{
static IWebDriver webDriver = new FirefoxDriver();
public static void Goto(string url)
{
webDriver.Manage().Window.Maximize();
webDriver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
webDriver.Url = url;
}
}
Now the issue. The 10 second implicit wait that I added in Browser does successfully wait at most 10 seconds after loading a page to see if it can locate whatever information I want it to find, that is not the problem.
As I said earlier, after I switched to testing on localhost, suddenly I ran into a strange issue where a page would begin to load (i.e. screen still totally white, nothing finished) or even sometimes the next page would JUST barely finish loading and suddenly the test would just up and fail, pointing to the Assert of IsAt returning false even though the page it was loading was the correct one. I could run that test immediately once more and it would pass without a problem. Run it a third time and it could randomly fail again. I'm honestly not sure what is causing the issue and any help would be appreciated!
Implicit waits work only for finding elements. For waiting on the title of the page to be a certain value, you'll want to use an explicit wait. You can write your own version of this pattern, but in the .NET bindings, the WebDriver.Support.dll assembly has a WebDriverWait class to help with this. Its use would look something like this:
// WARNING! Untested code written from memory below. It has not
// been tested or even compiled in an IDE, so may be syntactically
// incorrect. The concept, however, should still be valid.
public void WaitForTitle(IWebDriver driver, string title, TimeSpan timeout)
{
WebDriverWait wait = new WebDriverWait(driver, timeout);
wait.Until((d) => { return d.Title == title; });
}
You could even modify your IsAt method to use this pattern, catching the WebDriverTimeoutException and returning false if the wait function times out.

How to dispose IE when form is closed?

I've been looking for an answer to this problem, but couldn't find it anywhere.
I have written an app that utilizes Watin. It works fine, apart from the problem that if I click the "X" button to close the app BEFORE Watin completes all of the actions (before it's disposed, I guess), it doesn't close. My app is still running (although the form is no longer there), as well as all of the IE instances.
I guess I should use FormClosing event handler to kill Watin, but since I'm utilizing the using statement, I've no idea how to achieve that.
Here's a piece of code I'm using:
using (var newBrowser = new IE("http://address.com"))
{
AnalyzeTools FormActions = new AnalyzeTools(progressBar, labelProgress, labelProgressOutOf, richBoxKeywords.Lines.Count());
Analyzer Analytic = new Analyzer(newBrowser, richBoxKeywords.Lines.ToList<string>(), FormActions);
BeingAnalyzed = Analytic;
Analytic.Initialize(textBoxLogin.Text, textBoxPass.Text);
Analytic.HandleAnalysis();
}
EDIT:
OK, I did some more trouble-shooting and this is what I've come up with:
The app is working until all it's finished, simple as that. But it doesn't finish "properly", though -- it crashes, because it can't access the form which no longer exists.
I believe I could fix this by creating a FormClosing or FormClosed event that when triggered, would modify the behaviour of my app. A custom "exit" method. But still, I won't be terminating Watin (something I want to do) and the app would be still running.
The thing is, I don't really need it to accomplish all of the actions it's supposed to.
Is my idea of termination a good one? And is there a way to terminate Watin without dropping the using-statement idea?
EDIT 2:
OK, I tried a few new things.
I created that messagebox which asks for a decision. I tried using Application.Exit() to terminate, but it doesn't work as I hoped it would. The app's vshost is still running (WatiN?).
So I guess my question comes to this: is the only way to terminate WatiN to drop the using statement, make the IE object available everywhere in the class and dispose it when the user chooses to terminate it?
I think what you need to do is create an instance of IE and then just close that instance. When you need it again you can just recreate the instance. I found this on Stackoverflow a long time ago when I had a similiar problem but I couldn't find it again to link to it.
public sealed class BrowserIE
{
static readonly IE _Instance = new IE();
static BrowserIE()
{}
BrowserIE()
{ }
public static IE Instance
{
get { return _Instance; }
}
}
create a class with the code above. use
var browser = BrowserIE.Instance("myUrl");
and when your done with it use:
browser.Close();
hope this helps. If you have any other questions I'll try to help.
Which version of WatIn are you using
Watin has a specific dispose method for this job
browser.Dispose();

Categories