Merge branch 'random-tests' of https://github.com/marcioj/jasmine into marcioj-random-tests
This commit is contained in:
@@ -77,6 +77,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
var throwingExpectationFailures = queryString.getParam("throwFailures");
|
||||
env.throwOnExpectationFailure(throwingExpectationFailures);
|
||||
|
||||
var random = queryString.getParam("random");
|
||||
env.randomizeTests(random);
|
||||
|
||||
var seed = queryString.getParam("seed");
|
||||
if (seed) {
|
||||
env.seed(seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* ## Reporters
|
||||
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
|
||||
@@ -85,6 +93,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
env: env,
|
||||
onRaiseExceptionsClick: function() { queryString.navigateWithNewParam("catch", !env.catchingExceptions()); },
|
||||
onThrowExpectationsClick: function() { queryString.navigateWithNewParam("throwFailures", !env.throwingExpectationFailures()); },
|
||||
onRandomClick: function() { queryString.navigateWithNewParam("random", !env.randomTests()); },
|
||||
addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); },
|
||||
getContainer: function() { return document.body; },
|
||||
createElement: function() { return document.createElement.apply(document, arguments); },
|
||||
|
||||
@@ -55,6 +55,14 @@
|
||||
var throwingExpectationFailures = queryString.getParam("throwFailures");
|
||||
env.throwOnExpectationFailure(throwingExpectationFailures);
|
||||
|
||||
var random = queryString.getParam("random");
|
||||
env.randomizeTests(random);
|
||||
|
||||
var seed = queryString.getParam("seed");
|
||||
if (seed) {
|
||||
env.seed(seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* ## Reporters
|
||||
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
|
||||
@@ -63,6 +71,7 @@
|
||||
env: env,
|
||||
onRaiseExceptionsClick: function() { queryString.navigateWithNewParam("catch", !env.catchingExceptions()); },
|
||||
onThrowExpectationsClick: function() { queryString.navigateWithNewParam("throwFailures", !env.throwingExpectationFailures()); },
|
||||
onRandomClick: function() { queryString.navigateWithNewParam("random", !env.randomTests()); },
|
||||
addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); },
|
||||
getContainer: function() { return document.body; },
|
||||
createElement: function() { return document.createElement.apply(document, arguments); },
|
||||
|
||||
@@ -41,6 +41,7 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
createTextNode = options.createTextNode,
|
||||
onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {},
|
||||
onThrowExpectationsClick = options.onThrowExpectationsClick || function() {},
|
||||
onRandomClick = options.onRandomClick || function() {},
|
||||
addToExistingQueryString = options.addToExistingQueryString || defaultQueryString,
|
||||
timer = options.timer || noopTimer,
|
||||
results = [],
|
||||
@@ -146,9 +147,10 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
}
|
||||
};
|
||||
|
||||
this.jasmineDone = function() {
|
||||
this.jasmineDone = function(doneResult) {
|
||||
var banner = find('.jasmine-banner');
|
||||
var alert = find('.jasmine-alert');
|
||||
var order = doneResult && doneResult.order;
|
||||
alert.appendChild(createDom('span', {className: 'jasmine-duration'}, 'finished in ' + timer.elapsed() / 1000 + 's'));
|
||||
|
||||
banner.appendChild(
|
||||
@@ -168,7 +170,14 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
id: 'jasmine-throw-failures',
|
||||
type: 'checkbox'
|
||||
}),
|
||||
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-throw-failures' }, 'stop spec on expectation failure'))
|
||||
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-throw-failures' }, 'stop spec on expectation failure')),
|
||||
createDom('div', { className: 'jasmine-random-order' },
|
||||
createDom('input', {
|
||||
className: 'jasmine-random',
|
||||
id: 'jasmine-random-order',
|
||||
type: 'checkbox'
|
||||
}),
|
||||
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-random-order' }, 'run tests in random order'))
|
||||
)
|
||||
));
|
||||
|
||||
@@ -181,6 +190,10 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
throwCheckbox.checked = env.throwingExpectationFailures();
|
||||
throwCheckbox.onclick = onThrowExpectationsClick;
|
||||
|
||||
var randomCheckbox = find('#jasmine-random-order');
|
||||
randomCheckbox.checked = env.randomTests();
|
||||
randomCheckbox.onclick = onRandomClick;
|
||||
|
||||
var optionsMenu = find('.jasmine-run-options'),
|
||||
optionsTrigger = optionsMenu.querySelector('.jasmine-trigger'),
|
||||
optionsPayload = optionsMenu.querySelector('.jasmine-payload'),
|
||||
@@ -214,7 +227,15 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
statusBarMessage += 'No specs found';
|
||||
}
|
||||
|
||||
alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage));
|
||||
var seedBar;
|
||||
if (order && order.random) {
|
||||
seedBar = createDom('span', {class: 'jasmine-seed-bar'},
|
||||
', randomized with seed ',
|
||||
createDom('a', {title: 'randomized with seed ' + order.seed, href: seedHref(order.seed)}, order.seed)
|
||||
);
|
||||
}
|
||||
|
||||
alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage, seedBar));
|
||||
|
||||
for(i = 0; i < failedSuites.length; i++) {
|
||||
var failedSuite = failedSuites[i];
|
||||
@@ -345,6 +366,10 @@ jasmineRequire.HtmlReporter = function(j$) {
|
||||
return addToExistingQueryString('spec', result.fullName);
|
||||
}
|
||||
|
||||
function seedHref(seed) {
|
||||
return addToExistingQueryString('seed', seed);
|
||||
}
|
||||
|
||||
function defaultQueryString(key, value) {
|
||||
return '?' + key + '=' + value;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
|
||||
j$.Timer = jRequire.Timer();
|
||||
j$.TreeProcessor = jRequire.TreeProcessor();
|
||||
j$.version = jRequire.version();
|
||||
j$.Order = jRequire.Order();
|
||||
|
||||
j$.matchers = jRequire.requireMatchers(jRequire, j$);
|
||||
|
||||
@@ -452,6 +453,53 @@ if (typeof window == void 0 && typeof exports == 'object') {
|
||||
exports.Spec = jasmineRequire.Spec;
|
||||
}
|
||||
|
||||
/*jshint bitwise: false*/
|
||||
|
||||
getJasmineRequireObj().Order = function() {
|
||||
function Order(options) {
|
||||
this.random = 'random' in options ? options.random : true;
|
||||
var seed = this.seed = options.seed || generateSeed();
|
||||
this.sort = this.random ? randomOrder : naturalOrder;
|
||||
|
||||
function naturalOrder(items) {
|
||||
return items;
|
||||
}
|
||||
|
||||
function randomOrder(items) {
|
||||
var copy = items.slice();
|
||||
copy.sort(function(a, b) {
|
||||
return jenkinsHash(seed + a.id) - jenkinsHash(seed + b.id);
|
||||
});
|
||||
return copy;
|
||||
}
|
||||
|
||||
function generateSeed() {
|
||||
return String(Math.random()).slice(-5);
|
||||
}
|
||||
|
||||
// Bob Jenkins One-at-a-Time Hash algorithm is a non-cryptographic hash function
|
||||
// used to get a different output when the key changes slighly.
|
||||
// We use your return to sort the children randomly in a consistent way when
|
||||
// used in conjunction with a seed
|
||||
|
||||
function jenkinsHash(key) {
|
||||
var hash, i;
|
||||
for(hash = i = 0; i < key.length; ++i) {
|
||||
hash += key.charCodeAt(i);
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
return hash;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Order;
|
||||
};
|
||||
|
||||
getJasmineRequireObj().Env = function(j$) {
|
||||
function Env(options) {
|
||||
options = options || {};
|
||||
@@ -474,6 +522,8 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
var currentlyExecutingSuites = [];
|
||||
var currentDeclarationSuite = null;
|
||||
var throwOnExpectationFailure = false;
|
||||
var random = false;
|
||||
var seed = null;
|
||||
|
||||
var currentSuite = function() {
|
||||
return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
|
||||
@@ -623,6 +673,21 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
return throwOnExpectationFailure;
|
||||
};
|
||||
|
||||
this.randomizeTests = function(value) {
|
||||
random = !!value;
|
||||
};
|
||||
|
||||
this.randomTests = function() {
|
||||
return random;
|
||||
};
|
||||
|
||||
this.seed = function(value) {
|
||||
if (value) {
|
||||
seed = value;
|
||||
}
|
||||
return seed;
|
||||
};
|
||||
|
||||
var queueRunnerFactory = function(options) {
|
||||
options.catchException = catchException;
|
||||
options.clearStack = options.clearStack || clearStack;
|
||||
@@ -654,6 +719,12 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
runnablesToRun = [topSuite.id];
|
||||
}
|
||||
}
|
||||
|
||||
var order = new j$.Order({
|
||||
random: random,
|
||||
seed: seed
|
||||
});
|
||||
|
||||
var processor = new j$.TreeProcessor({
|
||||
tree: topSuite,
|
||||
runnableIds: runnablesToRun,
|
||||
@@ -669,6 +740,9 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
}
|
||||
currentlyExecutingSuites.pop();
|
||||
reporter.suiteDone(result);
|
||||
},
|
||||
orderChildren: function(node) {
|
||||
return order.sort(node.children);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -680,7 +754,11 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
totalSpecsDefined: totalSpecsDefined
|
||||
});
|
||||
|
||||
processor.execute(reporter.jasmineDone);
|
||||
processor.execute(function() {
|
||||
reporter.jasmineDone({
|
||||
order: order
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.addReporter = function(reporterToAdd) {
|
||||
@@ -2206,6 +2284,7 @@ getJasmineRequireObj().TreeProcessor = function() {
|
||||
queueRunnerFactory = attrs.queueRunnerFactory,
|
||||
nodeStart = attrs.nodeStart || function() {},
|
||||
nodeComplete = attrs.nodeComplete || function() {},
|
||||
orderChildren = attrs.orderChildren || function(node) { return node.children; },
|
||||
stats = { valid: true },
|
||||
processed = false,
|
||||
defaultMin = Infinity,
|
||||
@@ -2269,8 +2348,10 @@ getJasmineRequireObj().TreeProcessor = function() {
|
||||
} else {
|
||||
var hasExecutableChild = false;
|
||||
|
||||
for (var i = 0; i < node.children.length; i++) {
|
||||
var child = node.children[i];
|
||||
var orderedChildren = orderChildren(node);
|
||||
|
||||
for (var i = 0; i < orderedChildren.length; i++) {
|
||||
var child = orderedChildren[i];
|
||||
|
||||
processNode(child, parentEnabled);
|
||||
|
||||
@@ -2287,7 +2368,7 @@ getJasmineRequireObj().TreeProcessor = function() {
|
||||
executable: hasExecutableChild
|
||||
};
|
||||
|
||||
segmentChildren(node, stats[node.id], executableIndex);
|
||||
segmentChildren(node, orderedChildren, stats[node.id], executableIndex);
|
||||
|
||||
if (!node.canBeReentered() && stats[node.id].segments.length > 1) {
|
||||
stats = { valid: false };
|
||||
@@ -2303,11 +2384,11 @@ getJasmineRequireObj().TreeProcessor = function() {
|
||||
return executableIndex === undefined ? defaultMax : executableIndex;
|
||||
}
|
||||
|
||||
function segmentChildren(node, nodeStats, executableIndex) {
|
||||
function segmentChildren(node, orderedChildren, nodeStats, executableIndex) {
|
||||
var currentSegment = { index: 0, owner: node, nodes: [], min: startingMin(executableIndex), max: startingMax(executableIndex) },
|
||||
result = [currentSegment],
|
||||
lastMax = defaultMax,
|
||||
orderedChildSegments = orderChildSegments(node.children);
|
||||
orderedChildSegments = orderChildSegments(orderedChildren);
|
||||
|
||||
function isSegmentBoundary(minIndex) {
|
||||
return lastMax !== defaultMax && minIndex !== defaultMin && lastMax < minIndex - 1;
|
||||
|
||||
Reference in New Issue
Block a user