diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js index b8fc8d065985..c5966b37f6fb 100644 --- a/src/ngMock/angular-mocks.js +++ b/src/ngMock/angular-mocks.js @@ -2899,6 +2899,15 @@ angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) { window.inject = angular.mock.inject = function() { var blockFns = Array.prototype.slice.call(arguments, 0); var errorForStack = new Error('Declaration Location'); + // some browsers, e.g. PhanthomJS, do not set a new error object's stack + // information until it has been thrown + if (!errorForStack.stack) { + try { + throw errorForStack; + } catch (e) { + errorForStack = e; + } + } return wasInjectorCreated() ? workFn.call(currentSpec) : workFn; ///////////////////// function workFn() { diff --git a/test/ngMock/angular-mocksSpec.js b/test/ngMock/angular-mocksSpec.js index 1e19e2eb9ae6..9db25fff5e7d 100644 --- a/test/ngMock/angular-mocksSpec.js +++ b/test/ngMock/angular-mocksSpec.js @@ -914,6 +914,53 @@ describe('ngMock', function() { }); }).toThrow('test message'); })); + + describe('when called outside of test spec context and inject callback throws an Error', function() { + // - IE9 does not support providing stack traces + // - Chrome & Firefox give us the stack trace as soon as an Error is + // created + // - IE10, IE11 & PhantomJS give us the stack trace only once the error + // is thrown + var stackTraceSupported = (function() { + var error = new Error(); + if (error.stack) + return error.stack; + try { + throw error; + } catch (e) { + return e.stack; + } + })(); + + function testCaller() { + return inject(function() { + throw new Error(); + }); + } + var throwErrorFromInjectCallback = testCaller(); + + if (stackTraceSupported) { + describe('on browsers supporting stack traces', function() { + it('should update thrown Error stack with inject call location', function() { + try { + throwErrorFromInjectCallback(); + } catch (e) { + expect(e.stack).toMatch('testCaller'); + } + }); + }); + } else { + describe('on browsers not supporting stack traces', function() { + it('should not add stack trace information to thrown Error', function() { + try { + throwErrorFromInjectCallback(); + } catch (e) { + expect(e.stack).not.toBeDefined(); + } + }); + }); + } + }); }); });