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_)
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
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).
@charlierudolph Did you try my case (files mentioned above)?
_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
@ThaKing your example is huge and appears to be missing some dependencies.
Your code references a file get.base.url.js
which 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.
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
@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?
@pantherqin we started to rewrite our tests to the Promises and seems the error disappeared
@ThaKing what do you mean by rewrite tests to the promises, please?
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!')
});
I done the same code but till is get the " Error: function timed out, ensure the callback is executed within 72000 milliseconds"
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
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.
@sumbhatt11 What does the code look like that you wrote to address this issue?
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.
Most helpful comment
@ThaKing what do you mean by rewrite tests to the promises, please?