Similar question to: Jasmine angularjs - spying on a method that is called when controller is initialized
In my controller I use the angular-local-storage package to provide a localStorageService through injection.
in my unit tests I want to make sure the data is retrieved from the service, so I spy on the "get" and "add" methods and mock them (.andCallFake).
this works fine with all the methods that are called through $scope.$watch - as long as I force a $digest. but for the method that is called on the controller initialization, it does not seem to work. Can anyone advise why this doesn't work?
app>Main.js
angular.module('angularTodoApp')
.controller('MainCtrl',['$scope','localStorageService',function ($scope, localStorageService) {
var todosInStore = localStorageService.get('todos');
$scope.todos = todosInStore && todosInStore.split('\n') || [];
//$scope.todos = ['Item 1', 'Item 2', 'Item 3'];
$scope.$watch('todos', function(){
localStorageService.add('todos', $scope.todos.join('\n'));
},true);
$scope.addTodo = function() {
$scope.todos.push($scope.todo);
$scope.todo = '';
};
$scope.removeTodo = function(index) {
$scope.todos.splice(index,1);
};
}]);
test>Main.js
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('angularTodoApp'));
var MainCtrl,
scope,
localStorageService,
store = [];
// Initialize the controller and a mock scope
beforeEach(inject(function ($controller, $rootScope, _localStorageService_) {
scope = $rootScope.$new();
localStorageService = _localStorageService_;
MainCtrl = $controller('MainCtrl', {
$scope: scope,
localStorageService: _localStorageService_
});
//mock localStorageService get/add
spyOn(localStorageService,'get').andCallFake(function(key){
return store[key];
});
spyOn(localStorageService,'add').andCallFake(function(key, val){
store[key] = val;
});
}));
it('should retrieve "todos" from the store and assign to scope', function () {
expect(localStorageService.get).toHaveBeenCalledWith('todos');
expect(scope.todos.length).toBe(0);
});
it('should add items to the list and update the store for key = "todos"', function () {
scope.todo = 'Test 1';
scope.addTodo();
scope.$digest();
expect(localStorageService.add).toHaveBeenCalledWith('todos', jasmine.any(String));
expect(scope.todos.length).toBe(1);
});
all tests pass except the one in the constructor:
expect(localStorageService.get).toHaveBeenCalledWith('todos');
The reason is that the controller is initialised at the point you call $controller
, which in your example is before you're created the spies via spyOn
. The solution for your example is to move the call to $controller
to after the calls to spyOn
.
For longer test suites, to keep things DRY, you might have to put the call to $controller
in a separate function, that you can then call after you have mocked up any required services.
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