使用 Chai 解决 Protractor 和 Cucumber 中的承诺
Resolving promises in Protractor and Cucumber using Chai as Promised
最近我和一位同事在 "right" 中使用 Protractor 和 Chai 实现 Cucumber 步骤定义的方式存在一些分歧。我们的争论来自于相互缺乏对 Cucumber 上下文中 promise 解析的准确理解。
我们正在针对 AngularJS 应用程序进行测试,因此解决承诺和异步行为是必要的。我们遇到的最大问题是强制执行同步测试行为并让 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;
});
});
});
});
后者我觉得很不对,但我也不知道前者对不对。我对 eventually() 的理解是,它的工作方式与 then() 类似,因为它会等待 promise 解决后再继续。我希望前面的示例按顺序等待每个 expect() 调用,然后在最后的 expect() 中通过 notify() 调用 next() 以向黄瓜发出信号以继续下一步。
更令人困惑的是,我观察到其他同事这样写他们的期望:
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();
});
});
});
所以我想我暗示的问题是:
- 以上任何一项 有点 对吗?
- eventually() 到底做了什么?它会强制像 then() 这样的同步行为吗?
- and.notify(next) 到底是做什么的?它与在 then() 内部调用 next() 不同吗?
- 是否有我们尚未找到的最佳实践指南,可以更清楚地说明这些问题?
非常感谢。
- 你的感觉是正确的,你的同事是错误的(虽然这是一个合理的错误!)。量角器自动等待一个 WebDriver 命令在 运行 秒之前解决。因此,在您的第二个代码块中,
element(by.button('Run Search')).isPresent()
在 element(by.model('optionsBox')).isPresent()
和 element(by.model('searchTerms')).isPresent()
都完成之前不会解析。
eventually
解决承诺。解释在这里:
- 我不认为这与将
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,但它可以完成工作,而且在任何地方使用时看起来都非常干净
最近我和一位同事在 "right" 中使用 Protractor 和 Chai 实现 Cucumber 步骤定义的方式存在一些分歧。我们的争论来自于相互缺乏对 Cucumber 上下文中 promise 解析的准确理解。
我们正在针对 AngularJS 应用程序进行测试,因此解决承诺和异步行为是必要的。我们遇到的最大问题是强制执行同步测试行为并让 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;
});
});
});
});
后者我觉得很不对,但我也不知道前者对不对。我对 eventually() 的理解是,它的工作方式与 then() 类似,因为它会等待 promise 解决后再继续。我希望前面的示例按顺序等待每个 expect() 调用,然后在最后的 expect() 中通过 notify() 调用 next() 以向黄瓜发出信号以继续下一步。
更令人困惑的是,我观察到其他同事这样写他们的期望:
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();
});
});
});
所以我想我暗示的问题是:
- 以上任何一项 有点 对吗?
- eventually() 到底做了什么?它会强制像 then() 这样的同步行为吗?
- and.notify(next) 到底是做什么的?它与在 then() 内部调用 next() 不同吗?
- 是否有我们尚未找到的最佳实践指南,可以更清楚地说明这些问题?
非常感谢。
- 你的感觉是正确的,你的同事是错误的(虽然这是一个合理的错误!)。量角器自动等待一个 WebDriver 命令在 运行 秒之前解决。因此,在您的第二个代码块中,
element(by.button('Run Search')).isPresent()
在element(by.model('optionsBox')).isPresent()
和element(by.model('searchTerms')).isPresent()
都完成之前不会解析。 eventually
解决承诺。解释在这里:- 我不认为这与将
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,但它可以完成工作,而且在任何地方使用时看起来都非常干净