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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With