title: How Can I Test a .catch Promise Return in AngularJS using Jasmine?
body: <p>I'm fairly new to Javascript and just learning AngularJS but I've gotten most of my test cases to work with some great examples I've found.  Unfortunately I can't seem to find anything to help me test my current case.  </p>
  
  <p>I'm testing a Controller using a mocked Service whose method returns a promise.  I would like the mocked Service to return an error in order to execute the '.catch' block in the controller method.  I can tell that it's not getting called correctly in a couple of ways:</p>
  
  <ol>
  <li>I'm using <a href="https://gotwarlost.github.io/istanbul/">istanbul</a> for code coverage and it's telling me I'm not covering the 'catch' </li>
  <li>The code in the '.catch' block is not getting executed from what I can tell via debugging</li>
  </ol>
  
  <p>The controller under test, specifically need to test the '.catch' in $scope.login:</p>
  
  <p><strong>login.js</strong></p>
  
  <pre><code>'use strict';
  
  angular.module('ibcwebDashApp')
    .controller('LoginCtrl', function ($scope, Auth, $location) {
      $scope.user = {};
      $scope.errors = {};
  
      $scope.login = function(form) {
        $scope.submitted = true;
  
        if(form.$valid) {
          Auth.login({
            email: $scope.user.email,
            password: $scope.user.password
          })
          .then( function() {
            // Logged in, redirect to home
            $location.path('/');
          })
          .catch( function(err) {
            err = err.data;
            $scope.errors.other = err.message;
          });
        }
      };
    });
  </code></pre>
  
  <p>The service and method I'm attempting to mock:</p>
  
  <p><strong>Auth.login</strong></p>
  
  <pre><code>'use strict';
  
  angular.module('ibcwebDashApp')
    .factory('Auth', function Auth($location, $rootScope, Session, User, $cookieStore) {
  
      // Get currentUser from cookie
      $rootScope.currentUser = $cookieStore.get('user') || null;
      $cookieStore.remove('user');
  
      return {
  
        /**
         * Authenticate user
         * 
         * @param  {Object}   user     - login info
         * @param  {Function} callback - optional
         * @return {Promise}            
         */
        login: function(user, callback) {
          var cb = callback || angular.noop;
  
          return Session.save({
            email: user.email,
            password: user.password
          }, function(user) {
            $rootScope.currentUser = user;
            return cb();
          }, function(err) {
            return cb(err);
          }).$promise;
        },
  </code></pre>
  
  <p>And finally, my test file.  The funny part is that all tests are passing but the 'expect' in the last test can be changed to pretty much anything and it still passes.  The first two tests seem to run as expected but the last test is where I'm trying to execute the catch block by throwing an error from the mock Auth service:</p>
  
  <p><strong>login.unit.js</strong></p>
  
  <pre><code>'use strict';
  
  describe('Controller: LoginCtrl', function () {
    var $scope, $location, loginCtrl, mockAuthService;
  
  
    beforeEach(function() {
      mockAuthService = jasmine.createSpyObj('Auth', ['login']);
  
      module('ibcwebDashApp');
  
      module(function($provide) {
        $provide.value('Auth', mockAuthService);
      });
  
      inject(function($rootScope, $controller, $q, _$location_) {
        //create an empty scope
        $scope = $rootScope.$new();
        $location = _$location_;
        //declare the controller and inject our empty scope
        loginCtrl = $controller('LoginCtrl', {$scope: $scope, Auth: mockAuthService});
  
      });
  
    });
  
  
    describe('successful login', function() {
  
      beforeEach(function() {
        inject(function($q) {
          mockAuthService.login.andReturn($q.when());
        });
  
      });
  
      it('should call auth.login with the scope email and password when form is valid', function() {
        //given
        $scope.form = {};
        $scope.form.$valid = true;
        $scope.user.email = 'user@test.com';
        $scope.user.password = 'password123';
  
        //when
        $scope.login($scope.form);
  
        //then
        expect($scope.submitted).toBe(true);
        expect(mockAuthService.login).toHaveBeenCalledWith({email:'user@test.com', password:'password123'});
  
        $scope.$apply(); //force return of auth.login promise
  
        expect($location.path()).toBe('/');
      });
  
      it('should not call auth.login if form is invalid', function() {
        //given
        $scope.form = {};
        $scope.form.$valid = false;
  
        //when
        $scope.login($scope.form);
  
        expect(mockAuthService.login).not.toHaveBeenCalled();
      });
    });
  
    describe('unsuccessful login', function() {
  
      beforeEach(function () {
        inject(function () {
          mockAuthService.login.andReturn($q.when(new Error('Bad Login!')));
        });
  
        it('should set errors.other to the returned auth error message', function() {
          //given
          $scope.form = {};
          $scope.form.$valid = true;
  
          //when
          $scope.login($scope.form);
  
          $scope.$apply();
  
          //then
          expect($scope.errors.other).toEqual('Bad Login!');
        });
  
      });
    });
  });
  </code></pre>
  
  <p>I apologize for posting so much code but I wanted to provide as much context as possible.  I really appreciate anyone who can help me out as I learn my way around unit testing Angular and promises!  Thanks!!!</p>
  
  <p><strong>**UPDATE**</strong></p>
  
  <p>I was able to solve my issue with some help from below and discovering some syntactic errors.  Here's what fixed this:</p>
  
  <ol>
  <li>My <code>beforeEach</code> on the last test was not closed properly and actually enclosed the last test causing it not to run correctly (or maybe at all). This is why changing the expect conditions resulted in no errors.</li>
  <li>I changed my <code>beforeEach</code> inject to: <code>mockAuthService.login.andReturn($q.reject({data: {message: 'Bad Login!'}}));</code> using the <code>reject</code> suggested below.</li>
  <li>Once I properly closed the <code>beforeEach</code> I got an error message that $q was not defined so I had to added it to <code>inject(function($q)</code></li>
  </ol>
  
  <p>Once I corrected these issues the promise was correctly rejected and the error was caught by the appropriate code in the controller.  </p>