Angular + Jasmine:你如何测试依赖于指令外的html的指令?

时间:2016-03-29 23:11:51

标签: angularjs jasmine

我有一个指令,使用选择器克隆页面上的元素,并将克隆移动到页面上的其他位置:

(function() {
  'use strict';

  function ctAnimatedClone($timeout) {
    var directive = {
      restrict: 'E',
      scope: {
        visible: '=',
        ...
      },
      link: function(scope, element) {
        ...

        function cloneAndAnimateElement() {
          originalElement = angular.element(scope.elementSelector).first();
          clone = originalElement.clone();
          originalPosition = originalElement[0].getBoundingClientRect();

          clone.addClass('easeIn');
          originalElement.css({ visibility: 'hidden' });
          element.prepend(clone);

          var baseStyles = {
            opacity: 0.5,
            visibility: 'visible',
            position: 'absolute'
          };
          var styles = angular.extend(baseStyles, clonePositioning());
          clone.css(styles);

          $timeout(function() {
            clone.css({
              opacity: 1.0,
              position: 'absolute',
              top: scope.clonedElementPositionOffset.top,
              left: scope.clonedElementPositionOffset.left,
              marginLeft: '-' + (originalPosition.width / 2) + 'px'
            });
          });
        }
      }
    };

    return directive;
  }

  angular
  .module('crowdtap.animated-clone')
  .directive('ctAnimatedClone', ctAnimatedClone);
})();

我正在尝试使用Jasmine测试它,但它失败了:TypeError:Cannot set property 'visible' of undefined

/* global expect */
/* global inject */

describe('animated clone directive', function() {
  "use strict";

  var $compile, $rootScope;

  var elementHtml = "<div class='test-div'></div><ct-animated-clone visible='false' element-selector=\"'.test-div'\" cloned-element-position-offset=\"{ top: '50%', left: '50%' }\" fades-away-on-close='false' closed='false' stationary='false'></ct-animated-clone>";
  //

  beforeEach(function() {
    module('crowdtap.animated-clone');

    inject(function(_$compile_, _$rootScope_) {
      $compile   = _$compile_;
      $rootScope = _$rootScope_;
    });
  });

  it('moves the element when visible changes from false to true', function() {
    var element = $compile(elementHtml)($rootScope);
    $rootScope.$digest();
    var scope = element.isolateScope();
    scope.visible = true; //<------------------------------------------------
    scope.$apply();

    expect(element.css()).toContain("top: 10%");
  });
});

如何测试需要在页面上显示其他HTML元素的指令?

1 个答案:

答案 0 :(得分:1)

我最终通过了这个测试:

describe('animated clone directive', function() {
  "use strict";

  var $compile, $rootScope, $timeout, elementHtml, element;

  beforeEach(function() {
    module('crowdtap.animated-clone');

    inject(function(_$compile_, _$rootScope_, _$timeout_) {
      $compile   = _$compile_;
      $rootScope = _$rootScope_;
      $timeout = _$timeout_;
    });

    var dummyDiv = "<div class='test-div' style='width: 10px; position: absolute; top: 1px; left: 2px;'></div>";
    angular.element('body').append(dummyDiv);
  });

  afterEach(function() {
    angular.element('body > .test-div').remove();
  });

  ...

    describe('when stationary is false', function() {
      beforeEach(function() {
        elementHtml = "<ct-animated-clone visible='false' element-selector=\"'.test-div'\" cloned-element-position-offset=\"{ top: '50%', left: '50%' }\" fades-away-on-close='false' closed='false' stationary='false'></ct-animated-clone>";
        element = $compile(elementHtml)($rootScope);
        $rootScope.$digest();
        var scope = element.isolateScope();
        scope.visible = true;
        scope.$apply();
      });

      it('first positions the clone on top of the element', function() {
        var clone = element.children('.test-div');
        var cloneStyles = clone.attr('style');

        expect(cloneStyles).toContain("position: absolute");
        expect(cloneStyles).toContain("top: 1px");
        expect(cloneStyles).toContain("left: 2px");
        expect(cloneStyles).toContain("margin-left: 0px");
        expect(cloneStyles).toContain("opacity: 0.5");
      });

    });
  });
});