Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Session ID is null. Using WebDriver after calling quit()?" or "NoSuchSessionError: This driver instance does not have a valid session ID (did you call WebDriver.quit()?) and may no longer be used." when next scenario runs #709

Closed
ThaKing opened this issue Dec 29, 2016 · 14 comments

Comments

@ThaKing
Copy link

ThaKing commented Dec 29, 2016

Precondition:
test.feature

Feature:  Three tests

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

Scenario: one
    When something happens     <------ failed by timeout

Scenario: two
    When something else happens

Scenario: three
    When something else happens

world.js

var pc = require('../../../lib/index.js');
var url = require('../../../lib/get.base.url.js');

var world = function () {
    this.setDefaultTimeout(30000);   <-----   default timeout
    var seleniumAddress = url.getSeleniumHubURL();
    var options = {baseUrl: url.getBaseURL()};
    this.World = pc.world(seleniumAddress, options);
    this.After(function (scenario, callback) {
        this.takeSc(scenario, callback);
    });
};
module.exports = world;

index.js

var protractor = require('protractor');
var World = (function (seleniumAddress, options) {
        var desiredCapabilities = options.desiredCapabilities || {};
        var browserOpt = options.browser || desiredCapabilities.browser || "chrome";
        var timeout = options.timeout || 100000;

        function World() {
            var capabilities = protractor.Capabilities[browserOpt]().merge(desiredCapabilities);
            var driver = new protractor.Builder()
                .usingServer(seleniumAddress)
                .withCapabilities(capabilities)
                .build();

            driver.manage().timeouts().setScriptTimeout(timeout);
            var winHandleBefore;
            driver.getWindowHandle().then(function (result) {
                winHandleBefore = result;
            });

            this.browser = protractor.wrapDriver(driver);
            this.protractor = protractor;
            this.by = new protractor.ProtractorBy;

            if (options.assert) this.assert = options.assert;
            if (options.baseUrl) this.baseUrl = options.baseUrl;
            if (options.properties) this.properties = options.properties;

            console.log("Base URL:" + this.baseUrl);

            this.takeSc = function (scenario, callback) {
                if (scenario.isFailed()) {
                    driver.takeScreenshot().then(function (png) {
                        var decodedImage = new Buffer(png, 'base64');
                        scenario.attach(decodedImage, 'image/png');
                    }).then(function () {
                        driver.quit().then(function () {
                            callback();
                        });
                    });
                }
                else {
                    driver.quit().then(function () {
                        callback();
                    });
                }
            };
        }

        return World;
    });
module.exports.world = World;

steps.js

var steps = function () {
    this.When(/^something happens$/, function (callback) {
        this.browser.sleep(13000);
        this.browser.findElement(this.by.xpath("//somexpath")).getText().then(function (result) {
            callback();
        });
    });

    this.When(/^something else happens$/, function (callback) {
        this.browser.ignoreSynchronization = false;
        this.browser.get("http://gmail.com").then(function () {
            callback();
        });
    });

    this.When(/^Given I navigate to "([^"]*)"$/, function (site, callback) {
        this.browser.ignoreSynchronization = true;
        this.browser.get(site).then(function () {
            callback();
        });
    });
};

module.exports = steps;

Steps to reproduce:
1.The First scenario has fallen by DefaultTimeout (more than 30 secs as mentioned before in world.js)
2. The second scenario starts

Actual result:
The second scenario failed with "Session ID is null. Using WebDriver after calling quit()?" exception. But
third one is passed.

Expected result
The second scenario should passed too. The previous tests should not impact another

@ThaKing ThaKing changed the title "Session ID is null. Using WebDriver after calling quit()?" when next scenario runs "Session ID is null. Using WebDriver after calling quit()?" or "NoSuchSessionError: This driver instance does not have a valid session ID (did you call WebDriver.quit()?) and may no longer be used." when next scenario runs Dec 29, 2016
@charlierudolph
Copy link
Member

Can you please provide the output? I just tested a very small example where I create a webdriver in the world constructor and quit in an after hook and it works fine with multiple scenarios (using selenium webdriver directly, not protractor).

@ThaKing
Copy link
Author

ThaKing commented Dec 30, 2016

@charlierudolph Did you try my case (files mentioned above)?

@ThaKing
Copy link
Author

ThaKing commented Dec 30, 2016

webdrive console

