Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angularjs test simple factory that return static data

How do you mock out a simple Factory in AngularJs that returns static data in a Karma unit test?

I have this simple factory, that for the sake of example return static data:

angular.module('conciergeApp.services')
       .factory('CurrentUser', function() {
        return {
            id: 1,
            hotel_id: 1,
        }
      });

I'd like to know how to write a Karma test for this?

So far, I have this code, but id doesn't work:

describe('ReplyCtrl', function() {

    beforeEach(module('conciergeApp'));

    beforeEach(module(function($provide) {
        $provide.service('CurrentUser', function() {
            return 1;
        });
    }));

    //Getting reference of the mocked service
    var mockUtilSvc;

    inject(function(CurrentUser) {
        mockUtilSvc = CurrentUser;
    });

    beforeEach(inject(function($rootScope, $controller) {
        scope = $rootScope.$new();
        ctrl = $controller('ReplyCtrl', {
            $scope: scope
        });
    }));

    it('should return value from mock dependency', inject(function(mockUtilSvc) {
        expect(mockUtilSvc()).toEqual(1);
    }));

});

This is the error message that I've been getting:

Firefox 41.0.0 (Mac OS X 10.10.0) ReplyCtrl should return value from mock dependency FAILED
    Error: [$injector:unpr] Unknown provider: mockUtilSvcProvider <- mockUtilSvc
like image 289
Aaron Lelevier Avatar asked Sep 27 '22 08:09

Aaron Lelevier


1 Answers

1) You have inject in the wrong place. You are specifying inject function in your test it, just remove it.

i.e.

it('should return value from mock dependency', inject(function(mockUtilSvc) {
    expect(mockUtilSvc()).toEqual(1);
}));

would become

 it('should return value from mock dependency', function() {
    expect(mockUtilSvc()).toEqual(1);
});

2) Now the issue is that mockUtilSvc is a service instance and not a function as per your definition, also based on your mock you need to define it as factory (i.e you are returning 1 as the value of factory and it is not new able).

beforeEach(module(function($provide) {
    $provide.factory('CurrentUser', function() {
        return 1;
       //If you expect factory to be a function then you need to return a function returning 1 here
    });
}));

and

expect(mockUtilSvc).toEqual(1);

3) You could as well write this as:

$provide.value('CurrentUser', 1); //Provide the instance here right away

4) Your first inject is also in wrong place. You are just running it, but not running and assigning the instance during each spec run. before Each iteration you need to set the value of service instance to your variable, i.e:

 beforeEach(inject(function(CurrentUser) {
    mockUtilSvc = CurrentUser;
}));

An example test:

describe('ReplyCtrl', function() {
   var mockData = {
            id: 1234,
            hotel_id: 1,
        }, mockUtilSvc, scope, ctrl  ;


    beforeEach(module('conciergeApp', function($provide) {
        $provide.value('CurrentUser', mockData);
    }));

    beforeEach(inject(function(CurrentUser, $rootScope, $controller) {
        mockUtilSvc = CurrentUser;
        scope = $rootScope.$new();
        ctrl = $controller('ReplyCtrl', {
            $scope: scope
        });
    }));

    it('should return value from mock dependency', function() {
        expect(mockUtilSvc.id).toEqual(mockData.id);
    });
});

Demo

Note: There are other ways to mock and inject the mock. For example in this case you do not really need to use $provide.value as well. Instead you could create your mock object and pass it in during the controller instantiation as you have full control over there to pass the dependency, like below:

  ctrl = $controller('ReplyCtrl', {
            $scope: scope,
            CurrentUser: mockUtilSvc
   });

In case of more complex service with methods you could create mock like this.

  mockSvc = jasmin.createSpyObj('MyService', ['method1', 'method2']);
  mockSvc.method1.and.returnValue($q.when(mockData)); //Simulating a promise returned from an $http call  in the method.
like image 114
PSL Avatar answered Sep 29 '22 06:09

PSL