Replace old "catch exceptions" logic with proper fail fast with error reporting

- Option is called stopOnSpecFailure

[#85966014]
- See #414
- See jasmine/jasmine-npm#16
This commit is contained in:
Gregg Van Hove
2018-01-30 11:36:56 -08:00
parent e908b67b19
commit e15f273f06
14 changed files with 191 additions and 133 deletions

View File

@@ -73,8 +73,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var filterSpecs = !!queryString.getParam("spec");
var catchingExceptions = queryString.getParam("catch");
env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
var stoppingOnSpecFailure = queryString.getParam("failFast");
env.stopOnSpecFailure(typeof stoppingOnSpecFailure === "undefined" ? true : stoppingOnSpecFailure);
var throwingExpectationFailures = queryString.getParam("throwFailures");
env.throwOnExpectationFailure(throwingExpectationFailures);
@@ -96,7 +96,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var htmlReporter = new jasmine.HtmlReporter({
env: env,
onRaiseExceptionsClick: function() { queryString.navigateWithNewParam("catch", !env.catchingExceptions()); },
onStopExecutionClick: function() { queryString.navigateWithNewParam("failFast", !env.stoppingOnSpecFailure()); },
onThrowExpectationsClick: function() { queryString.navigateWithNewParam("throwFailures", !env.throwingExpectationFailures()); },
onRandomClick: function() { queryString.navigateWithNewParam("random", !env.randomTests()); },
addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); },

View File

@@ -51,8 +51,8 @@
var filterSpecs = !!queryString.getParam("spec");
var catchingExceptions = queryString.getParam("catch");
env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
var stoppingOnSpecFailure = queryString.getParam("failFast");
env.stopOnSpecFailure(typeof stoppingOnSpecFailure === "undefined" ? true : stoppingOnSpecFailure);
var throwingExpectationFailures = queryString.getParam("throwFailures");
env.throwOnExpectationFailure(throwingExpectationFailures);
@@ -74,7 +74,7 @@
*/
var htmlReporter = new jasmine.HtmlReporter({
env: env,
onRaiseExceptionsClick: function() { queryString.navigateWithNewParam("catch", !env.catchingExceptions()); },
onStopExecutionClick: function() { queryString.navigateWithNewParam("failFast", !env.stoppingOnSpecFailure()); },
onThrowExpectationsClick: function() { queryString.navigateWithNewParam("throwFailures", !env.throwingExpectationFailures()); },
onRandomClick: function() { queryString.navigateWithNewParam("random", !env.randomTests()); },
addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); },

View File

@@ -85,7 +85,7 @@ jasmineRequire.HtmlReporter = function(j$) {
getContainer = options.getContainer,
createElement = options.createElement,
createTextNode = options.createTextNode,
onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {},
onStopExecutionClick = options.onStopExecutionClick || function() {},
onThrowExpectationsClick = options.onThrowExpectationsClick || function() {},
onRandomClick = options.onRandomClick || function() {},
addToExistingQueryString = options.addToExistingQueryString || defaultQueryString,
@@ -322,13 +322,13 @@ jasmineRequire.HtmlReporter = function(j$) {
var optionsMenuDom = createDom('div', { className: 'jasmine-run-options' },
createDom('span', { className: 'jasmine-trigger' }, 'Options'),
createDom('div', { className: 'jasmine-payload' },
createDom('div', { className: 'jasmine-exceptions' },
createDom('div', { className: 'jasmine-stop-on-failure' },
createDom('input', {
className: 'jasmine-raise',
id: 'jasmine-raise-exceptions',
className: 'jasmine-fail-fast',
id: 'jasmine-fail-fast',
type: 'checkbox'
}),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-raise-exceptions' }, 'raise exceptions')),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-fail-fast' }, 'stop execution on spec failure')),
createDom('div', { className: 'jasmine-throw-failures' },
createDom('input', {
className: 'jasmine-throw',
@@ -346,10 +346,9 @@ jasmineRequire.HtmlReporter = function(j$) {
)
);
var raiseCheckbox = optionsMenuDom.querySelector('#jasmine-raise-exceptions');
raiseCheckbox.checked = !env.catchingExceptions();
raiseCheckbox.onclick = onRaiseExceptionsClick;
var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast');
failFastCheckbox.checked = env.stoppingOnSpecFailure();
failFastCheckbox.onclick = onStopExecutionClick;
var throwCheckbox = optionsMenuDom.querySelector('#jasmine-throw-failures');
throwCheckbox.checked = env.throwingExpectationFailures();

View File

@@ -563,7 +563,9 @@ getJasmineRequireObj().Spec = function(j$) {
onException: function () {
self.onException.apply(self, arguments);
},
onComplete: onComplete,
onComplete: function() {
onComplete(self.result.status === 'failed' && new j$.StopExecutionError('spec failed'));
},
userContext: this.userContext()
};
@@ -712,8 +714,6 @@ getJasmineRequireObj().Env = function(j$) {
var totalSpecsDefined = 0;
var catchExceptions = true;
var realSetTimeout = j$.getGlobal().setTimeout;
var realClearTimeout = j$.getGlobal().clearTimeout;
var clearStack = j$.getClearStack(j$.getGlobal());
@@ -725,6 +725,7 @@ getJasmineRequireObj().Env = function(j$) {
var currentlyExecutingSuites = [];
var currentDeclarationSuite = null;
var throwOnExpectationFailure = false;
var stopOnSpecFailure = false;
var random = true;
var seed = null;
var handlingLoadErrors = true;
@@ -859,23 +860,9 @@ getJasmineRequireObj().Env = function(j$) {
return buildExpectationResult(attrs);
};
// TODO: fix this naming, and here's where the value comes in
this.catchExceptions = function(value) {
catchExceptions = !!value;
return catchExceptions;
};
this.catchingExceptions = function() {
return catchExceptions;
};
var maximumSpecCallbackDepth = 20;
var currentSpecCallbackDepth = 0;
var catchException = function(e) {
return j$.Spec.isPendingSpecException(e) || catchExceptions;
};
this.throwOnExpectationFailure = function(value) {
throwOnExpectationFailure = !!value;
};
@@ -884,6 +871,14 @@ getJasmineRequireObj().Env = function(j$) {
return throwOnExpectationFailure;
};
this.stopOnSpecFailure = function(value) {
stopOnSpecFailure = !!value;
};
this.stoppingOnSpecFailure = function() {
return stopOnSpecFailure;
};
this.randomizeTests = function(value) {
random = !!value;
};
@@ -907,12 +902,17 @@ getJasmineRequireObj().Env = function(j$) {
};
var queueRunnerFactory = function(options, args) {
options.catchException = catchException;
var failFast = false;
if (options.isLeaf) {
failFast = throwOnExpectationFailure;
} else if (!options.isReporter) {
failFast = stopOnSpecFailure;
}
options.clearStack = options.clearStack || clearStack;
options.timeout = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout};
options.fail = self.fail;
options.globalErrors = globalErrors;
options.completeOnFirstError = throwOnExpectationFailure && options.isLeaf;
options.completeOnFirstError = failFast;
options.onException = options.onException || function(e) {
(currentRunnable() || topSuite).onException(e);
};
@@ -4447,6 +4447,9 @@ getJasmineRequireObj().pp = function(j$) {
};
getJasmineRequireObj().QueueRunner = function(j$) {
function StopExecutionError() {}
StopExecutionError.prototype = new Error();
j$.StopExecutionError = StopExecutionError;
function once(fn) {
var called = false;
@@ -4466,12 +4469,12 @@ getJasmineRequireObj().QueueRunner = function(j$) {
this.onComplete = attrs.onComplete || function() {};
this.clearStack = attrs.clearStack || function(fn) {fn();};
this.onException = attrs.onException || function() {};
this.catchException = attrs.catchException || function() { return true; };
this.userContext = attrs.userContext || new j$.UserContext();
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;
this.errored = false;
if (typeof(this.onComplete) !== 'function') {
throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete));
@@ -4517,8 +4520,10 @@ getJasmineRequireObj().QueueRunner = function(j$) {
cleanup();
if (j$.isError_(err)) {
self.fail(err);
errored = true;
if (!(err instanceof StopExecutionError)) {
self.fail(err);
}
self.errored = errored = true;
}
function runNext() {
@@ -4541,7 +4546,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
next.fail = function nextFail() {
self.fail.apply(null, arguments);
errored = true;
self.errored = errored = true;
next();
};
@@ -4570,8 +4575,8 @@ getJasmineRequireObj().QueueRunner = function(j$) {
return { completedSynchronously: false };
}
} catch (e) {
handleException(e, queueableFn);
errored = true;
onException(e);
self.errored = errored = true;
}
cleanup();
@@ -4579,22 +4584,13 @@ getJasmineRequireObj().QueueRunner = function(j$) {
function onException(e) {
self.onException(e);
errored = true;
self.errored = errored = true;
}
function onPromiseRejection(e) {
onException(e);
next();
}
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;
}
}
};
QueueRunner.prototype.run = function(recursiveIndex) {
@@ -4610,6 +4606,8 @@ getJasmineRequireObj().QueueRunner = function(j$) {
return;
}
self.errored = result.errored;
if (this.completeOnFirstError && result.errored) {
this.skipToCleanup(iterativeIndex);
return;
@@ -4618,7 +4616,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
this.clearStack(function() {
self.globalErrors.popListener(self.handleFinalError);
self.onComplete();
self.onComplete(self.errored && new StopExecutionError());
});
};
@@ -4671,7 +4669,8 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
queueRunnerFactory({
queueableFns: fns,
onComplete: onComplete
onComplete: onComplete,
isReporter: true
});
}