Javascript – how to return rejected/failure promise to through jasmine spy to an angular controller in a unit test


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 :-

.controller('LoginCtrl', function ($scope, $location, loginService, SessionService) {
    $scope.errorMessage = '';

    $scope.login = function () {

      var credentials = {
          password: this.password

     var request = loginService.login(credentials);

     request.then(function(promise){ //successfull callback
        if (promise['status'] === 200){
     function(errors){  //fail call back
      //  console.log(errors);

My test case :-

'use strict';

describe('Controller: LoginCtrl', function () {

  // load the controller's module

  var LoginCtrl, scope, location, login, loginReturn, session;
  var credentials = {'email': '', '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(
        return {
          then: function(response){

    spyOn(session, "setName").andCallFake(function(){
      return true;

  it('should go to login when login fail', function () {
    loginReturn = function(){
        successfullyCallback: {throwError:true},
        failCallback: {status: 400, 'data' : {'errors' : [{"type":"invalid_data","target":"email,password"}]}}

    var wrong_creds = {email: '', password: 'wrong_password'}; =;
    scope.password = wrong_creds.password;


    expect(scope.errorMessage).toBe('username or password combination is invalid');


Best Solution

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.