使用 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