【问题标题】:Is it possible to time out a cucumber.js step defintion是否可以使 cucumber.js 步骤定义超时
【发布时间】:2014-01-18 18:32:27
【问题描述】:

在 cucumber.js 中,我定义了一个步骤,类似于:

this.When(/^I call getCollections$/, function(callback) {

    this.repo.getCollections( function( err, results ) {

        this.results = results;
        callback( err );

    }.bind( this ) );

});

但是如果对 this.repo.getColections 的调用从不回调我的函数,那么 callback 将永远不会执行,并且 cucumber.js 会立即以正常的退出代码退出。

如果从不调用回调,有没有办法让 cucumber.js 失败?

【问题讨论】:

    标签: javascript cucumber cucumberjs


    【解决方案1】:

    类似的东西应该可以解决问题:

    this.Given(/^blah$/, function (callback) {
      var failed = false;
      var timeout = setTimeout(function () {
        callback(new Error("Timed out"));
      }, 500);
    
      doSomethingThatMightNeverCallback(function (err) {
        if (!failed) {
          clearTimeout(timeout);
          callback(err);
        }
      });
    });
    

    您可以轻松地重新定义 Cucumber 的 Given/When/Then:

    var cucumber = this;
    var Given = When = Then = defineStep;
    function defineStep (name, handler) {
      cucumber.defineStep(name, function () {
        var world = this;
        var args = Array.prototype.splice.call(arguments, 0);
        var callback = args.pop();
    
        var failed = false;
        var timeout = setTimeout(function () {
          callback(new Error("Timed out"));
        }, 500);
    
        args.push(function (err) {
          if (!failed) {
            clearTimeout(timeout);
            callback(err);
          }
        });
        handler.apply(world, args);
      });
    }
    

    然后使用Given()When()Then() 而不是this.Given() 等来定义您的步骤:

    Given(/^foo$/, function (callback) {
      setTimeout(callback, 400); // this will pass
    });
    
    Given(/^bar$/, function (callback) {
      setTimeout(callback, 500); // this will fail
    });
    
    When(/^baz$/, function (callback) {
      doYourStuff(callback);
    });
    

    正如预期的那样,我在第 2 步中遇到了以下情况:

    Feature: Baz
    
      Scenario:
        Given foo
        And bar
    

    输出:

    cucumber.js test.feature 
    .F
    
    (::) failed steps (::)
    
    Error: Timed out
        at null._onTimeout (/Users/jbpros/tmp/abc/code.js:13:18)
        at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
    
    Failing scenarios:
    /Users/jbpros/tmp/abc/test.feature:3 # Scenario: 
    
    1 scenario (1 failed)
    2 steps (1 failed, 1 passed)
    

    HTH,

    • 朱利安。

    【讨论】:

    • 在 Node 中编写代码时,几乎所有事情都是回调,测试的核心部分是确定代码在每个分支上成功回调。我不必在每个 When 步骤中都编写此代码来确保这一点。我不能使用内置的 Given When Then 设施感觉不对。这是我可以在自定义 World 构造函数中重新定义的东西,以便将其隐藏起来吗?
    • 建议的解决方案确实使用了内置的 Given/When/Then。它只是将它包装到另一个以您想要的方式处理超时的函数中。为什么它没有内置是因为我们无法判断每个人对丢失回调的需求。回调问题众所周知 (github.com/cucumber/cucumber-js/issues/27),并且没有全球范围的解决方案 atm。超时可能是您项目的完美方法,但并非所有人都适用。不过,Cucumber 的“超时”插件可能会有所帮助,我正在考虑发布这样的东西。
    • 回答您的问题:不,您不能在 World 上重新定义 Given/When/Then,原因很简单,即 Worlds 在加载步骤定义后很好地实例化。话虽如此,将上面的包装器“隐藏”在它自己的模块中并在您的步骤定义中很好地加载它是很容易的。
    • 在什么情况下“丢失”回调不是会成为步骤失败的原因?
    • 绝对是失败一步的好理由。在 JavaScript 中,没有直接的方法来判断回调何时丢失,afaik。
    【解决方案2】:

    这就是我最终做的事情:

    在一个模块 utils.js 中,我公开了一个函数

    function specifyTimeout( scenario, timeout ) {
    
        scenario.Before( function( callback ) {
    
            scenario.timeout = setTimeout( function() { throw new Error("Timed out"); }, 500 );
            callback();
    
        } );
    
        scenario.After( function( callback ) {
    
            clearTimeout( scenario.timeout );
            callback();
    
        } );
    
    }
    

    然后在我的步骤定义的顶部,我只是这样做:

    module.exports = function() {
    
        utils.specifyTimeout( this, 500 );
        . . .
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-24
      • 2020-10-30
      • 1970-01-01
      相关资源
      最近更新 更多