How to test _.defer() using Jasmine, AngularJs

杀马特。学长 韩版系。学妹 提交于 2019-12-01 12:54:07

You can do this by injecting a mock underscore library, with a defer function defined in the test. A way to do this is to define your own factory, _, which can then be mocked easily:

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

Then in the directive, you have to use it by injecting it:

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

In the test, you can then mock it:

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

This means that instead of the real one, the directive will use the mock _, which saves the callback passed to defer as deferCallback so you can invoke it when needed:

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

This makes the test synchronous, which is usually a better idea than using done(), as it keeps test as fast as possible.

You can see the above working at http://plnkr.co/edit/r7P25jKzEFgE5j10bZgE?p=preview

If you do not have lodash as a service to be injected you can just spy over the defer method, and if you care about the execution of the function passed then you can just set a callFake and call the argument function passed to the real defer:

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

More deeper let's say you have the following call:

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

then in your test you can say:

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

@Michal Charezma, gave a great solution for the problem that is actually a solution, but as it turned out it has some other restrictions for the rest of _ functions. For example:

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

raises an error that the throttle is undefined.

Following @Michal's logic, found another solution that lets functions like _.throttle() to work properly. So, instead of importing _ and using:

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

One can mock the defer function only, from the spec like:

var deferCallback = $window._.defer.mostRecentCall.args[0];
deferCallback()
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!