Allow user to stop a specs execution when an expectation fails
[finish #1165916] #577
This commit is contained in:
parent
1a08d1e8c6
commit
7693a4c959
@@ -19,6 +19,7 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
var currentSpec = null;
|
||||
var currentlyExecutingSuites = [];
|
||||
var currentDeclarationSuite = null;
|
||||
var throwOnExpectationFailure = false;
|
||||
|
||||
var currentSuite = function() {
|
||||
return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
|
||||
@@ -160,6 +161,14 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
return j$.Spec.isPendingSpecException(e) || catchExceptions;
|
||||
};
|
||||
|
||||
this.throwOnExpectationFailure = function(value) {
|
||||
throwOnExpectationFailure = !!value;
|
||||
};
|
||||
|
||||
this.throwingExpectationFailures = function() {
|
||||
return throwOnExpectationFailure;
|
||||
};
|
||||
|
||||
var queueRunnerFactory = function(options) {
|
||||
options.catchException = catchException;
|
||||
options.clearStack = options.clearStack || clearStack;
|
||||
@@ -242,7 +251,8 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
description: description,
|
||||
parentSuite: currentDeclarationSuite,
|
||||
expectationFactory: expectationFactory,
|
||||
expectationResultFactory: expectationResultFactory
|
||||
expectationResultFactory: expectationResultFactory,
|
||||
throwOnExpectationFailure: throwOnExpectationFailure
|
||||
});
|
||||
|
||||
runnableLookupTable[suite.id] = suite;
|
||||
@@ -336,7 +346,8 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
queueableFn: {
|
||||
fn: fn,
|
||||
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
|
||||
}
|
||||
},
|
||||
throwOnExpectationFailure: throwOnExpectationFailure
|
||||
});
|
||||
|
||||
runnableLookupTable[spec.id] = spec;
|
||||
|
||||
@@ -12,6 +12,7 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
this.expectationResultFactory = attrs.expectationResultFactory || function() { };
|
||||
this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
|
||||
this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
|
||||
this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
|
||||
|
||||
if (!this.queueableFn.fn) {
|
||||
this.pend();
|
||||
@@ -33,6 +34,10 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
this.result.passedExpectations.push(expectationResult);
|
||||
} else {
|
||||
this.result.failedExpectations.push(expectationResult);
|
||||
|
||||
if(this.throwOnExpectationFailure){
|
||||
throw new j$.errors.ExpectationFailed();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -76,6 +81,10 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e instanceof j$.errors.ExpectationFailed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.addExpectationResult(false, {
|
||||
matcherName: '',
|
||||
passed: false,
|
||||
|
||||
@@ -6,6 +6,7 @@ getJasmineRequireObj().Suite = function() {
|
||||
this.description = attrs.description;
|
||||
this.expectationFactory = attrs.expectationFactory;
|
||||
this.expectationResultFactory = attrs.expectationResultFactory;
|
||||
this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
|
||||
|
||||
this.beforeFns = [];
|
||||
this.afterFns = [];
|
||||
@@ -99,6 +100,10 @@ getJasmineRequireObj().Suite = function() {
|
||||
};
|
||||
|
||||
Suite.prototype.onException = function() {
|
||||
if (arguments[0] instanceof j$.errors.ExpectationFailed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(isAfterAll(this.children)) {
|
||||
var data = {
|
||||
matcherName: '',
|
||||
@@ -120,10 +125,17 @@ getJasmineRequireObj().Suite = function() {
|
||||
if(isAfterAll(this.children) && isFailure(arguments)){
|
||||
var data = arguments[1];
|
||||
this.result.failedExpectations.push(this.expectationResultFactory(data));
|
||||
if(this.throwOnExpectationFailure) {
|
||||
throw new j$.errors.ExpectationFailed();
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var child = this.children[i];
|
||||
child.addExpectationResult.apply(child, arguments);
|
||||
try {
|
||||
child.addExpectationResult.apply(child, arguments);
|
||||
} catch(e) {
|
||||
// keep going
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
10
src/core/errors.js
Normal file
10
src/core/errors.js
Normal file
@@ -0,0 +1,10 @@
|
||||
getJasmineRequireObj().errors = function() {
|
||||
function ExpectationFailed() {}
|
||||
|
||||
ExpectationFailed.prototype = new Error();
|
||||
ExpectationFailed.prototype.constructor = ExpectationFailed;
|
||||
|
||||
return {
|
||||
ExpectationFailed: ExpectationFailed
|
||||
};
|
||||
};
|
||||
@@ -20,6 +20,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
|
||||
|
||||
jRequire.base(j$, jasmineGlobal);
|
||||
j$.util = jRequire.util();
|
||||
j$.errors = jRequire.errors();
|
||||
j$.Any = jRequire.Any();
|
||||
j$.Anything = jRequire.Anything(j$);
|
||||
j$.CallTracker = jRequire.CallTracker();
|
||||
|
||||
@@ -11,6 +11,7 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
createElement = options.createElement,
|
||||
createTextNode = options.createTextNode,
|
||||
onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {},
|
||||
onThrowExpectationsClick = options.onThrowExpectationsClick || function() {},
|
||||
addToExistingQueryString = options.addToExistingQueryString || defaultQueryString,
|
||||
timer = options.timer || noopTimer,
|
||||
results = [],
|
||||
@@ -116,22 +117,51 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
|
||||
this.jasmineDone = function() {
|
||||
var banner = find('.banner');
|
||||
banner.appendChild(createDom('span', {className: 'duration'}, 'finished in ' + timer.elapsed() / 1000 + 's'));
|
||||
|
||||
var alert = find('.alert');
|
||||
alert.appendChild(createDom('span', {className: 'duration'}, 'finished in ' + timer.elapsed() / 1000 + 's'));
|
||||
|
||||
alert.appendChild(createDom('span', { className: 'exceptions' },
|
||||
createDom('label', { className: 'label', 'for': 'raise-exceptions' }, 'raise exceptions'),
|
||||
createDom('input', {
|
||||
className: 'raise',
|
||||
id: 'raise-exceptions',
|
||||
type: 'checkbox'
|
||||
})
|
||||
));
|
||||
var checkbox = find('#raise-exceptions');
|
||||
banner.appendChild(
|
||||
createDom('div', { className: 'run-options' },
|
||||
createDom('span', { className: 'trigger' }, 'Options'),
|
||||
createDom('div', { className: 'payload' },
|
||||
createDom('div', { className: 'exceptions' },
|
||||
createDom('input', {
|
||||
className: 'raise',
|
||||
id: 'raise-exceptions',
|
||||
type: 'checkbox'
|
||||
}),
|
||||
createDom('label', { className: 'label', 'for': 'raise-exceptions' }, 'raise exceptions')),
|
||||
createDom('div', { className: 'throw-failures' },
|
||||
createDom('input', {
|
||||
className: 'throw',
|
||||
id: 'throw-failures',
|
||||
type: 'checkbox'
|
||||
}),
|
||||
createDom('label', { className: 'label', 'for': 'throw-failures' }, 'stop spec on expectation failure'))
|
||||
)
|
||||
));
|
||||
|
||||
checkbox.checked = !env.catchingExceptions();
|
||||
checkbox.onclick = onRaiseExceptionsClick;
|
||||
var raiseCheckbox = find('#raise-exceptions');
|
||||
|
||||
raiseCheckbox.checked = !env.catchingExceptions();
|
||||
raiseCheckbox.onclick = onRaiseExceptionsClick;
|
||||
|
||||
var throwCheckbox = find('#throw-failures');
|
||||
throwCheckbox.checked = env.throwingExpectationFailures();
|
||||
throwCheckbox.onclick = onThrowExpectationsClick;
|
||||
|
||||
var optionsMenu = find('.run-options'),
|
||||
optionsTrigger = optionsMenu.querySelector('.trigger'),
|
||||
optionsPayload = optionsMenu.querySelector('.payload'),
|
||||
isOpen = /\bopen\b/;
|
||||
|
||||
optionsTrigger.onclick = function() {
|
||||
if (isOpen.test(optionsPayload.className)) {
|
||||
optionsPayload.className = optionsPayload.className.replace(isOpen, '');
|
||||
} else {
|
||||
optionsPayload.className += ' open';
|
||||
}
|
||||
};
|
||||
|
||||
if (specsExecuted < totalSpecsDefined) {
|
||||
var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
|
||||
|
||||
@@ -14,6 +14,7 @@ $failing-color: #ca3a11;
|
||||
$pending-color: #ba9d37;
|
||||
$empty-color: #eff543;
|
||||
$neutral-color: #bababa;
|
||||
$jasmine-color: #8a4182;
|
||||
|
||||
$font-size: 11px;
|
||||
$large-font-size: 14px;
|
||||
@@ -77,12 +78,6 @@ body {
|
||||
top: 6px;
|
||||
}
|
||||
|
||||
.banner .duration {
|
||||
position: absolute;
|
||||
right: 14px;
|
||||
top: 6px;
|
||||
}
|
||||
|
||||
// This div is available for testing elements that must be added to the DOM.
|
||||
// We position it out of view, so it doesn't obstruct the runner.
|
||||
#jasmine_content {
|
||||
@@ -101,8 +96,10 @@ body {
|
||||
}
|
||||
|
||||
.duration {
|
||||
color: $faint-text-color;
|
||||
color: #fff;
|
||||
float: right;
|
||||
line-height: $line-height * 2;
|
||||
padding-right: 9px;
|
||||
}
|
||||
|
||||
//--- Symbol summary ---//
|
||||
@@ -166,11 +163,32 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.exceptions {
|
||||
color: #fff;
|
||||
.run-options {
|
||||
float: right;
|
||||
margin-top: 5px;
|
||||
margin-right: 5px;
|
||||
border: 1px solid $jasmine-color;
|
||||
color: $jasmine-color;
|
||||
position: relative;
|
||||
line-height: 20px;
|
||||
|
||||
.trigger {
|
||||
cursor: pointer;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
.payload {
|
||||
position: absolute;
|
||||
display: none;
|
||||
right: -1px;
|
||||
border: 1px solid $jasmine-color;
|
||||
background-color: $page-background-color;
|
||||
white-space: nowrap;
|
||||
padding: 4px 8px;
|
||||
|
||||
&.open {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--- Alerts: status bars ---//
|
||||
|
||||
Reference in New Issue
Block a user