Test AngularJS factory function with Jasmine

23,105

You're not too far from what you need. First off, as you require my_data as my_module dependency, you don't need to inject my_module to the controller, just the factory (my_factory);

Secondly, you want to make use of ngMock. The docs are not very complete, but give a good insight. More here and a example here (look for test/unit/controllers).

Basically, what you want to do is to mock the service so you can be assured it has been called. To achieve it, inject $provide to your angular.mock.module call and provide a mocked my_factory service. The best way to achieve it is something like this:

describe('testing my_controller.my_function', function () {
  var mockedFactory, $rootScope, $controller;

  beforeEach(module('my_module', function($provide) {
    mockedFactory = {
      save: jasmine.createSpy()
    };

    $provide.value('my_factory', mockedFactory);
  }));

  beforeEach(inject(function(_$rootScope_, _$controller_) {
    $rootScope = _$rootScope_;
    $controller = _$controller_;
  }));

  scope = $rootScope.$new();

  it('should call the save function', function() {
    scope.my_function();
    expect(mockedFactory.save).toHaveBeenCalled();
  });
}

This way you'll override my_factory dependency.

Share:
23,105
ali
Author by

ali

I am a web, desktop and mobile applications developers with great knowledge in web development, medium knowledge in desktop applications development and a beginner status in mobile applications development.

Updated on August 23, 2022

Comments

  • ali
    ali almost 2 years

    I am very new to this (angularjs, jasmine, testacular) and I have this code (I simplified it a bit, leaving only what matters):

    //my_module.js
    angular.module('my_module', ['my_data'])
    .config([...]);
    
    .controller('my_controller', ['$scope', 'my_data',
        function($scope, my_data) {
            $scope.my_function = function() {
                return my_data.my_factory.save().then(function () {
                    console.log('saved');
                },
                function() {                             
                    console.log('Error');
                }); 
            }
        }
    )
    
    //my_data.js
    angular.module('my_data', [])
    .factory('my_factory', ['$q', '$rootScope',
        function($q, $rootScope) {
            var my_factory= function(my_data) {
                angular.extend(this, my_data);
            }
            my_factory.prototype.save = function() {
                var deferred = $q.defer();
                setTimeout(function() {
                    deferred.resolve();
                $rootScope.$apply();
                }, 1000);
    
                return deferred.promise;
            }
            return my_factory;
        }
    ])
    

    So, what I want to do is to test if my_data.my_factory.save is called when the my_module.my_controller.my_function is fired.

    //my_test.js
    describe('testing my_controller.my_function', function () {
        beforeEach(module('my_module'));
    
        var $rootScope, $controller;
        beforeEach(inject(function(_$rootScope_, _$controller_) {
            $rootScope = _$rootScope_;
            $controller = _$controller_;
        }));
    
        scope = $rootScope.$new();
    
        it('should call the save function', function() {
            scope.my_function();
            expect(my_data.save).toHaveBeenCalled();
        });
    }
    

    I need a little bit of help.

  • ridermansb
    ridermansb about 9 years
    Hi @CaioCunha.. Which controller you are testing? Where you specify it? I really liked this approach, and I am refactoring same of my test but I got this doubt github.com/Ridermansb/listfy/blob/feature/…