Your use of the promise mechanism is not correct, simply throwing a user-defined throw statement does not handle it as a promise rejection properly. According to the documentation on $q
:
When comparing deferreds/promises to the familiar behavior of
try/catch/throw, think of reject as the throw keyword in JavaScript.
This also means that if you "catch" an error via a promise error
callback and you want to forward the error to the promise derived from
the current promise, you have to "rethrow" the error by returning a
rejection constructed via reject.
While they are similar concepts, catching user-defined throw statements requires the use of catch
statement blocks. Additionally, $q
promises should only be used to catch rejected promises. Therefore, returning a rejected promise is the appropriate way to handle the process instead of throwing a user-defined exception.
DEMO
JAVASCRIPT
describe('Q Service Test', function() {
var $q,
$rootScope;
beforeEach(inject(function(_$q_, _$rootScope_) {
$q = _$q_;
$rootScope = _$rootScope_;
}));
it('Rejected promises are handled properly', function() {
var state = 'ok';
$q.when(1)
.then(function() {
return $q.reject('rejected');
})
.catch(function() {
state = 'error';
});
$rootScope.$digest();
expect(state).toBe('error');
});
});
UPDATE:
The reason for the behavior of your code in the browser is due to Angular's $q
implementation using try/catch
statement blocks in processing the promise queue. When any callbacks throw errors, it catches the error, rejects it with the exception as the reason for rejection, and uses $exceptionHandler
to log the error. It is recommended to simply return a rejected promise.
In terms of unit test behavior, the implementation of angular-mocks
differs from the application's actual $exceptionHandler
. The former uses different modes, with the default angular-mocks implementation using the rethrow
mode which throws the exception instead of logging it. To align unit tests with the application's $exceptionHandler
, set the mode to 'log'
.
DEMO
JAVASCRIPT
describe('Q Service Test', function() {
var $q,
$rootScope;
beforeEach(module('ng', function($exceptionHandlerProvider) {
$exceptionHandlerProvider.mode('log');
}));
beforeEach(inject(function(_$q_, _$rootScope_) {
$q = _$q_;
$rootScope = _$rootScope_;
}));
it('Caught exceptions are handled properly', function() {
var state = 'ok';
$q.when(1)
.then(function() {
throw new Error();
})
.catch(function() {
state = 'error';
});
$rootScope.$digest();
expect(state).toBe('error');
});
});