Vinni
Vinni

Reputation: 589

function timed out after 5000 milliseconds - Angular 4 - Protractor & cucumber

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;
    }
 }
}

Upvotes: 2

Views: 9149

Answers (3)

techguy2000
techguy2000

Reputation: 5161

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';

Upvotes: 2

Vinni
Vinni

Reputation: 589

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.

Upvotes: 2

quirimmo
quirimmo

Reputation: 9988

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 variable SELENIUM_PROMISE_MANAGER to 0. 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 setting SELENIUM_PROMISE_MANAGER to 1. 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 the SELENIUM_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

Upvotes: 1

Related Questions