【问题标题】:AngularJS $timeout function not executing in my Jasmine specsAngularJS $timeout 函数未在我的 Jasmine 规范中执行
【发布时间】:2013-06-25 09:18:37
【问题描述】:

我正在尝试使用 Karma 测试我的 AngularJS 控制器和 Jasmine。但是在现实生活中运行良好的$timeout 会使我的测试崩溃。

控制器:

var Ctrl = function($scope, $timeout) {
  $scope.doStuff = function() {
    $timeout(function() {
      $scope.stuffDone = true;
    }, 250);
  };
};

Jasmine it 阻塞($scope 和控制器已正确初始化):

it('should do stuff', function() {
  runs(function() {
    $scope.doStuff();
  });
  waitsFor(function() { 
    return $scope.stuffDone; 
  }, 'Stuff should be done', 750);
  runs(function() {
    expect($scope.stuffDone).toBeTruthy();
  });
});

当我在浏览器中运行我的应用程序时,$timeout 函数将被执行,$scope.stuffDone 将为真。但在我的测试中,$timeout 什么都不做,该函数永远不会执行,并且 Jasmine 在超时 750 毫秒后报告错误。这里可能有什么问题?

【问题讨论】:

    标签: angularjs jasmine


    【解决方案1】:

    根据$timeout 的Angular JS 文档,您可以使用$timeout.flush() 同步刷新延迟函数的队列。

    尝试将您的测试更新为:

    it('should do stuff', function() {
      expect($scope.stuffDone).toBeFalsy();
      $scope.doStuff();
      expect($scope.stuffDone).toBeFalsy();
      $timeout.flush();
      expect($scope.stuffDone).toBeTruthy();
    });
    

    这是一个plunker,显示您的原始测试失败和新测试通过。

    【讨论】:

    • 谢谢。应该是 RTFM。似乎在 Jasmine 测试中加载了 ngMocks 模块,并且模拟的 $timeout 实际上从未调用 window.setTimeout - 我正确吗?
    • 正确,看看Github上的代码herehere
    • 所以那些 Github 链接是指 master 并且不再有用。对于那些好奇的人,以下是针对该版本的相同链接:herehere
    • 这有帮助。但是我最后不得不调用 done() 来标记测试用例的结束。否则 jasmine 等待 5 秒(默认)并失败,因为 done() 没有被调用。希望这会有所帮助
    【解决方案2】:

    正如其中一个 cmets 所述,没有使用 Jasmine setTimeout 模拟,因为使用了 angular 的 JS 模拟 $timeout 服务。就个人而言,我宁愿使用 Jasmine 的,因为它的模拟方法让我可以测试超时的长度。您可以在单元测试中使用简单的提供程序有效地规避它:

    module(function($provide) {
      $provide.constant('$timeout', setTimeout);
    });
    

    注意:如果你走这条路,一定要在jasmine.Clock.tick之后拨打$scope.apply()

    【讨论】:

    • 如何将其反转回角度超时模拟,因为我有其他测试不想使用茉莉模拟?
    • 在这些测试中是否可以切换回使用 timeout.flush(1000) ?似乎在某些情况下使用 jasmine.clock().tick(1000) 并不是一个完美的替代品。
    【解决方案3】:

    由于$timeout 只是window.setTimeout 的包装,您可以使用模拟window.setTimeout 的茉莉花Clock.useMock()

      beforeEach(function() {
        jasmine.Clock.useMock();
      });
    
      it('should do stuff', function() {
        $scope.doStuff();
        jasmine.Clock.tick(251);
        expect($scope.stuffDone).toBeTruthy();
      });
    

    【讨论】:

    • 这是 Jasmine 1.x API。对于 Jasmine 2.x,你可以在 beforeEach 中运行 jasmine.clock().install(),在 afterEach 中运行 jasmine.clock().uninstall(),在 it 函数中运行 jasmine.clock().tick(251)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-13
    • 1970-01-01
    • 1970-01-01
    • 2014-09-08
    • 2012-01-08
    • 1970-01-01
    相关资源
    最近更新 更多