diff --git a/src/ng/q.js b/src/ng/q.js index c2fb12361c29..bc5167661824 100644 --- a/src/ng/q.js +++ b/src/ng/q.js @@ -343,6 +343,17 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { } }); + function PassToExceptionHandlerError(e) { + this.message = e.message; + this.name = e.name; + if (e.line) this.line = e.line; + if (e.sourceId) this.sourceId = e.sourceId; + if (e.stack) this.stack = e.stack; + if (e.stackArray) this.stackArray = e.stackArray; + } + + PassToExceptionHandlerError.prototype = Object.create(Error.prototype); + function processQueue(state) { var fn, promise, pending; @@ -364,6 +375,10 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { } } catch (e) { rejectPromise(promise, e); + // This error is explicitly marked for being passed to the $exceptionHandler + if (e && e instanceof PassToExceptionHandlerError) { + exceptionHandler(e); + } } } } finally { @@ -668,6 +683,7 @@ function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) { $Q.resolve = resolve; $Q.all = all; $Q.race = race; + $Q.$$PassToExceptionHandlerError = PassToExceptionHandlerError; return $Q; } diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js index 3416448b40b6..77cb1e2a89f3 100644 --- a/src/ngMock/angular-mocks.js +++ b/src/ngMock/angular-mocks.js @@ -1323,7 +1323,7 @@ angular.mock.dump = function(object) { ``` */ angular.mock.$httpBackendDecorator = - ['$rootScope', '$timeout', '$delegate', createHttpBackendMock]; + ['$q', '$rootScope', '$timeout', '$delegate', createHttpBackendMock]; /** * General factory function for $httpBackend mock. @@ -1339,7 +1339,7 @@ angular.mock.$httpBackendDecorator = * @param {Object=} $browser Auto-flushing enabled if specified * @return {Object} Instance of $httpBackend mock */ -function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { +function createHttpBackendMock($q, $rootScope, $timeout, $delegate, $browser) { var definitions = [], expectations = [], responses = [], @@ -1438,10 +1438,22 @@ function createHttpBackendMock($rootScope, $timeout, $delegate, $browser) { return; } } - throw wasExpected ? + + // In addition to be being converted to a rejection, this error also needs to be passed to + // the $exceptionHandler and be rethrown (so that the test fails). + var error = wasExpected ? new Error('No response defined !') : new Error('Unexpected request: ' + method + ' ' + url + '\n' + (expectation ? 'Expected ' + expectation : 'No more request expected')); + + // IE10+ and PhanthomJS do not set stack trace information, until the error is thrown + if (!error.stack) { + try { + throw error; + } catch (e) { /* empty */ } + } + + throw new $q.$$PassToExceptionHandlerError(error); } /** @@ -2706,7 +2718,7 @@ angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) { */ angular.mock.e2e = {}; angular.mock.e2e.$httpBackendDecorator = - ['$rootScope', '$timeout', '$delegate', '$browser', createHttpBackendMock]; + ['$q', '$rootScope', '$timeout', '$delegate', '$browser', createHttpBackendMock]; /**