2015-01-13 73 views
1

我已经问过这个question其中主要问题是作用域不存在于终端,但它存在于Chrome调试工具中。尽管答案没有得到解决。如何测试_.defer()使用茉莉花,AngularJs

问题是什么是正确的语法来测试波纹管指令,特别是行expect(scope.measurementScroll).toBe(true);。虽然挖通过网络我找不到任何类似的问题,大多数问题都涉及到$q.defer()凡在我的情况下,有下划线的方法_.defer()

控制器

'use strict'; 
angular.module('myApp') 
    .controller('MeasurementsTimelineCtrl', ['$scope', '$state', 'Measurements', function($scope, $state, Measurements) { 
    $scope.measurements = null; 
    var userId = $scope.currentUser ? $scope.currentUser.id : null; 
    if (userId) { 
     var listOfMeasurements = Measurements.userIndex(userId); 
     listOfMeasurements.then(function(data){ 
     $scope.measurements = data; 
     $scope.$broadcast('measurements-updated', $scope.measurements); 
     }); 
    } 
    }]); 

指令:

'use strict'; 
angular.module('myApp') 
    .directive('dashboardMeasurementTimeline', ['$window', function($window) { 
    return { 
     restrict: 'E', 
     templateUrl: 'myView.html', 
     controller: 'MeasurementsTimelineCtrl', 
     link: function(scope, element){ 
     scope.$on('measurements-updated', function(measurements) { 
      _.defer(function(){ 
      if(measurements) { 
       scope.measurementScroll = true; 
      } 
      }); 
     }); 
     } 
    }; 
    }]); 

测试

'use strict'; 
describe('Directive: dashboardMeasurementTimeline', function() { 

    var $rootScope, $compile, element, scope; 

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

    inject(function($injector) { 
     $rootScope = $injector.get('$rootScope'); 
     $compile = $injector.get('$compile'); 
    }); 

    scope = $rootScope.$new(); 
    element = angular.element('<dashboard-measurement-timeline></dashboard-measurement-timeline>'); 
    element = $compile(element)(scope); 

    scope.currentUser = {id : 'someId'}; 
    scope.$digest(); 
    scope.measurements = [{id: 'someId', time_of_test: 'Tue, 30 Dec 2014 14:00:00 -0000'}, 
     {id: 'someId', time_of_test: 'Thu, 20 Nov 2014 03:00:00 -0000'},]; 
    scope.$broadcast('measurements-updated', scope.measurements); 
    scope.$apply(); 
    }); 

    it('should assign true value to measurementScroll', function() { 
    expect(scope.measurementScroll).toBe(true); 
    }); 
}); 
+0

茉莉花1.3或2.0? – tasseKATT

+0

我使用的插件是'karma-jasmine:0.1.5',而Google搜索发现它相当于Jasmine 2.0 – Max

回答

2

您可以通过注入一个模拟的下划线库和测试中定义的defer函数来实现。要做到这一点的方法是定义你自己的工厂,_,它可以很容易地嘲笑:在指令

app.factory('_', function($window) { 
    return $window._; 
}); 

然后,你必须通过注射它来使用它:

app.directive('dashboardMeasurementTimeline', ['_', function(_) { 

在测试,然后你可以嘲笑它:

var deferCallback; 
beforeEach(module(function($provide) { 
    deferCallback = null; 
    $provide.value('_', { 
    defer: function(callback) { 
     deferCallback = callback; 
    } 
    }); 
})); 

这意味着,而不是真正的一个,该指令将使用模拟_,从而节省传递给回调0为deferCallback所以在需要的时候可以调用它:

scope.$broadcast('measurements-updated', scope.measurements); 
deferCallback(); 

它使测试同步,这通常比使用done()一个更好的主意,因为它使测试尽可能地快。

你可以看到在http://plnkr.co/edit/r7P25jKzEFgE5j10bZgE?p=preview

+0

非常感谢亲爱的@Michal Charezma,您的解决方案非常棒,可以解决问题 – Max

+0

我现在有一个小问题是在嘲笑'_'并将其导入到指令后,当使用其他'_'方法时产生错误,例如我正在使用: 'angular.element(scrollContainer).bind('scroll', _.throttle(scope.disableButtons,500)); ' 似乎'throttle()'的方法不存在 – Max

+1

@Max你应该可以添加'throttle'到传递给'$ provide.value'的对象 –

0

@Michal Charezma上述工作,给了那其实是一个解决问题的一个很好的解决方案,但事实证明它具有的功能_剩下的一些其他限制。 例如:

angular.element(scrollContainer).bind('scroll', _.throttle(scope.disableButtons, 500)); 

引发错误,该throttle是未定义的。

以下@ Michal的逻辑,发现了另一种解决方案,让功能_.throttle()正常工作。因此,而不是进口_和使用:

app.factory('_', function($window) { 
    return $window._; 
}); 

人们只能嘲笑defer功能,从规范,如:

var deferCallback = $window._.defer.mostRecentCall.args[0]; 
deferCallback() 
+1

我不认为这个方法实际上做了一个模拟对象。我怀疑它甚至可能会导致回调被推迟执行两次,一次是强制执行,另一次是在通话结束后暂停执行。 –

+0

呵呵,这真的很有趣点,必须再次检查规范。谢谢。 ) – Max

1

如果你没有lodash作为服务注入可以只是窥探过defer方法,如果你关心然后传递函数的执行,你可以只设置一个callFake并调用传递给实际defer参数功能:

spyOn(_, 'defer').and.callFake(f => f()); 

更多更深的假设您有下列呼叫:

function toTest() { 
_.defer(() => service.callAFunction()); 
} 

然后在您的测试,你可以说:

it('should call service.callAFunction',() => { 
    spyOn(service, 'callAFunction'); 
    spyOn(_, 'defer').and.callFake(f => f()); 
    toTest(); 
    expect(_.defer).toHaveBeenCalled(); 
    expect(service.callAFunction).toHaveBeenCalled(); 
}