how to return rejected/failure promise to through jasmine spy to an angular controller in a unit test
15,989
I find it easier to use actual promises for mocked services as it removes a lot of nested functions and is a lot easier to read.
Relevant snippets ($q needs to be injected in beforeEach):
deferred = $q.defer();
spyOn(login, 'login').andReturn(deferred.promise);
...
deferred.reject({ ... });
After resolving or rejecting the promise you need to call scope.$digest()
so angular can process it.
Author by
Nishutosh Sharma
Updated on July 29, 2022Comments
-
Nishutosh Sharma almost 2 years
I am using jasmine for testing my angular controllers. I am catching errors and success in the
.then(successCallback, errorCallback)
Although it is working fine on the bases of live functionality but am confused how to write a spy for returning an error as it is always caught in thesuccessCallback()
Following is the controller :-
angular.module('myApp') .controller('LoginCtrl', function ($scope, $location, loginService, SessionService) { $scope.errorMessage = ''; $scope.login = function () { var credentials = { email: this.email, password: this.password }; SessionService.resetSession(); var request = loginService.login(credentials); request.then(function(promise){ //successfull callback if (promise['status'] === 200){ //console.log('login'); $location.path('/afterloginpath'); } }, function(errors){ //fail call back // console.log(errors); $location.path('/login'); }); }; });
My test case :-
'use strict'; describe('Controller: LoginCtrl', function () { // load the controller's module beforeEach(module('myApp')); var LoginCtrl, scope, location, login, loginReturn, session; var credentials = {'email': '[email protected]', 'password': 'admin123'}; // Initialize the controller and a mock scope beforeEach(inject(function ($controller, $rootScope, $location, _loginService_, _SessionService_) { scope = $rootScope.$new(); LoginCtrl = $controller('LoginCtrl', { $scope: scope }); location = $location; login = _loginService_; session = _SessionService_; scope.errorMessage = ''; spyOn(login, "login").andCallFake( function(){ return { then: function(response){ response(loginReturn); } } } ); spyOn(session, "setName").andCallFake(function(){ return true; }); })); it('should go to login when login fail', function () { loginReturn = function(){ return{ successfullyCallback: {throwError:true}, failCallback: {status: 400, 'data' : {'errors' : [{"type":"invalid_data","target":"email,password"}]}} } }; var wrong_creds = {email: '[email protected]', password: 'wrong_password'}; scope.email = wrong_creds.email; scope.password = wrong_creds.password; scope.login(); expect(location.path()).toBe("/login"); expect(scope.errorMessage).toBe('username or password combination is invalid'); }); });
-
Nishutosh Sharma almost 10 yearsIt works, we can also call scope.$apply() is also works for me
-
ivarni almost 10 yearsscope.$apply() works because it triggers scope.$digest() but $apply() is meant to be called with an expression so I tend to prefer using $digest() instead. Take a look at docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply for the difference between them.
-
Muhammad Hashir Anwaar over 9 yearsJasmine 2.0 syntax is: and.returnValue();