When stop on failure is enabled, skip subsequent it() and beforeEach().

Note: afterEach() functions are still run, because skipping them is
highly likely to pollute specs that run after the failure.

[Finishes #92252330]

- Fixes #577
- Fixes #807
This commit is contained in:
Steve Gravrock
2017-06-15 17:30:00 -07:00
parent de862f8133
commit 585287b9d6
7 changed files with 368 additions and 56 deletions

View File

@@ -12,7 +12,9 @@ getJasmineRequireObj().QueueRunner = function(j$) {
}
function QueueRunner(attrs) {
this.queueableFns = attrs.queueableFns || [];
var queueableFns = attrs.queueableFns || [];
this.queueableFns = queueableFns.concat(attrs.cleanupFns || []);
this.firstCleanupIx = queueableFns.length;
this.onComplete = attrs.onComplete || function() {};
this.clearStack = attrs.clearStack || function(fn) {fn();};
this.onException = attrs.onException || function() {};
@@ -21,6 +23,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
this.fail = attrs.fail || function() {};
this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} };
this.completeOnFirstError = !!attrs.completeOnFirstError;
}
QueueRunner.prototype.execute = function() {
@@ -29,20 +32,32 @@ getJasmineRequireObj().QueueRunner = function(j$) {
self.onException(error);
};
this.globalErrors.pushListener(this.handleFinalError);
this.run(this.queueableFns, 0);
this.run(0);
};
QueueRunner.prototype.run = function(queueableFns, recursiveIndex) {
var length = queueableFns.length,
QueueRunner.prototype.skipToCleanup = function(lastRanIndex) {
if (lastRanIndex < this.firstCleanupIx) {
this.run(this.firstCleanupIx);
} else {
this.run(lastRanIndex + 1);
}
};
QueueRunner.prototype.run = function(recursiveIndex) {
var length = this.queueableFns.length,
self = this,
iterativeIndex;
for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
var queueableFn = queueableFns[iterativeIndex];
var completedSynchronously = attempt(queueableFn);
var result = attempt(iterativeIndex);
if (!completedSynchronously) {
if (!result.completedSynchronously) {
return;
}
if (this.completeOnFirstError && result.errored) {
this.skipToCleanup(iterativeIndex);
return;
}
}
@@ -52,7 +67,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
self.onComplete();
});
function attempt(queueableFn) {
function attempt() {
var clearTimeout = function () {
Function.prototype.apply.apply(self.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]);
},
@@ -70,18 +85,28 @@ getJasmineRequireObj().QueueRunner = function(j$) {
}),
next = once(function () {
cleanup();
function runNext() {
if (self.completeOnFirstError && errored) {
self.skipToCleanup(iterativeIndex);
} else {
self.run(iterativeIndex + 1);
}
}
if (completedSynchronously) {
setTimeout(function() {
self.run(queueableFns, iterativeIndex + 1);
});
setTimeout(runNext);
} else {
self.run(queueableFns, iterativeIndex + 1);
runNext();
}
}),
errored = false,
queueableFn = self.queueableFns[iterativeIndex],
timeoutId;
next.fail = function() {
self.fail.apply(null, arguments);
errored = true;
next();
};
@@ -102,31 +127,33 @@ getJasmineRequireObj().QueueRunner = function(j$) {
if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
maybeThenable.then(next, next.fail);
completedSynchronously = false;
return false;
return { completedSynchronously: false };
}
} else {
queueableFn.fn.call(self.userContext, next);
completedSynchronously = false;
return false;
return { completedSynchronously: false };
}
} catch (e) {
handleException(e, queueableFn);
errored = true;
}
cleanup();
return true;
}
return { completedSynchronously: true, errored: errored };
function onException(e) {
self.onException(e);
}
function onException(e) {
self.onException(e);
errored = true;
}
function handleException(e, queueableFn) {
onException(e);
if (!self.catchException(e)) {
//TODO: set a var when we catch an exception and
//use a finally block to close the loop in a nice way..
throw e;
function handleException(e, queueableFn) {
onException(e);
if (!self.catchException(e)) {
//TODO: set a var when we catch an exception and
//use a finally block to close the loop in a nice way..
throw e;
}
}
}
};