问题
I am automating an angular 4 application with protractor & cucumber framework.
Getting error for a simple button click. (Not all the times)
1) Scenario: Scenario 2 - features\Home.feature:9
Step: Then Click on edit button - features\Home.feature:11
Step Definition: stepDefinitions\FirstStep.ts:31
Message:
Error: function timed out after 5000 milliseconds
at Timeout.<anonymous> (C:\MyWorkspace\protractor-cucumber-final\protractor-cucumber-final\node_modules\cucumber\lib\user_code_runner.js:91:22)
at ontimeout (timers.js:386:14)
at tryOnTimeout (timers.js:250:5)
at Timer.listOnTimeout (timers.js:214:5)
Checked here I believe no need to set wait times as protractor is intelligent enough to resolve promises
my project details as follows:
Node: v6.10.3 protractor: v5.1.2
StepDefinition.ts:
let homePage = new HomePage();
Then(/^Click on edit button$/, async () => {
await homePage.clickEditButton();
});
HomePage.ts:
async clickEditButton() {
console.log('clicking on Edit Button');
await this.editButton.click();
}
package.json (part of it)
"main": "index.js",
"scripts": {
"test": "protractor config/config.js",
"webdriver-start": "webdriver-manager start",
"webdriver-update": "webdriver-manager update"
},
"dependencies": {
"chai": "^4.0.2",
"cucumber": "^2.3.0",
"mkdirp": "^0.5.1",
"protractor": "^5.1.1",
"protractor-cucumber-framework": "^3.1.0"
},
"devDependencies": {
"chai-as-promised": "^6.0.0",
"cucumber-html-report": "^0.6.0",
"cucumber-html-reporter": "^0.5.2",
"cucumberjs-allure-reporter": "^1.0.3",
"pg": "^6.0.3"
}
config.js
var chai = require("chai");
var chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);
exports.config = {
seleniumAddress: "http://localhost:4444/wd/hub",
baseUrl: "http://localhost:4200/",
framework: "custom",
frameworkPath: require.resolve("protractor-cucumber-framework"),
specs: ["../features/*.feature"],
exclude: "../features/database.feature",
resultJsonOutputFile: "./reports/json/protractor_report.json",
onPrepare: function() {
// browser.ignoreSynchronization = true;
browser.manage().window().maximize();
global.expect = chai.expect;
},
cucumberOpts: {
strict: true,
format: ["pretty"],
require: ["../stepDefinitions/*.js", "../support/*.js"],
tags: "@micro"
}
};
Thanks in advance
UPDATED 28-Aug'17:
ManageRecipeStep.ts
import {defineSupportCode} from 'cucumber';
import {ManageRecipePage} from "../pages/ManageRecipePage";
var chai = require("chai");
var chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);
let expect = chai.expect;
Then(/^Cancel button should be displayed$/, async () => {
await expect(manageRecipePage.getCancelButton()).to.eventually.equal('Cancel');
});
ManageRecipePage.ts
import {ActionUtil} from "../utils/ActionUtil";
import {BasePage, IdentificationType} from "../utils/BasePage";
const Locators = {
cancelByText: {
type:IdentificationType[IdentificationType.PartialButtonText],
value: "Cancel"
}
};
let actionUtil = new ActionUtil();
export class ManageRecipePage extends BasePage {
async getCancelButton() {
await actionUtil.getElementText(Locators.cancelByText);
}
}
ActionUtil.ts
import {BasePage} from "./BasePage";
export class ActionUtil {
private basePage: BasePage = new BasePage();
async getElementText(obj) {
let attempts = 0;
while(attempts < 2) {
try {
return await this.basePage.ElementLocator(obj).getText();
} catch(StaleElementException) {
console.log("EXCEPTION while getting Text" + StaleElementException);
}
attempts++;
}
return null; // todo: this case
}
BasePage.ts
import { browser, element, by, protractor, $$, $ } from 'protractor';
export enum IdentificationType {
Xpath,
Css,
Id,
Js,
Name,
PartialLinkText,
ClassName,
PartialButtonText
}
export class BasePage {
ElementLocator(obj) {
switch (obj.type) {
case IdentificationType[IdentificationType.Xpath]:
return element(by.xpath(obj.value));
case IdentificationType[IdentificationType.ClassName]:
return element(by.className(obj.value));
case IdentificationType[IdentificationType.Id]:
return element(by.id(obj.value));
case IdentificationType[IdentificationType.Js]:
return element(by.js(obj.value));
case IdentificationType[IdentificationType.Css]:
return element(by.css(obj.value));
case IdentificationType[IdentificationType.PartialButtonText]:
return element(by.partialButtonText(obj.value));
default:
break;
}
}
}
回答1:
Default timeout for cucumber is 5 sec. Setting default time (to 10 sec) worked for me. Example is here. This issue might be because application is down.
@quirimmo Thanks for your support.
回答2:
Two things:
1) Be sure to disable the WebDriver Control Flow
when using protractor with async/await
through the following command in the config:
SELENIUM_PROMISE_MANAGER: false
Here the spec of the property from the official doc:
Enable/disable the WebDriver Control Flow. WebDriverJS (and by extention, Protractor) uses a Control Flow to manage the order in which commands are executed and promises are resolved (see docs/control-flow.md for details). However, as syntax like
async
/await
are being introduced, WebDriverJS has decided to deprecate the control flow, and have users manage the asynchronous activity themselves (details here: https://github.com/SeleniumHQ/selenium/issues/2969). At the moment, the WebDriver Control Flow is still enabled by default. You can disable it by setting the environment variableSELENIUM_PROMISE_MANAGER
to0
. In a webdriver release in Q4 2017, the Control Flow will be disabled by default, but you will be able to re-enable it by settingSELENIUM_PROMISE_MANAGER
to1
. At a later point, the control flow will be removed for good. If you don't like managing environment variables, you can set this option in your config file, and Protractor will handle enabling/disabling the control flow for you. Setting this option is higher priority than theSELENIUM_PROMISE_MANAGER
environment variable. @type {boolean=}
2) Are you sure that Node 6.10.3 supports async/await
? I remember that the official default support for async/await
is since Node 7.6
回答3:
For me, (I am not using async/await), I am using
SELENIUM_PROMISE_MANAGER: true,
in protractor.conf.js
In my hooks.ts, I need either one of these:
BeforeAll({ timeout: 60 * 1000 }, () => {
setDefaultTimeout(60 * 1000);
return browser.get(config.baseUrl);
});
BeforeAll({ timeout: 60 * 1000 }, () => {
defineSupportCode( ({ setDefaultTimeout }) => {
setDefaultTimeout(60 * 1000);
});
return browser.get(config.baseUrl);
});
Here is my import:
import { Before, After, BeforeAll, defineSupportCode, Status, setDefaultTimeout } from 'cucumber';
来源:https://stackoverflow.com/questions/45852631/function-timed-out-after-5000-milliseconds-angular-4-protractor-cucumber