17:13:29.349 INFO - Executing: [new session: Capabilities [{browserName=chrome}]])
17:13:29.351 INFO - Creating a new session for Capabilities [{browserName=chrome}]
Starting ChromeDriver 2.25.426924 (649f9b868f6783ec9de71c123212b908bf3b232e) on port 17569
Only local connections are allowed.
17:13:29.883 INFO - Done: [new session: Capabilities [{browserName=chrome}]]
17:13:29.904 INFO - Executing: [set script timeout: 100000])
17:13:29.910 INFO - Done: [set script timeout: 100000]
17:13:29.919 INFO - Executing: [get current window handle])
17:13:29.924 INFO - Done: [get current window handle]
17:13:29.932 INFO - Executing: [get: http://google.com/])
17:13:31.265 INFO - Done: [get: http://google.com/]
17:13:41.298 INFO - Executing: [take screenshot])
17:13:41.521 INFO - Done: [take screenshot]
17:13:41.531 INFO - Executing: [delete session: 8e88decd-d531-4f0c-af3c-3b5ad4136793])
17:13:41.602 INFO - Done: [delete session: 8e88decd-d531-4f0c-af3c-3b5ad4136793]
17:13:41.624 INFO - Executing: [new session: Capabilities [{browserName=chrome}]])
17:13:41.626 INFO - Creating a new session for Capabilities [{browserName=chrome}]
Starting ChromeDriver 2.25.426924 (649f9b868f6783ec9de71c123212b908bf3b232e) on port 25151
Only local connections are allowed.
17:13:42.284 INFO - Done: [new session: Capabilities [{browserName=chrome}]]
17:13:52.328 INFO - Executing: [new session: Capabilities [{browserName=chrome}]])
17:13:52.331 INFO - Creating a new session for Capabilities [{browserName=chrome}]
Starting ChromeDriver 2.25.426924 (649f9b868f6783ec9de71c123212b908bf3b232e) on port 22830
Only local connections are allowed.
17:13:52.828 INFO - Done: [new session: Capabilities [{browserName=chrome}]]
17:13:52.838 INFO - Executing: [set script timeout: 100000])
17:13:52.843 INFO - Done: [set script timeout: 100000]
17:13:52.857 INFO - Executing: [get current window handle])
17:13:52.861 INFO - Done: [get current window handle]
17:13:52.869 INFO - Executing: [get: http://google.com/])
17:13:54.128 INFO - Done: [get: http://google.com/]
17:13:54.143 INFO - Executing: [get: data:text/html,<html></html>])
17:13:54.221 INFO - Done: [get: data:text/html,<html></html>]
17:13:54.229 INFO - Executing: [execute script: window.name = "NG_DEFER_BOOTSTRAP!" + window.name;window.location.replace("http://gmail.com/");, []])
17:13:55.136 INFO - Done: [execute script: window.name = "NG_DEFER_BOOTSTRAP!" + window.name;window.location.replace("http://gmail.com/");, []]
17:13:55.146 INFO - Executing: [execute script: return window.location.href;, []])
17:13:55.168 INFO - Done: [execute script: return window.location.href;, []]
17:13:55.179 INFO - Executing: [execute async script: try { return (function (attempts, ng12Hybrid, asyncCallback) {
  var callback = function(args) {
    setTimeout(function() {
      asyncCallback(args);
    }, 0);
  };
  var check = function(n) {
    try {
      if (!ng12Hybrid && window.getAllAngularTestabilities) {
        callback({ver: 2});
      } else if (window.angular && window.angular.resumeBootstrap) {
        callback({ver: 1});
      } else if (n < 1) {
        if (window.angular) {
          callback({message: 'angular never provided resumeBootstrap'});
        } else {
          callback({message: 'retries looking for angular exceeded'});
        }
      } else {
        window.setTimeout(function() {check(n - 1);}, 1000);
      }
    } catch (e) {
      callback({message: e});
    }
  };
  check(attempts);
}).apply(this, arguments); }
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [10, false]])
17:14:04.174 INFO - Executing: [take screenshot])
17:14:05.299 INFO - Done: [execute async script: try { return (function (attempts, ng12Hybrid, asyncCallback) {
  var callback = function(args) {
    setTimeout(function() {
      asyncCallback(args);
    }, 0);
  };
  var check = function(n) {
    try {
      if (!ng12Hybrid && window.getAllAngularTestabilities) {
        callback({ver: 2});
      } else if (window.angular && window.angular.resumeBootstrap) {
        callback({ver: 1});
      } else if (n < 1) {
        if (window.angular) {
          callback({message: 'angular never provided resumeBootstrap'});
        } else {
          callback({message: 'retries looking for angular exceeded'});
        }
      } else {
        window.setTimeout(function() {check(n - 1);}, 1000);
      }
    } catch (e) {
      callback({message: e});
    }
  };
  check(attempts);
}).apply(this, arguments); }
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [10, false]]
17:14:05.546 INFO - Done: [take screenshot]

