Mohit Garg
Mohit Garg

Reputation: 25

In Cucumber, callback function getting timedout though callback is called. Already increased DefaultTimeout but still error

Below is the Cucumber Given Step definition and in this callback() function was hit successfully and was able to see the console line i.e. "This is a callback function"

const assert = require('assert')
const {
	Before,
	Given,
	When,
	Then
} = require('cucumber');

var {
	setDefaultTimeout
} = require('cucumber');

setDefaultTimeout(6 * 1000);


Given('This has only one word {string}', function (string, callback) {
	console.log(string);

	function callback() {}
	callback();
});

But this step is not getting terminated, throws error "function timed out, ensure the callback is executed within 6000 milliseconds"

C:\Users\Mohit.Garg\Desktop\Cucumber practice\example5>protractor conf.js
[17:14:55] I/launcher - Running 1 instances of WebDriver
[17:14:55] I/local - Starting selenium standalone server...
[17:14:57] I/local - Selenium standalone server started at http://10.200.3.79:55733/wd/hub
(node:27784) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
Feature: Login

  Scenario: Login
    Given This has only one word "hi"
This is a callback function
    × failed
      Error: function timed out, ensure the callback is executed within 6000 milliseconds
          at Timeout._onTimeout (C:\Users\Mohit.Garg\Desktop\Cucumber practice\example5\node_modules\cucumber\src\user_code_runner.js:61:18)
          at ontimeout (timers.js:436:11)
          at tryOnTimeout (timers.js:300:5)
          at listOnTimeout (timers.js:263:5)
          at Timer.processTimers (timers.js:223:10)

I don't think this is related to DefaultTimeout becasue if I use below code with same Timeout value it runs perfectly. I have replaced "callback" in Given with different name "newcallback" and called inside callback function at the end. See below

Given('This has only one word {string}', function (string, newcallback) {
	console.log(string);

	function callback() {
		newcallback()
	}
	callback();
});

I hope am clear with my issue, your help is very much appreciated.

Upvotes: 1

Views: 1434

Answers (1)

yong
yong

Reputation: 13712

1) When there is no Async code inside the step function, no need to use the callback argument.

Then(/^the response status is (.*)$/, function (status) {
  // Synchronous code
  assert.equal(this.responseStatus, status)
});

2) But if there is any Async code inside the step function, you need to use the callback argument or return a promise.

For example:

Given('This has only one word {string}', function (string, callback) {
   // the `callback` is specified by argument: callback

   ... do other things
   // when step done invoke the `callback`
   callback()
}

Given('This has only one word {string}', function (string, abc) {
   // the `callback` is specified by argument: abc

   ... do other things
   // when step done invoke the `callback`
   abc()
}

Given('This has only {amount} word {string}', function (amount, string, xyz) {
   // the `callback` is specified by argument: xyz

   ... do other things
   // when step done invoke the `callback`
   xyz()
}

Important : Cucumber will task the last argument of the function as the callback, no matter you give the argument name to whatever string.

// Asynchronous - callback
// Take a callback as an additional argument to execute when the step is done
Then(/^the file named (.*) is empty$/, function (fileName, callback) {

  fs.readFile(fileName, 'utf8', function(error, contents) {
    if (error) {
      callback(error);
    } else {
      assert.equal(contents, '');
      callback();
    }
  });
});

// Asynchronous - promise
// Return a promise. The step is done when the promise resolves or rejects
When(/^I view my profile$/, function () {
  // Assuming this.driver is a selenium webdriver
  return this.driver.findElement({css: '.profile-link'}).then(function(element) {
    return element.click();
  });
});

Back to your code:

Given('This has only one word {string}', function (string, callback) {
    console.log(string);
    // the `callback` specified by argument: callback   

    function callback() {} 
    // you define a function, named 'callback' too, which overwrite the
    // real `callback`

    callback();
    // you invoked the function you defined, not the real `callback`,
    // so cucumber wait the real `callback` be invoked, until reach
    // the timeout, then report timeout exception. 
});

Upvotes: 1

Related Questions