Collect unhandled exceptions and pass them to the current runnable

Fixes #529
Fixes #937
This commit is contained in:
Gregg Van Hove
2017-03-07 16:32:11 -08:00
parent 92e7436db2
commit 1042c9a2dd
8 changed files with 283 additions and 0 deletions

View File

@@ -40,6 +40,8 @@ getJasmineRequireObj().Env = function(j$) {
'specDone'
]);
var globalErrors = new j$.GlobalErrors();
this.specFilter = function() {
return true;
};
@@ -187,6 +189,7 @@ getJasmineRequireObj().Env = function(j$) {
options.clearStack = options.clearStack || clearStack;
options.timeout = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout};
options.fail = self.fail;
options.globalErrors = globalErrors;
new j$.QueueRunner(options).execute();
};
@@ -250,9 +253,11 @@ getJasmineRequireObj().Env = function(j$) {
currentlyExecutingSuites.push(topSuite);
globalErrors.install();
processor.execute(function() {
clearResourcesForRunnable(topSuite.id);
currentlyExecutingSuites.pop();
globalErrors.uninstall();
reporter.jasmineDone({
order: order,

45
src/core/GlobalErrors.js Normal file
View File

@@ -0,0 +1,45 @@
getJasmineRequireObj().GlobalErrors = function(j$) {
function GlobalErrors(global) {
var handlers = [];
global = global || j$.getGlobal();
var onerror = function onerror() {
var handler = handlers[handlers.length - 1];
handler.apply(null, Array.prototype.slice.call(arguments, 0));
};
this.uninstall = function noop() {};
this.install = function install() {
if (global.process && j$.isFunction_(global.process.on)) {
var originalHandlers = global.process.listeners('uncaughtException');
global.process.removeAllListeners('uncaughtException');
global.process.on('uncaughtException', onerror);
this.uninstall = function uninstall() {
global.process.removeListener('uncaughtException', onerror);
for (var i = 0; i < originalHandlers.length; i++) {
global.process.on('uncaughtException', originalHandlers[i]);
}
};
} else {
var originalHandler = global.onerror;
global.onerror = onerror;
this.uninstall = function uninstall() {
global.onerror = originalHandler;
};
}
};
this.pushListener = function pushListener(listener) {
handlers.push(listener);
};
this.popListener = function popListener() {
handlers.pop();
};
}
return GlobalErrors;
};

View File

@@ -20,6 +20,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
this.userContext = attrs.userContext || {};
this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
this.fail = attrs.fail || function() {};
this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} };
}
QueueRunner.prototype.execute = function() {
@@ -56,8 +57,13 @@ getJasmineRequireObj().QueueRunner = function(j$) {
var clearTimeout = function () {
Function.prototype.apply.apply(self.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]);
},
handleError = function(error) {
onException(error);
next();
},
next = once(function () {
clearTimeout(timeoutId);
self.globalErrors.popListener(handleError);
self.run(queueableFns, iterativeIndex + 1);
}),
timeoutId;
@@ -67,6 +73,8 @@ getJasmineRequireObj().QueueRunner = function(j$) {
next();
};
self.globalErrors.pushListener(handleError);
if (queueableFn.timeout) {
timeoutId = Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [function() {
var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');

View File

@@ -57,6 +57,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.DiffBuilder = jRequire.DiffBuilder(j$);
j$.NullDiffBuilder = jRequire.NullDiffBuilder(j$);
j$.ObjectPath = jRequire.ObjectPath(j$);
j$.GlobalErrors = jRequire.GlobalErrors(j$);
j$.matchers = jRequire.requireMatchers(jRequire, j$);