cucumber console

(node:20927) DeprecationWarning: os.tmpDir() is deprecated. Use os.tmpdir() instead.
Feature: Three tests

Base URL:http://google.com
  Scenario: one
  ✔ Given Given I navigate to "http://google.com"
  ✖ When something happens

Base URL:http://google.com
  Scenario: two
  ✖ Given Given I navigate to "http://google.com"
  - When something else happens

Base URL:http://google.com
  Scenario: three
  ✔ Given Given I navigate to "http://google.com"
  ✖ When something else happens
[17:14:05] E/protractor - Could not find Angular on page http://gmail.com/ : retries looking for angular exceeded

Failures:

1) Scenario: one - src/test/features/test.feature:6
   Step: When something happens - src/test/features/test.feature:7
   Step Definition: src/test/features/step_definitions/steps.js:3
   Message:
     function timed out after 10000 milliseconds

2) Scenario: two - src/test/features/test.feature:9
   Step: Given Given I navigate to "http://google.com" - src/test/features/test.feature:4
   Step Definition: src/test/features/step_definitions/steps.js:17
   Message:
     NoSuchSessionError: This driver instance does not have a valid session ID (did you call WebDriver.quit()?) and may no longer be used.
       at checkHasNotQuit (/home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/webdriver.js:395:15)
       at /home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/webdriver.js:382:7
       at TaskQueue.execute_ (/home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/promise.js:2913:14)
       at TaskQueue.executeNext_ (/home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/promise.js:2896:21)
       at asyncRun (/home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/promise.js:2775:27)
       at /home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/promise.js:639:7

     From: Task: WebElement.getText()
       at WebDriver.schedule (/home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/webdriver.js:377:17)
       at WebElementPromise.schedule_ (/home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/webdriver.js:1744:25)
       at WebElementPromise.getText (/home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/webdriver.js:2025:17)
       at World.<anonymous> (/home/thaking/test/tests-ui-js/src/test/features/step_definitions/steps.js:5:64)
       at _combinedTickCallback (internal/process/next_tick.js:67:7)
       at process._tickCallback (internal/process/next_tick.js:98:9)
     

3) Scenario: two - src/test/features/test.feature:9
   Step: After 
   Step Definition: src/test/features/step_definitions/support/world.js:9
   Message:
     function timed out after 10000 milliseconds

4) Scenario: three - src/test/features/test.feature:12
   Step: When something else happens - src/test/features/test.feature:13
   Step Definition: src/test/features/step_definitions/steps.js:10
   Message:
     function timed out after 10000 milliseconds

5) Scenario: three - src/test/features/test.feature:12
   Step: After 
   Step Definition: src/test/features/step_definitions/support/world.js:9
   Message:
     Error: Angular could not be found on the page http://gmail.com/. If this is not an Angular application, you may need to turn off waiting for Angular. Please see https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular-on-page-load
       at /home/thaking/test/tests-ui-js/node_modules/protractor/built/browser.js:503:23
       at ManagedPromise.invokeCallback_ (/home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/promise.js:1379:14)
       at TaskQueue.execute_ (/home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/promise.js:2913:14)
       at TaskQueue.executeNext_ (/home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/promise.js:2896:21)
       at asyncRun (/home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/promise.js:2775:27)
       at /home/thaking/test/tests-ui-js/node_modules/selenium-webdriver/lib/promise.js:639:7
       at process._tickCallback (internal/process/next_tick.js:103:7)
     
3 scenarios (3 failed)
6 steps (3 failed, 1 skipped, 2 passed)
0m35.995s

Process finished with exit code 1

@charlierudolph
Copy link
Member

charlierudolph commented Dec 30, 2016

@ThaKing your example is huge and appears to be missing some dependencies.

Your code references a file get.base.url.jswhich is not included.
It also appears to include running selenium in another process which is not documented.

It looks like some errors may not be being reported in your After hook because of how you are mixing promises and callbacks.

driver.quit().then(function () {
  callback();
})

With the above code you are not covering the case that the quit fails. You need to add .catch or pass a second function to .then. You have a similar problem almost everywhere.

Cucumber support steps/hooks that return promises, so I would advise switching to only using promises. Also I try to never let a step/hook timeout. If you implement your own timeouts on the step internals, you get a useful error message about why the step failed instead of the very un-useful message: function timed out after 10000 milliseconds

