前提:
_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;
重现步骤:
1.第一个场景已经被DefaultTimeout下降(前面_world.js_中提到了超过30秒)
实际结果:
第二种情况因“会话 ID 为空。调用quit() 后使用WebDriver?”而失败。 例外。 但
第三个通过。
预期结果
第二种情况也应该通过。 之前的测试不应该影响另一个
你能提供输出吗? 我刚刚测试了一个非常小的例子,我在世界构造函数中创建了一个 webdriver 并在一个 after 钩子中退出,它在多个场景中都可以正常工作(直接使用 selenium webdriver,而不是量角器)。
@charlierudolph你有没有尝试过我的案例(上面提到的文件)?
_网盘控制台_
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]
_黄瓜控制台_
(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你的例子很大,似乎缺少一些依赖项。
您的代码引用了未包含的文件get.base.url.js
。
它还似乎包括在另一个未记录的进程中运行 selenium。
由于您混合承诺和回调的方式,您的After
钩子中可能没有报告某些错误。
driver.quit().then(function () {
callback();
})
使用上面的代码,您没有涵盖quit
失败的情况。 您需要添加.catch
或将第二个函数传递给.then
。 你几乎到处都有类似的问题。
Cucumber 支持返回承诺的步骤/钩子,所以我建议切换到只使用承诺。 此外,我尽量不要让步骤/挂钩超时。 如果您在步骤内部实现自己的超时,则会收到一条关于步骤失败原因的有用错误消息,而不是非常无用的消息: function timed out after 10000 milliseconds
总的来说,我相信黄瓜不会让一种情况影响另一种情况,希望通过报告其他错误,您将能够确定问题。
这次超时
_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();
});
});
我举个例子。 在现实生活中,我有做某事的方法,但它失败了
_world.js_
this.setDefaultTimeout(30000); <----- default timeout
在此超时之后,下一个场景因异常而失败。
get.base.url.js
返回应用程序 url 和 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();
也许,这不是黄瓜 js 的问题,感谢您的帮助
@ThaKing
你好,
我遇到了同样的问题。 (第一个场景超时,第二个立即显示错误“WebDriverError:会话 ID 为空。调用 quit() 后使用 WebDriver?”)
你有没有找到任何解决办法?
@pantherqin我们开始将测试重写为
@ThaKing重写对承诺的测试是什么意思?
当您使用 restartBrowserBetweenTests: true 时,我对这个失败做了一个解决方案,当浏览器重新启动时它丢失了引用,因为它无法与页面交互,要解决这个问题,您必须在对象中执行一个函数来初始化定位器,必须始终调用该函数,您将运行测试。
在我的存储库中有一个我做的解决方案: https :
PageObejct 文件: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();
}
}
规范文件: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!')
});
我做了相同的代码,但直到得到“错误:函数超时,确保回调在 72000 毫秒内执行”
我做了相同的代码,但直到得到“错误:函数超时,确保回调在 72000 毫秒内执行”
我发给你了,怎么解决。
https://medium.com/@melayer.sima/spec -spec-js-6d4d8f6d7b1a
我遇到了同样的问题。 经过几个小时的调查和调试,我注意到我们的框架仅在驱动程序实例为空时才创建一个新的驱动程序实例,如果它不为空,则返回前一个实例。 我假设调用 driver.quit() 不会自动为当前驱动程序实例分配一个空值,因此我通过在我的 After 钩子上显式设置该值为空来解决这个问题。
希望这可以帮助有类似问题的人。
@sumbhatt11您为解决此问题而编写的代码是什么样的?
我遇到了同样的错误。 正如@sumbhatt11所做的那样,我搜索了几个小时。 我有一个 Driver.java 类只能有 1 个驱动程序。 它的单例逻辑。 如果已经有驱动程序,我会通过调用我编写的 Driver.getDriver 方法来使用它。 通过使用这种方法,我解决了错误。 据我所知,它仅提供 1 个驱动程序和 1 个会话 ID。 不要在每个类中都使用静态 WebDrivers。 创建一个 Driver 类,编写一个驱动程序初始化程序和 getter 方法。
最有用的评论
@ThaKing重写对承诺的测试是什么意思?