2

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

索引.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: ロケーターを使用して要素が見つかりません: by.model("AintNoGood") ... 1 つのシナリオ (1 つが失敗) 3 つのステップ (1 つが失敗、2 つが成功)

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>

シナリオを 1 ステップずつ実行していると仮定して、失敗すると仮定して 2 番目のステップの定義を記述します。

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 つの合格)

したがって、2 番目のステップはパスします。明らかに、html に配置されているはずの要素がない場合は、そうすべきではありません。

質問:

ここで何が起こっているのか分かりますか?

そうでない場合は、それを理解するためにもっと時間を費やす前に、誰かが CucumberJS で分度器を使用して成功したかどうか疑問に思っていますか?

4

1 に答える 1

2

これ:

browser.get('').then(
    callback());
});

次のようにする必要があります。

browser.get('').then(callback);

そのまま、すぐに を呼び出して、callback返されたものを引数として に渡します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とhttps://github.comを読んでください。 /SeleniumHQ/selenium/wiki/WebDriverJs#control-flows .

于 2015-04-15T02:21:41.703 に答える