使用<select>对指令进行单元测试

Jas*_*hah 1 unit-testing jasmine angularjs angularjs-directive

我有一个叫做<dimension>渲染html 的指令:

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;
          });
        }
      };
    }
  ]);
Run Code Online (Sandbox Code Playgroud)

我现在想要创建一个单元测试,以验证在从xhr加载后,select中有正确数量的元素.我创建了一个大致如下的单元测试:

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.
    });
  });
});
Run Code Online (Sandbox Code Playgroud)

然而,最后的期望()并没有做正确的事情.有关如何测试<select>加载正确信息并显示它的任何建议吗?

Mic*_*ord 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); 
    });
  });
});
Run Code Online (Sandbox Code Playgroud)

这是一个使用上述测试工作的Plunker脚本.