使用AngularJS尝试一些BDD,这样我就可以使用Protractor和CucumberJS自动化场景了。奇怪的是,魔鬼的工作是试图让步骤定义明智地失败。
Features.feature
Feature: Calculator
As a user
I want to perform arithmetic operations
So that I don't have to think too hard
Scenario: Addition
Given I have opened the calculator application
When I add 2 and 2
Then the result 4 should be displayed
Steps.js
module.exports = function() {
this.Given(/^I have opened the calculator application$/, function (callback) {
//load protractor config baseurl
browser.get('').then(
callback());
});
this.When(/^I add (\d+) and (\d+)$/, function (arg1, arg2, callback) {
//enter numbers to be added
element(by.model('firstNumber')).sendKeys(arg1);
element(by.model('secondNumber')).sendKeys(arg2);
//select mathematical operator from dropdown list
element(by.css('select')).click();
element(by.css('select option[value="0"]')).click();
//hit the calculate button
element(by.buttonText('=')).click();
callback();
});
this.Then(/^the result (\d+) should be displayed$/, function (arg1, callback) {
element(by.binding('result')).getText()
.then(function(result){
result === arg1 ? callback() : callback.fail();
});
});
};
的index.html
<!doctype html>
<html class="no-js">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body ng-app="calculator" ng-controller="MainCtrl">
<input ng-model="firstNumber">
<select ng-model="selectedOperation" ng-options="op as op.value for op in operations"></select>
<input ng-model="secondNumber">
<button ng-click="Calculate()">=</button>
<span ng-bind="result"></span>
<script src="bower_components/angular/angular.js"></script>
<script src="scripts/app.js"></script>
</body>
</html>
App.js
angular
.module('calculator', [])
.controller('MainCtrl', function ($scope) {
$scope.operations = [
{ label: 'Add', value: '+' },
{ label: 'Subtract', value: '-' }
];
$scope.selectedOperation = $scope.operations[0];
$scope.Calculate = function(){
switch($scope.selectedOperation.label) {
case 'Add':
var result = Number($scope.firstNumber) + Number($scope.secondNumber);
break;
case 'Subtract':
var result = Number($scope.firstNumber) - Number($scope.secondNumber);
break;
};
$scope.result = result !== NaN || result === 0 ? result : 'Boo! bad input!';
};
});
量角器输出:
1个场景(1个通过) 3个步骤(3个通过)
上面的设置工作正常。量角器提供正确的输出,我可以通过在Then()步骤中评估不正确的结果来使方案失败。看起来很好。
我看到的第一个问题是当我尝试使When步骤失败时。例如,使用上面相同的设置,但尝试找到不存在的元素。
this.When(/^I add (\d+) and (\d+)$/, function (arg1, arg2, callback) {
//enter numbers to be added. Sabotage edition!
element(by.model('AintNoGood')).sendKeys(arg1);
element(by.model('secondNumber')).sendKeys(arg2);
//select mathematical operator from dropdown list
element(by.css('select')).click();
element(by.css('select option[value="0"]')).click();
//hit the calculate button
element(by.buttonText('=')).click();
callback();
});
量角器输出: NoSuchElementError:找不到使用locator找到的元素:by.model(&#34; AintNoGood&#34;) ... 1个场景(1个失败) 3个步骤(1个失败,2个过去)
第二步失败了。我的印象是,当步骤失败时,所有后续步骤都会被跳过,但量角器继续进行到第3步,无论如何都要通过。
陌生人仍然......我清空了HTML。 BDD测试优先和所有。
Inmdex.html
<!doctype html>
<html class="no-js">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body ng-app="calculator" ng-controller="MainCtrl">
<!--Ghost town here-->
<script src="bower_components/angular/angular.js"></script>
<script src="scripts/app.js"></script>
</body>
</html>
假设我一次一步地完成这个场景,我会在第二步写下定义,假设它会失败。
module.exports = function() {
this.Given(/^I have opened the calculator application$/, function (callback) {
//load protractor config baseurl
browser.get('').then(
callback());
});
this.When(/^I add (\d+) and (\d+)$/, function (arg1, arg2, callback) {
//enter numbers to be added
element(by.model('firstNumber')).sendKeys(arg1);
element(by.model('secondNumber')).sendKeys(arg2);
//select mathematical operator from dropdown list
element(by.css('select')).click();
element(by.css('select option[value="0"]')).click();
//hit the calculate button
element(by.buttonText('=')).click();
callback();
});
this.Then(/^the result (\d+) should be displayed$/, function (arg1, callback) {
callback.pending();
});
};
量角器输出: 1个场景(1个待定) 3个步骤(1个待定,2个通过)
所以第二步过去了。显然它不应该没有它应该在html中定位的元素。
问题:
知道这里发生了什么吗?
如果没有,在我花更多时间去理解它之前,我想知道是否有人在使用Protractor和CucumberJS时取得了成功?
答案 0 :(得分:2)
此:
browser.get('').then(
callback());
});
应该是:
browser.get('').then(callback);
实际上,您立即调用callback
并将其返回的任何内容作为参数传递给then
。
在您的第一个this.When
结尾处:
callback();
但它前面的element()
调用链不会阻塞。他们只是安排在WebDriver控制流程上完成操作,所以我怀疑这个&#34; callback()&#34;将立即被调用。您可以通过执行以下操作来解决此问题:
element(by.buttonText('=')).click().then(callback);
获取在控制流中安排的回调。
WebDriver控制流程违反直觉并且常常是钝的,因此您需要阅读https://github.com/angular/protractor/blob/master/docs/control-flow.md和https://github.com/SeleniumHQ/selenium/wiki/WebDriverJs#control-flows。