2013-08-19 96 views
1

我有一個叫<dimension>指令,呈現HTML:單元測試指令與<select>

angular.module('myApp.directives'). 
    directive('dimension', ['$rootScope', 'Dimension', function($rootScope, Dimension) { 
    return { 
     restrict: 'E', 
     scope: { 
     ngModel: '=', 
     inputs: '=inputsModel', 
     url: '@', 
     listenFor: '@', 
     broadcastOnChange: '@' 
     }, 
     controller: function($scope, $element, $attrs, $transclude, Dimension) { 
     this.get = function() { 
      Dimension.get($attrs.url, $scope.inputs).then(function(data) { 
      $scope.alloptions = data; 
      }); 
     }; 
     }, 
     link: function($scope, $element, $attrs, $controller) { 
     $controller.get(); 

     // Listen for changes to select, and broadcast those changes out to rootScope 
     var dimension = $($element).find('select'); 
     dimension.on('change', function(event) { 
      $rootScope.$broadcast('DimensionDirective.change', $attrs.broadcastOnChange); 
     }); 

     // Listen for the broadcast, and react if the value of the broadcast is in the listen-for attribute list 
     $rootScope.$on('DimensionDirective.change', function(event, value) { 
      if (value == $scope.listenForArray) { 
      $controller.get(); 
      } 
     }); 
     }, 
     template: 
      '<div>' + 
      '<label ng-transclude></label>' + 
      '<fieldset>' + 
       '<div class="form-group">' + 
        '<select ng-model="ngModel" ng-options="x for x in alloptions" multiple class="form-control"></select>' + 
       '</div>' + 
      '</fieldset>' + 
      '</div>', 
     replace: true, 
     transclude: true 
    }; 
    }]). 
    factory('Dimension', 
    ["$http", function($http) { 
     return { 
     get: function(_url, _inputs) { 
      var future; 
      future = $http({ 
      url: _url, 
      method: 'POST', 
      data: _inputs 
      }); 
      return future.then(function(response) { 
      return response.data; 
      }); 
     } 
     }; 
    } 
    ]); 

我現在想創建一個單元測試來驗證有在選擇正確的元素數量,之後便從xhr加載。我創建了一個大致如下所示的單元測試:

describe('directive', function() { 
    var $httpBackend; 

    beforeEach(module('myApp.directives')); 

    beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) { 
    $httpBackend = _$httpBackend_; 
    $httpBackend.expectPOST('url'). 
     respond(["Item 1", "Item 2"]); 
    })); 

    it('should load select\'s options from xhr on render', function() { 
    inject(function($compile, $rootScope) { 
     var element = $compile('<dimension ng-model="inputs.model" url="url">Dimension</dimension>')($rootScope); 
     var select = element.find('select'); 
     expect(element.find('select').length).toBe(2); //TODO this isn't right. 
    }); 
    }); 
}); 

但是,最後expect()並沒有做正確的事情。 關於如何測試<select>加載正確的信息並顯示它的任何建議?

+0

'dimension'是包含該模板的指令嗎?你可以粘貼指令的代碼嗎? – zsong

+0

是的,dimension是包含模板的指令。 –

+0

你能發佈你的指令代碼嗎? –

回答

5

我看到三個問題與你的測試代碼:

  • 你不是叫$httpBackend.flush,因此不能模擬HTTP響應;
  • 您不會觸發摘要循環,因此Angular不會呈現指令的標記。
  • 您正在嘗試計算有多少select正在渲染,但它總是隻有一個。您應該計算生成多少個option

所有這些都容易解決(我已經改變了你的代碼一點點清楚發生了什麼):

describe('directive', function() { 
    var $httpBackend; 

    beforeEach(function() { 
    module('myApp.directives'); 

    inject(function(_$httpBackend_, $rootScope, $controller) { 
     $httpBackend = _$httpBackend_; 
    }); 
    }); 

    it('should load select\'s options from xhr on render', function() { 
    inject(function($compile, $rootScope) { 
     // Arrange 
     $httpBackend.expectPOST('url').respond(["Item 1", "Item 2"]); 
     var element = $compile('<dimension ng-model="inputs.model" url="url">Dimension</dimension>')($rootScope); 

     // Act 
     $httpBackend.flush(); // Simulates a response 
     $rootScope.$digest(); // Triggers a digest cycle 

     // Assert 
     expect(element.find('option').length).toBe(2); 
    }); 
    }); 
}); 

這裏有一個Plunker腳本上面的測試工作。

+0

很好,謝謝!看起來我需要更多地瞭解摘要循環。 –

+0

沒問題。測試指令可能有點棘手,因爲我們需要手動執行Angular會在瀏覽器中自動執行的一些操作(如觸發摘要循環)或者在瀏覽器的沙箱外無法正常工作(如模擬擊鍵)。 –