Reputation: 2003
In my angular JS application I have a mainController which takes in a userFactory as a parameter. The userFactory consists of an object called userService which in turn has a userDetails object and some methods including resetUserDetails. (see further down)
In the mainController I have a logOut function which calls the userFactory.userService.resetUserDetails
method. I would like to test this logOut function with jasmine however I am getting some errors. I am very new to Jasmine so apologies if its something obvious i'm missing.
So firstly in my Jasmine suite I create a MainControllerSpec for testing my mainController.
Within this spec I'm injecting a factory called userFactory. I'm trying to spyOn my resetUserDetails
method as follows however getting an error:
spyOn(userFactory, 'userService.resetUserDetails');
Error: userService.resetUserDetails()
does not exist.
I tried this process by creating a function called test in my userFactory (outside the userService object) and it works well so at least I know the factory injection in the spec is set up fine.
Any help greatly appreciated. Thanks
describe("MainController", function () {
beforeEach(angular.mock.module('mapModule', 'ngRoute','ngTouch', 'ngAnimate'));
var scope, userFactory;
beforeEach(inject(function($rootScope, $controller, _userFactory_){
scope = $rootScope.$new();
userFactory = _userFactory_;
$controller('mainController', {
$scope: scope
});
}));
describe('The logOut function', function() {
it('should call the resetUserDetails function of the userFactory.userService object and reset the userDetails object', function() {
//spyOn takes in a factory and a method of that factory
spyOn(userFactory, 'userService.resetUserDetails');
//spyOn(userFactory, 'test'); tried this and it works.
scope.logOut();
expect(userFactory.userService.resetUserDetails).toHaveBeenCalled();
});
});
});
$scope.logOut = function(){
userFactory.userService.resetUserDetails();
//userFactory.test(); //tried this with spyOn in jasmine
}
mapApp.factory('userFactory', function(){
var userService = {
/*
* Initialize a userDetails object.
*/
userDetails : {
"userID" : null,
"facebookUserID" : "",
"facebookName" : "",
"facebookProfilePic" : "",
"userPrivilegeID" : 1,
"userToken" : "",
"isLoggedIn" : false
},
resetUserDetails : function(){
/*
* This method resets the userDetails object.
*/
this.userDetails = {
"userID" : null,
"facebookUserID" : "",
"facebookName" : "",
"facebookProfilePic" : "",
"userPrivilegeID" : 1,
"userToken" : "",
"isLoggedIn" : false
};
}
};
var test = function(){
/*
* for testing spyOn in Jasmine
*/
};
//return public API so that we can access it in all controllers
return{
userService: userService,
test: test
};
});
Upvotes: 1
Views: 3824
Reputation: 9988
You need to mock your userFactory
before to inject it directly.
Goals of unit tests are to test the files as black boxes, without testing also the logic of the related methods directly.
For them you will write your spec file for the userFactory
instead.
In this case what you can do is something like the following:
describe("MainController", function() {
beforeEach(angular.mock.module('mapModule', 'ngRoute', 'ngTouch', 'ngAnimate'));
var scope, userFactory;
// here mock the methods of your factory
beforeEach(module(function($provide) {
$provide.value('userFactory', {
myFirstObject: {
myFirstMethod: function() {}
}
});
}));
beforeEach(inject(function($rootScope, $controller, _userFactory_) {
scope = $rootScope.$new();
userFactory = _userFactory_;
$controller('mainController', {
$scope: scope
});
}));
describe('The logOut function', function() {
it('should call the resetUserDetails function of the userFactory.userService object and reset the userDetails object', function() {
//here spy on the method and return what you would like to return in this test
// or if you don't need to manage the return, as it seems you don't, just use callThrough
spyOn(userFactory.myFirstObject, 'myFirstMethod').and.callThrough();
scope.logOut();
expect(userFactory.myFirstObject.myFirstMethod).toHaveBeenCalled();
});
});
});
Upvotes: 1