使用Chai as promises解决了Protractor和Cucumber中的承诺问题

Resolving promises in Protractor and Cucumber using Chai as Promised

本文关键字:Cucumber 承诺 问题 Protractor as Chai promises 解决 使用      更新时间:2023-09-26

最近,我和一位同事在使用Protractor和Chai as promise实现黄瓜步骤定义的"正确"方式上发生了一些分歧。我们的争论来自于双方都缺乏对Cucumber上下文中的promise resolution到底是怎么回事的理解。

我们是针对AngularJS应用进行测试,所以解析承诺和异步行为是必要的。我们遇到的最大问题是强制同步测试行为,并让Cucumber等待步骤定义之间的承诺。在某些情况下,我们观察到在Webdriver执行步骤定义之前,Cucumber似乎直接通过了这些步骤定义。我们对这个问题的解决办法各不相同。

考虑假设的场景:

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

我觉得后者真的错了,但我也不知道前者是否正确。我对最终()的理解是,它的工作方式类似于then(),因为它在继续之前等待承诺解决。我希望前一个示例按顺序等待每个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();
        });
    });
});

我想我暗示的问题是:

  • 以上甚至有点对吗?
  • 最终()真正做什么?它是否像then()那样强制执行同步行为?
  • and.notify(next)的真正作用是什么?它与在then()中调用next()不同吗?
  • 有没有我们还没有找到的最佳实践指南,可以更清楚地说明这一点?

提前感谢。

    你的感觉是正确的,你的同事错了(尽管这是一个合理的错误!)Protractor在运行第二个WebDriver命令之前会自动等待一个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!

对我来说是这样的-下面的函数搜索总是等于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);
});

我知道这是一个hack,但是它完成了工作,看起来很干净,当在任何地方使用