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 the successCallback()
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');
});
});
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.
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