使用 CucumberJS 的量角器测试不规则通过
Protractor tests with CucumberJS passing irregularly
尝试使用 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 步骤失败时。例如,使用与上面相同的设置但尝试定位 none 现有元素。
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:使用定位器未找到元素:by.model("AintNoGood")
...
1 个场景(1 个失败)
3 个步骤(1 个失败,2 个通过)
第二步正确失败。我的印象是,当一个步骤失败时,所有后续步骤都会被跳过,但量角器会继续进行到第三步,无论如何都会通过。
陌生人还是...我清空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.
中的元素有 none 时,它不应该
问题:
知道这里发生了什么吗?
如果没有,在我花更多时间尝试理解它之前,我想知道是否有人成功地将 Protractor 与 CucumberJS 结合使用?
这个:
browser.get('').then(
callback());
});
应该是:
browser.get('').then(callback);
实际上,您正在立即调用 callback
并将它 returns 作为参数传递给 then
。
在您的第一个 this.When
中,您的结尾是:
callback();
但它前面的 element()
调用链不会阻塞。他们只是安排在 WebDriver 控制流上完成的操作,所以我怀疑这个 "callback()" 几乎会立即被调用。您可以通过以下方式解决此问题:
element(by.buttonText('=')).click().then(callback);
获取控制流中安排的回调。
WebDriver 控制流是违反直觉的并且通常很迟钝,因此您需要阅读 https://github.com/angular/protractor/blob/master/docs/control-flow.md and https://github.com/SeleniumHQ/selenium/wiki/WebDriverJs#control-flows。
尝试使用 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 步骤失败时。例如,使用与上面相同的设置但尝试定位 none 现有元素。
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:使用定位器未找到元素:by.model("AintNoGood") ... 1 个场景(1 个失败) 3 个步骤(1 个失败,2 个通过)
第二步正确失败。我的印象是,当一个步骤失败时,所有后续步骤都会被跳过,但量角器会继续进行到第三步,无论如何都会通过。
陌生人还是...我清空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.
中的元素有 none 时,它不应该问题:
知道这里发生了什么吗?
如果没有,在我花更多时间尝试理解它之前,我想知道是否有人成功地将 Protractor 与 CucumberJS 结合使用?
这个:
browser.get('').then(
callback());
});
应该是:
browser.get('').then(callback);
实际上,您正在立即调用 callback
并将它 returns 作为参数传递给 then
。
在您的第一个 this.When
中,您的结尾是:
callback();
但它前面的 element()
调用链不会阻塞。他们只是安排在 WebDriver 控制流上完成的操作,所以我怀疑这个 "callback()" 几乎会立即被调用。您可以通过以下方式解决此问题:
element(by.buttonText('=')).click().then(callback);
获取控制流中安排的回调。
WebDriver 控制流是违反直觉的并且通常很迟钝,因此您需要阅读 https://github.com/angular/protractor/blob/master/docs/control-flow.md and https://github.com/SeleniumHQ/selenium/wiki/WebDriverJs#control-flows。