Overall, I am confident cucumber is not allowing one scenario to effect another and hopefully by getting those other errors reported you will be able to determine the issue.

@ThaKing
Copy link
Author

ThaKing commented Jan 3, 2017

This timeout
steps.js

 this.When(/^something happens$/, function (callback) {
        this.browser.sleep(13000);   <----------- timeout
        this.browser.findElement(this.by.xpath("//somexpath")).getText().then(function (result) {
            callback();
        });
    });

I used for example. In real life I have method which do something, but it failed by
world.js
this.setDefaultTimeout(30000); <----- default timeout

and after this timeout the next scenario fails by exception.

get.base.url.js returns me the application url and selenium hub url.

var url = function () {
    url.prototype.getBaseURL = function () {
        var URL = process.env.BASE_URL;
        return (URL === undefined ? 'http://google.com' : URL);
    };

    url.prototype.getSeleniumHubURL = function () {
        var SELENIUM_URL = process.env.SELENIUM_HUB_URL;
        return (SELENIUM_URL === undefined ? 'http://localhost:4444/wd/hub' : SELENIUM_URL);
    };
};

module.exports = new url();

Maybe, this is not a cucumber-js issue than thank you for help

@chuan-qin
Copy link

@ThaKing

Hi,

I am experiencing the same issue. (1st scenario timeout, 2nd immediately shows error of "WebDriverError: Session ID is null. Using WebDriver after calling quit()?")

Have you found any solution to that?

@ThaKing
Copy link
Author

ThaKing commented Mar 17, 2017

@pantherqin we started to rewrite our tests to the Promises and seems the error disappeared

@matanyos
Copy link

matanyos commented May 7, 2018

@ThaKing what do you mean by rewrite tests to the promises, please?

@tuliobluz
Copy link

tuliobluz commented Aug 10, 2018

I did one solution to this failure when you used the restartBrowserBetweenTests: true, when the browser restart it lost the references because of that it couldn't interact with the page, to solve this problem you have to do one function in an object to initialize the locators, that function must be called always you will run the test.

In my repository has a solution that I did: https://github.com/tuliobluz/protractor-cucumber-pageobject

PageObejct File: e2e/pages/spec.po.js

'use strict';

let nameInput,
  greeting;

module.exports = {
  init: () => {
    nameInput = element(by.model('yourName'));
    greeting = element(by.binding('yourName'));

  },
  get: (string) => {
    return browser.get(string);
  },
  setName: (name) => {
    return nameInput.sendKeys(name);
  },
  getGreetingText: () => {
    return greeting.getText();
  }
}

Spec file: e2e/specs/spec.spec.js

let specPage = require('../pages/spec.po.js');

let chai = require('chai');
let chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
let expect = chai.expect;
var {setDefaultTimeout} = require('cucumber');
setDefaultTimeout(60 * 1200);

Before(function(){
    specPage.init();
})

Given('The user go to {string}', function (string) {
    specPage.get(string);
});

When('The user adds {string} in the name field', function (string) {
    specPage.setName(string);
});

Then('The user should see Hello with the username', function () {
    expect(specPage.getGreetingText())
        .to.eventually.equal('Hello Tulio!')
});

@simapatil
Copy link

I done the same code but till is get the " Error: function timed out, ensure the callback is executed within 72000 milliseconds"

@tuliobluz
Copy link

I done the same code but till is get the " Error: function timed out, ensure the callback is executed within 72000 milliseconds"

I sent to you, how to fix this.

https://medium.com/@melayer.sima/spec-spec-js-6d4d8f6d7b1a

@sumbhatt11
Copy link

sumbhatt11 commented Nov 20, 2018

I was having the same issue. On investigating and debugging for hours I noticed that our framework is creating a new driver instance only when the driver instance is null and is returning the previous instance if it's not null. I assume calling driver.quit() doesn't automatically assign a null value to the current driver instance, hence I resolved the issue by explicitly setting the value as null on my After hook.
Hope this might help someone with a similar issue.

@Srutherford2407
Copy link

@sumbhatt11 What does the code look like that you wrote to address this issue?

@Salih1393
Copy link

I was getting the same error. As @sumbhatt11 did, I searched for it for hours. I have a Driver.java class to be able to have only 1 driver. Its the singleton logic. If there is already a driver, I use it by calling Driver.getDriver method that I coded. By using this methodology, I solved the error. It provides only 1 driver and only 1 session ID as far as I understood. Don't use static WebDrivers in every class. Create a Driver class, code a driver initializer and getter method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants