Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Fix ngMock window.inject() error stack trace reporting on repeated or non-initial injection function calls for the 1.4.x branch (issue #13594) #13597

Open
wants to merge 7 commits into
base: v1.4.x
Choose a base branch
from
Open
2 changes: 0 additions & 2 deletions src/ngMock/angular-mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -2521,8 +2521,6 @@ if (window.jasmine || window.mocha) {
throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
}
throw e;
} finally {
errorForStack = null;
}
}
}
Expand Down
127 changes: 99 additions & 28 deletions test/ngMock/angular-mocksSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -920,50 +920,121 @@ describe('ngMock', function() {
}).toThrow('test message');
}));

describe('error stack trace when called outside of spec context', function() {
// - Chrome, Firefox, Edge, Opera give us the stack trace as soon as an Error is created
// - IE10+, PhantomJS give us the stack trace only once the error is thrown
// - IE9 does not provide stack traces
var stackTraceSupported = (function() {
var error = new Error();
if (!error.stack) {
try {
throw error;
} catch (e) {}
// - Chrome, Firefox, Edge, Opera give us the stack trace as soon as an Error is created
// - IE10+, PhantomJS give us the stack trace only once the error is thrown
// - IE9 does not provide stack traces
var stackTraceSupported = (function() {
var error = new Error();
if (!error.stack) {
try {
throw error;
} catch (e) {}
}

return !!error.stack;
})();

// function returned by inject(), when called outside of test spec
// context, may have stored state so do not reuse the result from this
// call in multiple test specs
function testInjectCaller(injectionFunctionCount) {
var shouldThrow = [];
// using an extra named function wrapper around the Error throw avoids
// stack trace constructed by some browsers (e.g. FireFox) from
// containing the name of the external caller function
function injectionFunction(index) {
return function() {
if (shouldThrow[index])
throw new Error();
};
}
var injectionFunctions = [];
for (var i = 0; i < (injectionFunctionCount || 1); ++i) {
injectionFunctions.push(injectionFunction(i));
}
var injectingCall = inject.apply(window, injectionFunctions);
injectingCall.setThrow = function(index, value) {
if (!isDefined(value)) {
value = index;
index = 0;
}
shouldThrow[index] = value;
};
return injectingCall;
}

return !!error.stack;
})();
if (!stackTraceSupported) {
describe('on browsers not supporting stack traces', function() {
describe('when called outside of test spec context', function() {
var injectingCall = testInjectCaller();

function testCaller() {
return inject(function() {
throw new Error();
it('should not add stack trace information to thrown injection Error', function() {
injectingCall.setThrow(true);
try {
injectingCall();
} catch (e) {
expect(e.stack).toBeUndefined();
}
});
});
}
var throwErrorFromInjectCallback = testCaller();
});
}

if (stackTraceSupported) {
describe('on browsers supporting stack traces', function() {
if (stackTraceSupported) {
describe('on browsers supporting stack traces', function() {
describe('when called outside of test spec context and initial inject callback invocation fails', function() {
var throwingInjectingCall = testInjectCaller();
throwingInjectingCall.setThrow(true);

// regression test for issue #13591 when run on IE10+ or PhantomJS
it('should update thrown Error stack trace with inject call location', function() {
try {
throwErrorFromInjectCallback();
throwingInjectingCall();
} catch (e) {
expect(e.stack).toMatch('testCaller');
expect(e.stack).toMatch('testInjectCaller');
}
});
});
} else {
describe('on browsers not supporting stack traces', function() {
it('should not add stack trace information to thrown Error', function() {

describe('when called outside of test spec context', function() {
var injectingCall = testInjectCaller();

// regression test for issue #13594
// regression test for issue #13591 when run on IE10+ or PhantomJS
it('should update thrown Error stack when repeated inject callback invocations fail', function() {
injectingCall.setThrow(false);
injectingCall(); // initial call that will not throw
injectingCall.setThrow(true);
try {
throwErrorFromInjectCallback();
injectingCall(); // non-initial call, but first failing one
} catch (e) {
expect(e.stack).toBeUndefined();
expect(e.stack).toMatch('testInjectCaller');
}
try {
injectingCall(); // repeated failing call
} catch (e) {
expect(e.stack).toMatch('testInjectCaller');
}
});
});
}
});

describe('when called outside of test spec context with multiple injected functions', function() {
var injectingCall = testInjectCaller(2);

// regression test for issue #13594
// regression test for issue #13591 when run on IE10+ or PhantomJS
it('should update thrown Error stack when second injected function fails', function() {
injectingCall.setThrow(0, false);
injectingCall.setThrow(1, true);
try {
injectingCall();
} catch (e) {
expect(e.stack).toMatch('testInjectCaller');
}
});
});
});
}
});
});

Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy