SessionNotFoundException: Session ID is null. Using WebDriver after calling quit()? (Selenium)

kroe761 picture kroe761 · Dec 27, 2016 · Viewed 43.5k times · Source

I am trying to write some selenium automated UI tests using Cucumber/Java. If I have only one test in my feature file, everything works fine. But if I add a second test, I get this error on driver.get():

org.openqa.selenium.remote.SessionNotFoundException: Session ID is null. Using WebDriver after calling quit()?
Build info: version: '2.51.0', revision: '1af067dbcaedd7d2ab9af5151fc471d363d97193', time: '2016-02-05 11:20:57'

Basically, I am initializing the webdriver variable on the InitializeWebdriver class in one package, and then referencing it in the other (step definition) classes. I did have the step definition listed below as a part of the InitializeWebdriver class, and it was working just fine (until moved on to a different step in a different class. So I moved that step to a CommonSteps.java file to see if it would then fail, and it did. So now I'm just stuck. I was thinking of doing an if (driver.equals(null)) in the @Before and doing a different action if had already been initialized, but I don't know what that other action would be.

Here is my code:

tests.feature

Feature:  Two tests

Background:
    Given I navigate to "http://www.google.com"

Scenario: Test one
    When something happens

Scenario: Test two
    When something else happens

InitializeWebDriver.java

public class InitializeWebDriver {

    public static WebDriver driver = null;

    @Before
    public void beforeScenario() {
        driver = new ChromeDriver();
    }

    @After
    public void afterScenario() {
        driver.quit();
    }
}

CommonSteps.java

import myPackage.InitializeWebDriver;

public class CommonSteps {

    static WebDriver driver = InitializeWebDriver.driver;

    @Given("^I navigate to \"([^\"]*)\"$")
    public void i_navigate_to(String url) {
        driver.get(value);
    }

Thanks!

Answer

David Knipe picture David Knipe · Dec 28, 2016

I don't think driver is null, that would cause a NullPointerException and it would have no way of knowing to convert it to a SessionNotFoundException. So it looks like driver has been created and then ended, i.e. .quit() has been called too soon, as suggested in the error message.

Here's what I think is happening:

  1. It starts the first test and calls the @Before. This causes InitializeWebDriver.driver to be set as the new WebDriver.
  2. Only after that does it load the class CommonSteps, so CommonSteps.driver is set to the WebDriver that was just created.
  3. The test runs successfully, and .quit() is called on the WebDriver, in the @After method.
  4. Then it starts the second test. A new WebDriver is created in the @Before method. InitializeWebDriver.driver is updated; however, CommonSteps.driver is not updated, because the driver = InitializeWebDriver.driver; only happens when CommonSteps is first loaded.
  5. Therefore, when it gets to driver.get(value), driver is the original WebDriver, which has already been .quit().

This is assuming you're running the tests in series. If they're in parallel then it will be a bit different.

Basically the problem is that you're using static attributes for WebDriver, which shouldn't be shared between different test runs. It's a while since I've done this stuff, and I don't remember how you store variables scoped to a test run. (In any case I wouldn't be able to answer with certainty, since you haven't said which test framework you're using: JUnit, or something else?) So you'll have to fix it yourself, or ask how to get test-scoped variables in whatever framework you're using.

That's if you want to do it properly. If you just want a cheap fix, and if you're not planning to run tests in parallel, I suspect that you can fix it by changing driver.get(value); to InitializeWebDriver.driver.get(value);. In fact, I suggest you try changing that anyway, just to make sure I'm right about this.