【问题标题】:Resolving promises in Protractor and Cucumber using Chai as Promised使用 Chai as Promised 解决 Protractor 和 Cucumber 中的承诺
【发布时间】:2015-07-13 18:29:53
【问题描述】:

最近,我和一位同事在使用 Protractor 和 Chai as Promised 实现 Cucumber 步骤定义的“正确”方式上存在一些分歧。我们的争论源于双方对 Cucumber 上下文中的承诺解决方案的确切含义缺乏了解。

我们正在针对 AngularJS 应用程序进行测试,因此解决 Promise 和异步行为是必不可少的。我们遇到的最大问题是强制同步测试行为并让 Cucumber 等待步骤定义之间的承诺。在某些情况下,我们观察到这样的情况,Cucumber 似乎在 Webdriver 执行步骤定义之前就直接完成了步骤定义。我们对这个问题的解决方案各不相同......

考虑假设场景:

Scenario: When a user logs in, they should see search form
  Given a user exists in the system
  When the user logs into the application
  Then the search form should be displayed

大部分的困惑源于 Then 步骤。在这个例子中,定义应该断言搜索表单的所有字段都存在于页面上,这意味着多个 isPresent() 检查。

从我能找到的文档和示例中,我觉得断言应该是这样的:

this.Then(/the search form should be displayed/, function(next) {
    expect(element(by.model('searchTerms')).isPresent()).to.eventually.be.true;
    expect(element(by.model('optionsBox')).isPresent()).to.eventually.be.true;
    expect(element(by.button('Run Search')).isPresent()).to.eventually.be.true.and.notify(next);
});

但是,我的同事认为,为了满足承诺解决方案,您需要将期望与 then() 链接起来,如下所示:

this.Then(/the search form should be displayed/, function(next) {
    element(by.model('searchTerms')).isPresent().then(function(result) {
        expect(result).to.be.true;

    }).then(function() {
        element(by.model('optionsBox')).isPresent().then(function(result) {
            expect(result).to.be.true;

        }).then(function() {
            element(by.button('Run Search')).isPresent().then(function(result) {
                expect(result).to.be.true;
                next;
            });
        });
    });
});

后者对我来说确实是错误的,但我也不知道前者是否正确。我理解 finally() 的方式是它与 then() 的工作方式类似,因为它在继续之前等待 promise 解决。我希望前一个示例按顺序等待每个 expect() 调用,然后在最终的 expect() 中通过 notify() 调用 next() 以向 cucumber 发出信号以继续下一步。

更令人困惑的是,我观察到其他同事这样写他们的期望:

expect(some_element).to.eventually.be.true.then(function() {
    expect(some_other_element).to.eventually.be.true.then(function() {
        expect(third_element).to.eventually.be.true.then(function() {
            next();
        });
    });
});

所以我认为我所暗示的问题是:

  • 以上任何一个都有点对吗?
  • finally() 的真正作用是什么?它会强制像 then() 这样的同步行为吗?
  • and.notify(next) 的真正作用是什么?它与在 then() 中调用 next() 有什么不同吗?
  • 是否有我们尚未找到的最佳实践指南可以更清楚地说明这些内容?

非常感谢。

【问题讨论】:

    标签: javascript angularjs protractor chai cucumberjs


    【解决方案1】:
    • 您的感觉是正确的,您的同事是错误的(尽管这是一个合理的错误!)。 Protractor 会在运行第二个之前自动等待一个 WebDriver 命令解析。因此,在您的第二个代码块中,element(by.button('Run Search')).isPresent() 将在 element(by.model('optionsBox')).isPresent()element(by.model('searchTerms')).isPresent() 都完成之前无法解析。
    • eventually 解决承诺。解释在这里:https://stackoverflow.com/a/30790425/1432449
    • 我认为这与将next() 放在then() 中没有什么不同
    • 我认为没有最佳实践指南。 Cucumber 不是 Protractor 团队的核心重点,对它的支持主要由 github 上的社区提供。如果您或您认识的人想要编写最佳实践指南,我们(量角器团队)将欢迎 PR!

    【讨论】:

    • 太好了,感谢您的澄清!我同意,基于示例和描述,在上面的示例中链接 then 似乎很有意义。我们对 Protractor 的测试有些陌生,所以这对我们来说是全新的领域。也许我们将来会考虑编写最佳实践指南。 :)
    【解决方案2】:

    对我有用的是 - 下面的函数搜索总是等于 true 的东西 - 在存在 html 标记的情况下。我在每次测试结束时调用这个函数,传入回调

    function callbackWhenDone(callback) {
        browser.wait(EC.presenceOf(element(by.css('html'))))
            .then(function () {callback();})
    }
    

    这是一个简单测试中的用法:

    this.Given(/^I go on "([^"]*)"$/, function (arg1, callback) {
        browser.get('/' + arg1);
        callbackWhenDone(callback);
    });
    

    我知道有点小技巧,但它可以完成工作并且在任何地方使用时看起来都很干净

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多