Im writing some unit tests for my controller which uses promises. Basically this:
UserService.getUser($routeParams.contactId).then(function (data) {
$scope.$apply(function () {
$scope.contacts = data;
});
});
I have mocked my UserService. This is my unit test:
beforeEach(inject(function ($rootScope, $controller, $q, $routeParams) {
$routeParams.contactId = contactId;
window.localStorage.clear();
UserService = {
getUser: function () {
def = $q.defer();
return def.promise;
}
};
spyOn(UserService, 'getUser').andCallThrough();
scope = $rootScope.$new();
ctrl = $controller('ContactDetailController', {
$scope: scope,
UserService:UserService
});
}));
it('should return 1 contact', function () {
expect(scope.contacts).not.toBeDefined();
def.resolve(contact);
scope.$apply();
expect(scope.contacts.surname).toEqual('NAME');
expect(scope.contacts.email).toEqual('EMAIL');
});
This give me the following error:
Error: [$rootScope:inprog] $digest already in progress
Now removing the $scope.$apply in the controller causes the test to pass, like this:
UserService.getUser($routeParams.contactId).then(function (data) {
$scope.contacts = data;
});
However this breaks functionality of my controller... So what should I do here?
Thanks for the replies, the $apply is not happening in the UserService. It's in the controller. Like this:
EDIT: The $apply is happening in the controller like this.
appController.controller('ContactDetailController', function ($scope, $routeParams, UserService) {
UserService.getUser($routeParams.contactId).then(function (data) {
$scope.$apply(function () {
$scope.contacts = data;
});
});
Real UserService:
function getUser(user) {
if (user === undefined) {
user = getUserId();
}
var deferred = Q.defer();
$http({
method: 'GET',
url: BASE_URL + '/users/' + user
}).success(function (user) {
deferred.resolve(user);
});
return deferred.promise;
}