ngAnimate单元测试不添加类

时间:2013-10-04 00:57:45

标签: unit-testing angularjs ng-animate

我是单元测试以及ng-animate模块的新手。我做了一个简单的指令来测试ng-animate。

 .directive('slideShow', function ($animate, $compile) {
    return {
      template: '<div class="slide-show-container"></div>',
      restrict: 'EA',
      replace: true,
      link: function (scope, element, attrs) {
        var newElement = $compile('<div class="slide-show-slide"></div>')(scope);

        element.bind('mouseenter',function() {
          element.append(newElement);
          $animate.addClass(newElement, 'slide-enter');
        });
        element.bind('mouseleave',function() {
          $animate.removeClass(newElement, 'slide-enter');
        });
      }
    };
  });

然后我进行了以下单元测试以确认正在添加.slide-enter类。

  it('should add slide-enter class', function () {
    element.triggerHandler( "mouseenter" );
    expect(element.children().hasClass("slide-enter")).toEqual(true)
  });

当我在手动测试中将鼠标移除时,该指令正确地添加了该类。但是单元测试失败并显示没有添加幻灯片输入类。

最后,我想出了解决问题的唯一方法是将单元测试包装在$ timeout中:

  it('should add slide-enter class', inject(function ($timeout) {
    element.triggerHandler( "mouseenter" );
    $timeout(function() {
      expect(element.children().hasClass("slide-enter")).toEqual(true);
    });
    $timeout.flush();
  }));

任何人都可以帮助我理解为什么测试工作需要这个$ timeout吗?是否还有另一种方法可以使这个单元测试工作,我正在搞乱?

1 个答案:

答案 0 :(得分:4)

注意我正在使用角度动画1.2.0-rc.2,并记录了我在此版本中的发现。在查看1.2.0-rc.3代码时,$timeout.flush()调用的需求似乎已得到修复,但我尚未对其进行测试。 https://github.com/angular/angular.js/blob/v1.2.0-rc.3/src/ngAnimate/animate.js


我的一个测试遇到了同样的问题。在我调用了应该触发添加类的代码之后,在调用$timeout.flush()之前,我只能通过调用expect来让我的测试工作。如果您重写它,您的测试应该有效:

it('should add slide-enter class', inject(function ($timeout) {
  element.triggerHandler( "mouseenter" );
  $timeout.flush();  
  expect(element.children().hasClass("slide-enter")).toEqual(true);
}));

我不得不深入研究ngAnimate代码以找出它,这就是我找到的。

如果您查看angular-animate.js功能的addClass文件。您将看到以下内容:

addClass : function(element, className, done) {
  performAnimation('addClass', className, element, null, null, function() {
    $delegate.addClass(element, className, done);
  });
}

作为performAnimation的最后一个参数的闭包是最终添加该类的内容。

performAnimation中,最后一个参数名为'onComplete`。有一段代码可以处理在跳过动画时调用此闭包的问题:

//skip the animation if animations are disabled, a parent is already being animated
//or the element is not currently attached to the document body.
if ((parent.inheritedData(NG_ANIMATE_STATE) || disabledAnimation).running) {
  //avoid calling done() since there is no need to remove any
  //data or className values since this happens earlier than that
  //and also use a timeout so that it won't be asynchronous
  $timeout(onComplete || noop, 0, false);
  return;
}   

$timeout的调用导致了问题。在角度测试中运行此代码时,对$timeout的调用只是将闭包排队。然后,测试代码必须调用$timeout.flush()才能运行该函数。