In Java, best way to check if Selenium WebDriver has quit
Asked Answered
K

3

34

I need to check a collection of Page Objects to see, for each one, if quit() has been called on its WebDriver.

I've written the following method to check a WebDriver's state:

public static boolean hasQuit(WebDriver driver) {
        try {
            driver.getTitle();
            return false;
        } catch (SessionNotFoundException e) {
            return true;
        }
}

Here's the problem: I don't like having to throw and catch an exception to discover the truth of a boolean, but it seems I have no choice since the WebDriver API doesn't provide a method to check if the driver has quit.

So my question is, is there a better way to check if a WebDriver has quit?

I found a similar (and more general) question here, but the question did not have any code that had been tried, and the only answer was to always set the WebDriver to null after quiting (which I don't necessarily have control over).

Keratosis answered 4/9, 2013 at 16:24 Comment(2)
You can try to find out if the firefox/chrome/IE process is either running or not. Then you can decide if the browser is open or closed. Very decisive decision.Klug
@ran in some situations setting a driver to null after quit may work, but in a lot of cases you could still have other references to the driver object, and therefore the driver is not garbage collected. So most of the time setting null after quit is not going to be a fool-proof solution.Keratosis
X
25

If quit() has been called, driver.toString() returns null:

>>> FirefoxDriver: firefox on XP (null))

Otherwise, it returns a hashcode of the object:

>>> FirefoxDriver: firefox on XP (9f897f52-3a13-40d4-800b-7dec26a0c84d)

so you could check for null when assigning a boolean:

boolean hasQuit = driver.toString().contains("(null)");
Xuthus answered 4/9, 2013 at 19:49 Comment(7)
-1: You shouldn't depend on toString() for programmatic behavior. If you bothered digging into this function you would have noticed the null is coming from sessionId so really all you need is to check if getSessionId() returns null. Ultimately, however, Sajan's answer is more reliable because there is no guarantee that all implementations will set sessionId to null but you are guaranteed that stopClient() will be called.Gnaw
@Gnaw You have a point about checking if getSessionId() == null. However, Sajan's answer is ultimately not more reliable, because it only works if the instance of the WebDriver has been subclassed as he suggested, and there is no guarantee that the WebDriver will actually have been subclassed in this way.Keratosis
@TJamesBoone, nothing prevents you from subclassing WebDriver yourself. I have done this and it works perfectly.Gnaw
@Gnaw Of course nothing prevents me from subclassing WebDriver myself. But in most selenium projects that I've worked on, there is no guarantee that the WebDriver instance passed into my method will, in fact, be one that I've subclassed. I suppose if I was the one responsible for setting up and designing the entire selenium project, I could arrange it in such a way that only my subclassed WebDrivers are ever used. But honestly, that seems like overkill just to avoid the extremely unlikely event that I might have to deal with an implementation that does not set sessionId to null.Keratosis
This doesn't work if driver executable is still running but the browser was closed for some reasons. In that case the "driver.toString().contains("(null)")" part returns false, but if I am trying accessing browser through driver it will throw an exception. Also the "? true : false" part is excessive. You should just write "boolean hasQuit = driver.toString().contains("(null)");"Kozlowski
@dnk.nitro: excessive boolean assignment noted. I edited it. I'm sure Pat Meeker won't mind.Keratosis
For the people nit picking about depending to string, it's simply the idea that was needed. The guy is not telling you what to do, just change your if logic and stop complaining. Maybe try and help someone instead of having a weird superiority complex.Voltmeter
K
16

There are basically two approaches you can take, depending on your situation.

Situation 1: Extending WebDriver is not a realistic option.

This is the most common situation. Most developers working with Selenium in real-work situations who want a handy way of telling if a WebDriver has quit are working in an already established testing framework, and trying to refactor the framework to ensure that only your custom extensions of WebDrivers are used is probably more trouble than it's worth.

In this case, Sajan's answer and Gili's recommendation of his answer won't be useful, because overriding RemoteWebDriver#stopClient() is not an option. (Besides, even if it was, most people are looking for a simple answer.)

As long as you are only using standard implementations of WebDriver that come with Selenium (FirefoxDriver, ChromeDriver, InternetExplorerDriver, SafariDriver, etc.), you can cast the WebDriver to a RemoteWebDriver and then check if the sessionId is null (Pat was on the right track, but a direct call to sessionId is better than using toString()).

public static boolean hasQuit(WebDriver driver) {
    return ((RemoteWebDriver)driver).getSessionId() == null;
}

This answer should be good for 95% of all cases, because how often are you going to use a WebDriver that doesn't implement RemoteWebDriver? (Not very often.)

Situation 2: You CAN realistically extend your WebDriver.

This situation is less common, but perhaps you are either:
    (a)  Working with a well-designed and abstracted framework, or
    (b)  Starting a selenium test framework from scratch.

In this case, you can create your own interface that extends WebDriver:

public interface CustomDriver extends WebDriver {

    boolean hasQuit();

}

And then you can extend standard WebDrivers like so (in this example, ChromeDriver):

public class CustomChromeDriver extends ChromeDriver implements CustomDriver {

    boolean hasQuit = false;

    @Override
    public boolean hasQuit() {
        return hasQuit;
    }

    @Override
    public void stopClient() {
        super.stopClient();
        hasQuit = true;
    }
}
Keratosis answered 18/12, 2014 at 6:54 Comment(1)
This is the correct approach, but does it consider the case when driver has crashed (BROWSER_TIMEOUT for example)?Bare
E
5

StopClient method will be invoked after quit (RemoteWebDriver Source) is called, may be you can subclass your instance of RemoteWebDriver and override stopClient method, set some flag and check for the flag to determine if the webdriver is closed (quit).

Eicher answered 4/9, 2013 at 16:45 Comment(2)
In general I like your idea, but: (1) I don't necessarily have control over the implementation of the WebDriver instance being used; (2) I probably want to avoid calling my own method off of a driver since it is not declared in the WebDriver interface. But otherwise a neat idea and shows good knowledge of the inner workings of RemoteWebDriver, so +1.Keratosis
Unfortunately then we have to do something like you showed before or setting webdriver to null and check.Eicher

© 2022 - 2024 — McMap. All rights reserved.