Search code examples
angularjsservicejasminespyon

Mocking a service and calling through in Jasmine


I'm trying to test a service in my AngularJS project. All I'm trying to do is see if the method on my service has called through. I thought that when you use 'and.callThrough()' in jasmine it called the method for you and then you can see if it was called. However, when I test my function karma is giving me the response of 'Expected spy of getArtists to have been called'.

describe('Practice', function(){
 beforeEach(module('MyApp'));
 var ctrl, loadArtists, rootscope, dataFactory;
 beforeEach(inject(function($controller, $rootScope, DataFactory){
    spyOn(DataFactory, 'getArtists').and.callThrough();
    dataFactory = DataFactory
    rootscope = $rootScope;
    scope = rootscope.$new();
    ctrl = $controller('LaunchCtrl',{scope: scope, artistsPicsRotate: []});
}));

it('should do nothing',function(){
    expect(ctrl.artistsPicsRotate).toEqual([])
});

it('should call through DataFactory', function(){
    expect(dataFactory.getArtists).toHaveBeenCalled();
    expect(dataFactory.getArtists.calls.count()).toEqual(1);
});

});

Any ideas on why this isn't working would be much appreciated.


Solution

  • As explained in the comments the call to the service is done by the ui-router resolves before the controller is instantiated. That means the controller never explicitly calls DataService.getArtists(), because the call is done when the routing state is resolved and the received result is injected in the controller. So when testing the controller there is no need to test the call to the service because that call is not directly made from it.

    However if you want to test the state definition here is one example how you can do it.

    describe('Practice', function(){
      beforeEach(module('MyApp'));
      var ctrl, loadArtists, rootscope, dataFactory, $state;
      beforeEach(inject(function($controller, $rootScope, DataFactory, _$state_){
        dataFactory = DataFactory
        rootscope = $rootScope;
        scope = rootscope.$new();
        $state = _$state_;
        ctrl = $controller('LaunchCtrl',{scope: scope, artistsPicsRotate: []});
      }));
    
      it('should do nothing',function(){
          expect(ctrl.artistsPicsRotate).toEqual([])
      });
    
      // NOTE: test your state definition
      describe('state definition', function () {
    
        var stateDefinition;
        beforeEach(function () {
          stateDefinition = $state.get('stateName');
        });
    
        // NOTE: write test for each resolve
        it('should resolve artists', function() {
          // given
          spyOn(dataFactory, 'getArtists').and.callThrough();
    
          // when
          var artists = stateDefinition.resolve.artistsPicsRotate();
    
          // then
          expect(artists).toBeDefined();
          expect(dataFactory.getArtists).toHaveBeenCalled();
          expect(dataFactory.getArtists.calls.count()).toEqual(1);
        });  
      });
    });