Implement TreeProcessor to solve some issues with running the suite
- execute beforeAll/afterAll once per suite instead of once per child when running focused specs/suites Fixes #773 - refuse to execute an order if it would cause a suite with a beforeAll or afterAll to be re-entered after leaving once - report children of an xdescribe similarly to how they would be reported if they were themselves x'd out Fixes #774 - only process the tree once instead of figuring it out again at each level [finishes #87545620] Fixes #776
This commit is contained in:
committed by
Chris Amavisca and Gregg Van Hove
parent
0c68cc4afc
commit
715de7aa38
@@ -65,6 +65,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
|
||||
j$.StringMatching = jRequire.StringMatching(j$);
|
||||
j$.Suite = jRequire.Suite();
|
||||
j$.Timer = jRequire.Timer();
|
||||
j$.TreeProcessor = jRequire.TreeProcessor();
|
||||
j$.version = jRequire.version();
|
||||
|
||||
j$.matchers = jRequire.requireMatchers(jRequire, j$);
|
||||
@@ -330,12 +331,15 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
return this.expectationFactory(actual, this);
|
||||
};
|
||||
|
||||
Spec.prototype.execute = function(onComplete) {
|
||||
Spec.prototype.execute = function(onComplete, enabled) {
|
||||
var self = this;
|
||||
if (enabled === false && !this.markedPending) {
|
||||
this.disable();
|
||||
}
|
||||
|
||||
this.onStart(this);
|
||||
|
||||
if (this.markedPending || this.disabled) {
|
||||
if (!this.isExecutable()) {
|
||||
complete();
|
||||
return;
|
||||
}
|
||||
@@ -386,6 +390,11 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
}
|
||||
};
|
||||
|
||||
Spec.prototype.getResult = function() {
|
||||
this.result.status = this.status();
|
||||
return this.result;
|
||||
};
|
||||
|
||||
Spec.prototype.status = function() {
|
||||
if (this.disabled) {
|
||||
return 'disabled';
|
||||
@@ -533,27 +542,21 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
delete runnableResources[id];
|
||||
};
|
||||
|
||||
var beforeAndAfterFns = function(suite, runnablesExplictlySet) {
|
||||
var beforeAndAfterFns = function(suite) {
|
||||
return function() {
|
||||
var befores = [],
|
||||
afters = [],
|
||||
beforeAlls = [],
|
||||
afterAlls = [];
|
||||
afters = [];
|
||||
|
||||
while(suite) {
|
||||
befores = befores.concat(suite.beforeFns);
|
||||
afters = afters.concat(suite.afterFns);
|
||||
|
||||
if (runnablesExplictlySet()) {
|
||||
beforeAlls = beforeAlls.concat(suite.beforeAllFns);
|
||||
afterAlls = afterAlls.concat(suite.afterAllFns);
|
||||
}
|
||||
|
||||
suite = suite.parentSuite;
|
||||
}
|
||||
|
||||
return {
|
||||
befores: beforeAlls.reverse().concat(befores.reverse()),
|
||||
afters: afters.concat(afterAlls)
|
||||
befores: befores.reverse(),
|
||||
afters: afters
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -623,26 +626,40 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.execute = function(runnablesToRun) {
|
||||
if(runnablesToRun) {
|
||||
runnablesExplictlySet = true;
|
||||
} else if (focusedRunnables.length) {
|
||||
runnablesExplictlySet = true;
|
||||
runnablesToRun = focusedRunnables;
|
||||
} else {
|
||||
runnablesToRun = [topSuite.id];
|
||||
if(!runnablesToRun) {
|
||||
if (focusedRunnables.length) {
|
||||
runnablesToRun = focusedRunnables;
|
||||
} else {
|
||||
runnablesToRun = [topSuite.id];
|
||||
}
|
||||
}
|
||||
var processor = new j$.TreeProcessor({
|
||||
tree: topSuite,
|
||||
runnableIds: runnablesToRun,
|
||||
queueRunnerFactory: queueRunnerFactory,
|
||||
nodeStart: function(suite) {
|
||||
currentlyExecutingSuites.push(suite);
|
||||
defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
|
||||
reporter.suiteStarted(suite.result);
|
||||
},
|
||||
nodeComplete: function(suite, result) {
|
||||
if (!suite.disabled) {
|
||||
clearResourcesForRunnable(suite.id);
|
||||
}
|
||||
currentlyExecutingSuites.pop();
|
||||
reporter.suiteDone(result);
|
||||
}
|
||||
});
|
||||
|
||||
var allFns = [];
|
||||
for(var i = 0; i < runnablesToRun.length; i++) {
|
||||
var runnable = runnableLookupTable[runnablesToRun[i]];
|
||||
allFns.push((function(runnable) { return { fn: function(done) { runnable.execute(done); } }; })(runnable));
|
||||
if(!processor.processTree().valid) {
|
||||
throw new Error('Invalid order: would cause a beforeAll or afterAll to be run multiple times');
|
||||
}
|
||||
|
||||
reporter.jasmineStarted({
|
||||
totalSpecsDefined: totalSpecsDefined
|
||||
});
|
||||
|
||||
queueRunnerFactory({queueableFns: allFns, onComplete: reporter.jasmineDone});
|
||||
processor.execute(reporter.jasmineDone);
|
||||
};
|
||||
|
||||
this.addReporter = function(reporterToAdd) {
|
||||
@@ -666,28 +683,12 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
id: getNextSuiteId(),
|
||||
description: description,
|
||||
parentSuite: currentDeclarationSuite,
|
||||
queueRunner: queueRunnerFactory,
|
||||
onStart: suiteStarted,
|
||||
expectationFactory: expectationFactory,
|
||||
expectationResultFactory: expectationResultFactory,
|
||||
runnablesExplictlySetGetter: runnablesExplictlySetGetter,
|
||||
resultCallback: function(attrs) {
|
||||
if (!suite.disabled) {
|
||||
clearResourcesForRunnable(suite.id);
|
||||
}
|
||||
currentlyExecutingSuites.pop();
|
||||
reporter.suiteDone(attrs);
|
||||
}
|
||||
expectationResultFactory: expectationResultFactory
|
||||
});
|
||||
|
||||
runnableLookupTable[suite.id] = suite;
|
||||
return suite;
|
||||
|
||||
function suiteStarted(suite) {
|
||||
currentlyExecutingSuites.push(suite);
|
||||
defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
|
||||
reporter.suiteStarted(suite.result);
|
||||
}
|
||||
};
|
||||
|
||||
this.describe = function(description, specDefinitions) {
|
||||
@@ -759,17 +760,11 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
}
|
||||
}
|
||||
|
||||
var runnablesExplictlySet = false;
|
||||
|
||||
var runnablesExplictlySetGetter = function(){
|
||||
return runnablesExplictlySet;
|
||||
};
|
||||
|
||||
var specFactory = function(description, fn, suite, timeout) {
|
||||
totalSpecsDefined++;
|
||||
var spec = new j$.Spec({
|
||||
id: getNextSpecId(),
|
||||
beforeAndAfterFns: beforeAndAfterFns(suite, runnablesExplictlySetGetter),
|
||||
beforeAndAfterFns: beforeAndAfterFns(suite),
|
||||
expectationFactory: expectationFactory,
|
||||
resultCallback: specResultCallback,
|
||||
getSpecName: function(spec) {
|
||||
@@ -1965,18 +1960,13 @@ getJasmineRequireObj().Suite = function() {
|
||||
this.id = attrs.id;
|
||||
this.parentSuite = attrs.parentSuite;
|
||||
this.description = attrs.description;
|
||||
this.onStart = attrs.onStart || function() {};
|
||||
this.resultCallback = attrs.resultCallback || function() {};
|
||||
this.clearStack = attrs.clearStack || function(fn) {fn();};
|
||||
this.expectationFactory = attrs.expectationFactory;
|
||||
this.expectationResultFactory = attrs.expectationResultFactory;
|
||||
this.runnablesExplictlySetGetter = attrs.runnablesExplictlySetGetter || function() {};
|
||||
|
||||
this.beforeFns = [];
|
||||
this.afterFns = [];
|
||||
this.beforeAllFns = [];
|
||||
this.afterAllFns = [];
|
||||
this.queueRunner = attrs.queueRunner || function() {};
|
||||
this.disabled = false;
|
||||
|
||||
this.children = [];
|
||||
@@ -2039,51 +2029,17 @@ getJasmineRequireObj().Suite = function() {
|
||||
}
|
||||
};
|
||||
|
||||
Suite.prototype.execute = function(onComplete) {
|
||||
var self = this;
|
||||
|
||||
this.onStart(this);
|
||||
|
||||
if (this.disabled) {
|
||||
complete();
|
||||
return;
|
||||
}
|
||||
|
||||
var allFns = [];
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
allFns.push(wrapChildAsAsync(this.children[i]));
|
||||
}
|
||||
|
||||
if (this.isExecutable()) {
|
||||
allFns = this.beforeAllFns.concat(allFns);
|
||||
allFns = allFns.concat(this.afterAllFns);
|
||||
}
|
||||
|
||||
this.queueRunner({
|
||||
queueableFns: allFns,
|
||||
onComplete: complete,
|
||||
userContext: this.sharedUserContext(),
|
||||
onException: function() { self.onException.apply(self, arguments); }
|
||||
});
|
||||
|
||||
function complete() {
|
||||
self.result.status = self.status();
|
||||
self.resultCallback(self.result);
|
||||
|
||||
if (onComplete) {
|
||||
onComplete();
|
||||
}
|
||||
}
|
||||
|
||||
function wrapChildAsAsync(child) {
|
||||
return { fn: function(done) { child.execute(done); } };
|
||||
}
|
||||
Suite.prototype.isExecutable = function() {
|
||||
return !this.disabled;
|
||||
};
|
||||
|
||||
Suite.prototype.isExecutable = function() {
|
||||
var runnablesExplicitlySet = this.runnablesExplictlySetGetter();
|
||||
return !runnablesExplicitlySet && hasExecutableChild(this.children);
|
||||
Suite.prototype.canBeReentered = function() {
|
||||
return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0;
|
||||
};
|
||||
|
||||
Suite.prototype.getResult = function() {
|
||||
this.result.status = this.status();
|
||||
return this.result;
|
||||
};
|
||||
|
||||
Suite.prototype.sharedUserContext = function() {
|
||||
@@ -2136,17 +2092,6 @@ getJasmineRequireObj().Suite = function() {
|
||||
return !args[0];
|
||||
}
|
||||
|
||||
function hasExecutableChild(children) {
|
||||
var foundActive = false;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
if (children[i].isExecutable()) {
|
||||
foundActive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return foundActive;
|
||||
}
|
||||
|
||||
function clone(obj) {
|
||||
var clonedObj = {};
|
||||
for (var prop in obj) {
|
||||
@@ -2188,6 +2133,214 @@ getJasmineRequireObj().Timer = function() {
|
||||
return Timer;
|
||||
};
|
||||
|
||||
getJasmineRequireObj().TreeProcessor = function() {
|
||||
function TreeProcessor(attrs) {
|
||||
var tree = attrs.tree,
|
||||
runnableIds = attrs.runnableIds,
|
||||
queueRunnerFactory = attrs.queueRunnerFactory,
|
||||
nodeStart = attrs.nodeStart || function() {},
|
||||
nodeComplete = attrs.nodeComplete || function() {},
|
||||
stats = { valid: true },
|
||||
processed = false,
|
||||
defaultMin = Infinity,
|
||||
defaultMax = 1 - Infinity;
|
||||
|
||||
this.processTree = function() {
|
||||
processNode(tree, false);
|
||||
processed = true;
|
||||
return stats;
|
||||
};
|
||||
|
||||
this.execute = function(done) {
|
||||
if (!processed) {
|
||||
this.processTree();
|
||||
}
|
||||
|
||||
if (!stats.valid) {
|
||||
throw 'invalid order';
|
||||
}
|
||||
|
||||
var childFns = wrapChildren(tree, 0);
|
||||
|
||||
queueRunnerFactory({
|
||||
queueableFns: childFns,
|
||||
onException: function() {
|
||||
tree.onException.apply(tree, arguments);
|
||||
},
|
||||
onComplete: done
|
||||
});
|
||||
};
|
||||
|
||||
function runnableIndex(id) {
|
||||
for (var i = 0; i < runnableIds.length; i++) {
|
||||
if (runnableIds[i] === id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processNode(node, parentEnabled) {
|
||||
var executableIndex = runnableIndex(node.id);
|
||||
|
||||
if (executableIndex !== undefined) {
|
||||
parentEnabled = true;
|
||||
}
|
||||
|
||||
parentEnabled = parentEnabled && node.isExecutable();
|
||||
|
||||
if (!node.children) {
|
||||
stats[node.id] = {
|
||||
executable: parentEnabled && node.isExecutable(),
|
||||
segments: [{
|
||||
index: 0,
|
||||
owner: node,
|
||||
nodes: [node],
|
||||
min: startingMin(executableIndex),
|
||||
max: startingMax(executableIndex)
|
||||
}]
|
||||
};
|
||||
} else {
|
||||
var hasExecutableChild = false;
|
||||
|
||||
for (var i = 0; i < node.children.length; i++) {
|
||||
var child = node.children[i];
|
||||
|
||||
processNode(child, parentEnabled);
|
||||
|
||||
if (!stats.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
var childStats = stats[child.id];
|
||||
|
||||
hasExecutableChild = hasExecutableChild || childStats.executable;
|
||||
}
|
||||
|
||||
stats[node.id] = {
|
||||
executable: hasExecutableChild,
|
||||
};
|
||||
|
||||
segmentChildren(node, stats[node.id], executableIndex);
|
||||
|
||||
if (!node.canBeReentered() && stats[node.id].segments.length > 1) {
|
||||
stats = { valid: false };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startingMin(executableIndex) {
|
||||
return executableIndex === undefined ? defaultMin : executableIndex;
|
||||
}
|
||||
|
||||
function startingMax(executableIndex) {
|
||||
return executableIndex === undefined ? defaultMax : executableIndex;
|
||||
}
|
||||
|
||||
function segmentChildren(node, nodeStats, executableIndex) {
|
||||
var currentSegment = { index: 0, owner: node, nodes: [], min: startingMin(executableIndex), max: startingMax(executableIndex) },
|
||||
result = [currentSegment],
|
||||
lastMax = defaultMax,
|
||||
orderedChildSegments = orderChildSegments(node.children);
|
||||
|
||||
for (var i = 0; i < orderedChildSegments.length; i++) {
|
||||
var childSegment = orderedChildSegments[i],
|
||||
maxIndex = childSegment.max,
|
||||
minIndex = childSegment.min;
|
||||
|
||||
if (lastMax !== defaultMax && minIndex !== defaultMin && lastMax < minIndex - 1) {
|
||||
currentSegment = { index: result.length, owner: node, nodes: [], min: defaultMin, max: defaultMin };
|
||||
result.push(currentSegment);
|
||||
}
|
||||
|
||||
currentSegment.nodes.push(childSegment);
|
||||
currentSegment.min = Math.min(currentSegment.min, minIndex);
|
||||
currentSegment.max = Math.max(currentSegment.max, maxIndex);
|
||||
lastMax = maxIndex;
|
||||
}
|
||||
|
||||
nodeStats.segments = result;
|
||||
}
|
||||
|
||||
function orderChildSegments(array) {
|
||||
var result = [];
|
||||
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
var child = array[i],
|
||||
segments = stats[child.id].segments;
|
||||
|
||||
for (var j = 0; j < segments.length; j++) {
|
||||
result.push(segments[j]);
|
||||
}
|
||||
}
|
||||
|
||||
result.sort(function(a, b) {
|
||||
if (a.min === null) {
|
||||
return b.min === null ? 0 : 1;
|
||||
}
|
||||
|
||||
if (b.min === null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return a.min - b.min;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function executeNode(node, segmentNumber) {
|
||||
if (node.children) {
|
||||
return {
|
||||
fn: function(done) {
|
||||
nodeStart(node);
|
||||
|
||||
queueRunnerFactory({
|
||||
onComplete: function() {
|
||||
nodeComplete(node, node.getResult());
|
||||
done();
|
||||
},
|
||||
queueableFns: wrapChildren(node, segmentNumber),
|
||||
userContext: node.sharedUserContext(),
|
||||
onException: function() {
|
||||
node.onException.apply(node, arguments);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
fn: function(done) { node.execute(done, stats[node.id].executable); }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function minValue(array) {
|
||||
return Math.min.apply(null, array);
|
||||
}
|
||||
|
||||
function maxValue(array) {
|
||||
return Math.max.apply(null, array);
|
||||
}
|
||||
|
||||
function wrapChildren(node, segmentNumber) {
|
||||
var result = [],
|
||||
segmentChildren = stats[node.id].segments[segmentNumber].nodes;
|
||||
|
||||
for (var i = 0; i < segmentChildren.length; i++) {
|
||||
result.push(executeNode(segmentChildren[i].owner, segmentChildren[i].index));
|
||||
}
|
||||
|
||||
if (!stats[node.id].executable) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return node.beforeAllFns.concat(result).concat(node.afterAllFns);
|
||||
}
|
||||
}
|
||||
|
||||
return TreeProcessor;
|
||||
};
|
||||
|
||||
getJasmineRequireObj().Any = function() {
|
||||
|
||||
function Any(expectedObject) {
|
||||
|
||||
@@ -148,6 +148,29 @@ describe("Spec", function() {
|
||||
expect(resultCallback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("can be disabled at execution time by a parent", function() {
|
||||
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
|
||||
startCallback = jasmine.createSpy('startCallback'),
|
||||
specBody = jasmine.createSpy('specBody'),
|
||||
resultCallback = jasmine.createSpy('resultCallback'),
|
||||
spec = new j$.Spec({
|
||||
onStart:startCallback,
|
||||
queueableFn: { fn: specBody },
|
||||
resultCallback: resultCallback,
|
||||
queueRunnerFactory: fakeQueueRunner
|
||||
});
|
||||
|
||||
spec.execute(undefined, false);
|
||||
|
||||
expect(spec.result.status).toBe('disabled');
|
||||
|
||||
expect(fakeQueueRunner).not.toHaveBeenCalled();
|
||||
expect(specBody).not.toHaveBeenCalled();
|
||||
|
||||
expect(startCallback).toHaveBeenCalled();
|
||||
expect(resultCallback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("can be marked pending, but still calls callbacks when executed", function() {
|
||||
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
|
||||
startCallback = jasmine.createSpy('startCallback'),
|
||||
@@ -244,7 +267,7 @@ describe("Spec", function() {
|
||||
expect(specNameSpy.calls.mostRecent().args[0].id).toEqual(spec.id);
|
||||
});
|
||||
|
||||
describe("when a spec is marked pending during execution", function() {
|
||||
describe("when a spec is marked pending during execution", function() {
|
||||
it("should mark the spec as pending", function() {
|
||||
var fakeQueueRunner = function(opts) {
|
||||
opts.onException(new Error(j$.Spec.pendingSpecExceptionMessage));
|
||||
@@ -279,4 +302,50 @@ describe("Spec", function() {
|
||||
expect(spec.result.pendingReason).toEqual('custom message');
|
||||
});
|
||||
});
|
||||
|
||||
it("retrieves a result with updated status", function() {
|
||||
var spec = new j$.Spec({ queueableFn: { fn: function() {} } });
|
||||
|
||||
expect(spec.getResult().status).toBe('passed');
|
||||
});
|
||||
|
||||
it("retrives a result with disabled status", function() {
|
||||
var spec = new j$.Spec({ queueableFn: { fn: function() {} } });
|
||||
spec.disable();
|
||||
|
||||
expect(spec.getResult().status).toBe('disabled');
|
||||
});
|
||||
|
||||
it("retrives a result with pending status", function() {
|
||||
var spec = new j$.Spec({ queueableFn: { fn: function() {} } });
|
||||
spec.pend();
|
||||
|
||||
expect(spec.getResult().status).toBe('pending');
|
||||
});
|
||||
|
||||
it("should not be executable when disabled", function() {
|
||||
var spec = new j$.Spec({
|
||||
queueableFn: { fn: function() {} }
|
||||
});
|
||||
spec.disable();
|
||||
|
||||
expect(spec.isExecutable()).toBe(false);
|
||||
});
|
||||
|
||||
it("should not be executable when pending", function() {
|
||||
var spec = new j$.Spec({
|
||||
queueableFn: { fn: function() {} }
|
||||
});
|
||||
spec.pend();
|
||||
|
||||
expect(spec.isExecutable()).toBe(false);
|
||||
});
|
||||
|
||||
it("should be executable when not disabled or pending", function() {
|
||||
var spec = new j$.Spec({
|
||||
queueableFn: { fn: function() {} }
|
||||
});
|
||||
|
||||
expect(spec.isExecutable()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -52,31 +52,6 @@ describe("Suite", function() {
|
||||
expect(suite.beforeFns).toEqual([innerBefore, outerBefore]);
|
||||
});
|
||||
|
||||
it("runs beforeAll functions in order of needed execution", function() {
|
||||
var env = new j$.Env(),
|
||||
fakeQueueRunner = jasmine.createSpy('fake queue runner'),
|
||||
suite = new j$.Suite({
|
||||
env: env,
|
||||
description: "I am a suite",
|
||||
queueRunner: fakeQueueRunner
|
||||
}),
|
||||
firstBefore = jasmine.createSpy('outerBeforeAll'),
|
||||
lastBefore = jasmine.createSpy('insideBeforeAll'),
|
||||
fakeIt = {execute: jasmine.createSpy('it'), isExecutable: function() { return true; } };
|
||||
|
||||
suite.beforeAll(firstBefore);
|
||||
suite.beforeAll(lastBefore);
|
||||
suite.addChild(fakeIt);
|
||||
|
||||
suite.execute();
|
||||
var suiteFns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
|
||||
suiteFns[0]();
|
||||
expect(firstBefore).toHaveBeenCalled();
|
||||
suiteFns[1]();
|
||||
expect(lastBefore).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("adds after functions in order of needed execution", function() {
|
||||
var env = new j$.Env(),
|
||||
suite = new j$.Suite({
|
||||
@@ -92,244 +67,6 @@ describe("Suite", function() {
|
||||
expect(suite.afterFns).toEqual([innerAfter, outerAfter]);
|
||||
});
|
||||
|
||||
it("runs afterAll functions in order of needed execution", function() {
|
||||
var env = new j$.Env(),
|
||||
fakeQueueRunner = jasmine.createSpy('fake queue runner'),
|
||||
suite = new j$.Suite({
|
||||
env: env,
|
||||
description: "I am a suite",
|
||||
queueRunner: fakeQueueRunner
|
||||
}),
|
||||
firstAfter = jasmine.createSpy('outerAfterAll'),
|
||||
lastAfter = jasmine.createSpy('insideAfterAll'),
|
||||
fakeIt = {execute: jasmine.createSpy('it'), isExecutable: function() { return true; } };
|
||||
|
||||
suite.afterAll(firstAfter);
|
||||
suite.afterAll(lastAfter);
|
||||
suite.addChild(fakeIt);
|
||||
|
||||
suite.execute();
|
||||
var suiteFns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
|
||||
suiteFns[1]();
|
||||
expect(firstAfter).toHaveBeenCalled();
|
||||
suiteFns[2]();
|
||||
expect(lastAfter).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not run *All functions if runnables are explicitly set", function(){
|
||||
var env = new j$.Env(),
|
||||
fakeQueueRunner = jasmine.createSpy('fake queue runner'),
|
||||
suite = new j$.Suite({
|
||||
env: env,
|
||||
description: "I am a suite",
|
||||
queueRunner: fakeQueueRunner,
|
||||
runnablesExplictlySetGetter: function(){return true;}
|
||||
}),
|
||||
beforeAll = jasmine.createSpy('beforeAll'),
|
||||
afterAll = jasmine.createSpy('afterAll'),
|
||||
fakeIt = {execute: jasmine.createSpy('it'), isExecutable: function() { return true; } };
|
||||
|
||||
suite.beforeAll(beforeAll);
|
||||
suite.afterAll(afterAll);
|
||||
suite.addChild(fakeIt);
|
||||
|
||||
suite.execute();
|
||||
var suiteFns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
|
||||
expect(suite.isExecutable()).toBeFalsy();
|
||||
expect(suiteFns.length).toEqual(1);
|
||||
expect(beforeAll).not.toHaveBeenCalled();
|
||||
expect(afterAll).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("can be disabled, but still calls callbacks", function() {
|
||||
var env = new j$.Env(),
|
||||
fakeQueueRunner = jasmine.createSpy('fake queue runner'),
|
||||
onStart = jasmine.createSpy('onStart'),
|
||||
resultCallback = jasmine.createSpy('resultCallback'),
|
||||
onComplete = jasmine.createSpy('onComplete'),
|
||||
suite = new j$.Suite({
|
||||
env: env,
|
||||
description: "with a child suite",
|
||||
onStart: onStart,
|
||||
resultCallback: resultCallback,
|
||||
queueRunner: fakeQueueRunner
|
||||
});
|
||||
|
||||
suite.disable();
|
||||
|
||||
expect(suite.disabled).toBe(true);
|
||||
|
||||
suite.execute(onComplete);
|
||||
|
||||
expect(fakeQueueRunner).not.toHaveBeenCalled();
|
||||
expect(onStart).toHaveBeenCalled();
|
||||
expect(resultCallback).toHaveBeenCalled();
|
||||
expect(onComplete).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("delegates execution of its specs, suites, beforeAlls, and afterAlls", function() {
|
||||
var env = new j$.Env(),
|
||||
parentSuiteDone = jasmine.createSpy('parent suite done'),
|
||||
fakeQueueRunnerForParent = jasmine.createSpy('fake parent queue runner'),
|
||||
parentSuite = new j$.Suite({
|
||||
env: env,
|
||||
description: "I am a parent suite",
|
||||
queueRunner: fakeQueueRunnerForParent
|
||||
}),
|
||||
fakeQueueRunner = jasmine.createSpy('fake queue runner'),
|
||||
suite = new j$.Suite({
|
||||
env: env,
|
||||
description: "with a child suite",
|
||||
queueRunner: fakeQueueRunner
|
||||
}),
|
||||
fakeSpec1 = {
|
||||
execute: jasmine.createSpy('fakeSpec1'),
|
||||
isExecutable: function() { return true; }
|
||||
},
|
||||
beforeAllFn = { fn: jasmine.createSpy('beforeAll') },
|
||||
afterAllFn = { fn: jasmine.createSpy('afterAll') };
|
||||
|
||||
spyOn(suite, "execute");
|
||||
|
||||
parentSuite.addChild(fakeSpec1);
|
||||
parentSuite.addChild(suite);
|
||||
parentSuite.beforeAll(beforeAllFn);
|
||||
parentSuite.afterAll(afterAllFn);
|
||||
|
||||
parentSuite.execute(parentSuiteDone);
|
||||
|
||||
var parentSuiteFns = fakeQueueRunnerForParent.calls.mostRecent().args[0].queueableFns;
|
||||
|
||||
parentSuiteFns[0].fn();
|
||||
expect(beforeAllFn.fn).toHaveBeenCalled();
|
||||
parentSuiteFns[1].fn();
|
||||
expect(fakeSpec1.execute).toHaveBeenCalled();
|
||||
parentSuiteFns[2].fn();
|
||||
expect(suite.execute).toHaveBeenCalled();
|
||||
parentSuiteFns[3].fn();
|
||||
expect(afterAllFn.fn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not run beforeAll or afterAll if there are no executable child specs", function() {
|
||||
var env = new j$.Env(),
|
||||
fakeQueueRunnerForParent = jasmine.createSpy('fake parent queue runner'),
|
||||
fakeQueueRunnerForChild = jasmine.createSpy('fake child queue runner'),
|
||||
parentSuite = new j$.Suite({
|
||||
env: env,
|
||||
description: "I am a suite",
|
||||
queueRunner: fakeQueueRunnerForParent
|
||||
}),
|
||||
childSuite = new j$.Suite({
|
||||
env: env,
|
||||
description: "I am a suite",
|
||||
queueRunner: fakeQueueRunnerForChild,
|
||||
parentSuite: parentSuite
|
||||
}),
|
||||
beforeAllFn = jasmine.createSpy('beforeAll'),
|
||||
afterAllFn = jasmine.createSpy('afterAll');
|
||||
|
||||
parentSuite.addChild(childSuite);
|
||||
parentSuite.beforeAll(beforeAllFn);
|
||||
parentSuite.afterAll(afterAllFn);
|
||||
|
||||
parentSuite.execute();
|
||||
expect(fakeQueueRunnerForParent).toHaveBeenCalledWith(jasmine.objectContaining({
|
||||
queueableFns: [{ fn: jasmine.any(Function) }]
|
||||
}));
|
||||
});
|
||||
|
||||
it("calls a provided onStart callback when starting", function() {
|
||||
var env = new j$.Env(),
|
||||
suiteStarted = jasmine.createSpy('suiteStarted'),
|
||||
fakeQueueRunner = function(attrs) { attrs.onComplete(); },
|
||||
suite = new j$.Suite({
|
||||
env: env,
|
||||
description: "with a child suite",
|
||||
onStart: suiteStarted,
|
||||
queueRunner: fakeQueueRunner
|
||||
}),
|
||||
fakeSpec1 = {
|
||||
execute: jasmine.createSpy('fakeSpec1'),
|
||||
isExecutable: function() { return true; }
|
||||
};
|
||||
|
||||
suite.execute();
|
||||
|
||||
expect(suiteStarted).toHaveBeenCalledWith(suite);
|
||||
});
|
||||
|
||||
it("calls a provided onComplete callback when done", function() {
|
||||
var env = new j$.Env(),
|
||||
suiteCompleted = jasmine.createSpy('parent suite done'),
|
||||
fakeQueueRunner = function(attrs) { attrs.onComplete(); },
|
||||
suite = new j$.Suite({
|
||||
env: env,
|
||||
description: "with a child suite",
|
||||
queueRunner: fakeQueueRunner
|
||||
}),
|
||||
fakeSpec1 = {
|
||||
execute: jasmine.createSpy('fakeSpec1')
|
||||
};
|
||||
|
||||
suite.execute(suiteCompleted);
|
||||
|
||||
expect(suiteCompleted).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls a provided result callback when done", function() {
|
||||
var env = new j$.Env(),
|
||||
suiteResultsCallback = jasmine.createSpy('suite result callback'),
|
||||
fakeQueueRunner = function(attrs) { attrs.onComplete(); },
|
||||
suite = new j$.Suite({
|
||||
env: env,
|
||||
description: "with a child suite",
|
||||
queueRunner: fakeQueueRunner,
|
||||
resultCallback: suiteResultsCallback
|
||||
}),
|
||||
fakeSpec1 = {
|
||||
execute: jasmine.createSpy('fakeSpec1')
|
||||
};
|
||||
|
||||
suite.execute();
|
||||
|
||||
expect(suiteResultsCallback).toHaveBeenCalledWith({
|
||||
id: suite.id,
|
||||
status: 'finished',
|
||||
description: "with a child suite",
|
||||
fullName: "with a child suite",
|
||||
failedExpectations: []
|
||||
});
|
||||
});
|
||||
|
||||
it("calls a provided result callback with status being disabled when disabled and done", function() {
|
||||
var env = new j$.Env(),
|
||||
suiteResultsCallback = jasmine.createSpy('suite result callback'),
|
||||
fakeQueueRunner = function(attrs) { attrs.onComplete(); },
|
||||
suite = new j$.Suite({
|
||||
env: env,
|
||||
description: "with a child suite",
|
||||
queueRunner: fakeQueueRunner,
|
||||
resultCallback: suiteResultsCallback
|
||||
}),
|
||||
fakeSpec1 = {
|
||||
execute: jasmine.createSpy('fakeSpec1')
|
||||
};
|
||||
|
||||
suite.disable();
|
||||
|
||||
suite.execute();
|
||||
|
||||
expect(suiteResultsCallback).toHaveBeenCalledWith({
|
||||
id: suite.id,
|
||||
status: 'disabled',
|
||||
description: "with a child suite",
|
||||
fullName: "with a child suite",
|
||||
failedExpectations: []
|
||||
});
|
||||
});
|
||||
|
||||
it('has a status of failed if any afterAll expectations have failed', function() {
|
||||
var suite = new j$.Suite({
|
||||
expectationResultFactory: function() { return 'hi'; }
|
||||
@@ -339,4 +76,30 @@ describe("Suite", function() {
|
||||
suite.addExpectationResult(false);
|
||||
expect(suite.status()).toBe('failed');
|
||||
});
|
||||
|
||||
it("retrieves a result with updated status", function() {
|
||||
var suite = new j$.Suite({});
|
||||
|
||||
expect(suite.getResult().status).toBe('finished');
|
||||
});
|
||||
|
||||
it("retrives a result with disabled status", function() {
|
||||
var suite = new j$.Suite({});
|
||||
suite.disable();
|
||||
|
||||
expect(suite.getResult().status).toBe('disabled');
|
||||
});
|
||||
|
||||
it("is executable if not disabled", function() {
|
||||
var suite = new j$.Suite({});
|
||||
|
||||
expect(suite.isExecutable()).toBe(true);
|
||||
});
|
||||
|
||||
it("is not executable if disabled", function() {
|
||||
var suite = new j$.Suite({});
|
||||
suite.disable();
|
||||
|
||||
expect(suite.isExecutable()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
565
spec/core/TreeProcessorSpec.js
Normal file
565
spec/core/TreeProcessorSpec.js
Normal file
@@ -0,0 +1,565 @@
|
||||
describe("TreeProcessor", function() {
|
||||
var nodeNumber = 0, leafNumber = 0;
|
||||
|
||||
function Node(attrs) {
|
||||
attrs = attrs || {};
|
||||
this.id = 'node' + nodeNumber++;
|
||||
this.children = attrs.children || [];
|
||||
this.canBeReentered = function() {
|
||||
return !attrs.noReenter;
|
||||
};
|
||||
this.isExecutable = function() {
|
||||
return attrs.executable !== false;
|
||||
};
|
||||
this.sharedUserContext = function() {
|
||||
return attrs.userContext || {};
|
||||
};
|
||||
this.getResult = jasmine.createSpy(this.id + '#execute');
|
||||
this.beforeAllFns = attrs.beforeAllFns || [];
|
||||
this.afterAllFns = attrs.afterAllFns || [];
|
||||
}
|
||||
|
||||
function Leaf(attrs) {
|
||||
attrs = attrs || {};
|
||||
this.id = 'leaf' + leafNumber++;
|
||||
this.isExecutable = function() {
|
||||
return attrs.executable !== false;
|
||||
};
|
||||
this.execute = jasmine.createSpy(this.id + '#execute');
|
||||
}
|
||||
|
||||
it("processes a single executable leaf", function() {
|
||||
var leaf = new Leaf(),
|
||||
processor = new j$.TreeProcessor({ tree: leaf, runnableIds: [leaf.id] }),
|
||||
result = processor.processTree();
|
||||
|
||||
expect(result.valid).toBe(true);
|
||||
|
||||
expect(result[leaf.id]).toEqual({
|
||||
executable: true,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
});
|
||||
|
||||
it("processes a single non-executable leaf", function() {
|
||||
var leaf = new Leaf({ executable: false }),
|
||||
processor = new j$.TreeProcessor({ tree: leaf, runnableIds: [leaf.id] }),
|
||||
result = processor.processTree();
|
||||
|
||||
expect(result.valid).toBe(true);
|
||||
|
||||
expect(result[leaf.id]).toEqual({
|
||||
executable: false,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
});
|
||||
|
||||
it("processes a single non-specified leaf", function() {
|
||||
var leaf = new Leaf(),
|
||||
processor = new j$.TreeProcessor({ tree: leaf, runnableIds: [] }),
|
||||
result = processor.processTree();
|
||||
|
||||
expect(result.valid).toBe(true);
|
||||
|
||||
expect(result[leaf.id]).toEqual({
|
||||
executable: false,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
});
|
||||
|
||||
it("processes a tree with a single leaf with the root specified", function() {
|
||||
var leaf = new Leaf(),
|
||||
parent = new Node({ children: [leaf] }),
|
||||
processor = new j$.TreeProcessor({ tree: parent, runnableIds: [parent.id] }),
|
||||
result = processor.processTree();
|
||||
|
||||
expect(result.valid).toBe(true);
|
||||
|
||||
expect(result[parent.id]).toEqual({
|
||||
executable: true,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
|
||||
expect(result[leaf.id]).toEqual({
|
||||
executable: true,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
});
|
||||
|
||||
it("processes a tree with a single non-executable leaf, with the root specified", function() {
|
||||
var leaf = new Leaf({ executable: false }),
|
||||
parent = new Node({ children: [leaf] }),
|
||||
processor = new j$.TreeProcessor({ tree: parent, runnableIds: [parent.id] }),
|
||||
result = processor.processTree();
|
||||
|
||||
expect(result.valid).toBe(true);
|
||||
|
||||
expect(result[parent.id]).toEqual({
|
||||
executable: false,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
|
||||
expect(result[leaf.id]).toEqual({
|
||||
executable: false,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
});
|
||||
|
||||
it("processes a complicated tree with the root specified", function() {
|
||||
var nonExecutable = new Leaf({ executable: false }),
|
||||
executable = new Leaf({ executable: true }),
|
||||
parent = new Node({ children: [nonExecutable, executable] }),
|
||||
childless = new Node(),
|
||||
childOfDisabled = new Leaf({ executable: true }),
|
||||
disabledNode = new Node({ executable: false, children: [childOfDisabled] }),
|
||||
root = new Node({ children: [parent, childless, disabledNode] }),
|
||||
processor = new j$.TreeProcessor({ tree: root, runnableIds: [root.id] }),
|
||||
result = processor.processTree();
|
||||
|
||||
expect(result.valid).toBe(true);
|
||||
|
||||
expect(result[root.id]).toEqual({
|
||||
executable: true,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
|
||||
expect(result[childless.id]).toEqual({
|
||||
executable: false,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
|
||||
expect(result[nonExecutable.id]).toEqual({
|
||||
executable: false,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
|
||||
expect(result[executable.id]).toEqual({
|
||||
executable: true,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
|
||||
expect(result[parent.id]).toEqual({
|
||||
executable: true,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
|
||||
expect(result[disabledNode.id]).toEqual({
|
||||
executable: false,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
|
||||
expect(result[childOfDisabled.id]).toEqual({
|
||||
executable: false,
|
||||
segments: jasmine.any(Array)
|
||||
});
|
||||
});
|
||||
|
||||
it("marks the run order invalid if it would re-enter a node that does not allow re-entry", function() {
|
||||
var leaf1 = new Leaf(),
|
||||
leaf2 = new Leaf(),
|
||||
leaf3 = new Leaf(),
|
||||
reentered = new Node({ noReenter: true, children: [leaf1, leaf2] }),
|
||||
root = new Node({ children: [reentered, leaf3] }),
|
||||
processor = new j$.TreeProcessor({ tree: root, runnableIds: [leaf1.id, leaf3.id, leaf2.id] }),
|
||||
result = processor.processTree();
|
||||
|
||||
expect(result).toEqual({ valid: false });
|
||||
});
|
||||
|
||||
it("marks the run order valid if a node being re-entered allows re-entry", function() {
|
||||
var leaf1 = new Leaf(),
|
||||
leaf2 = new Leaf(),
|
||||
leaf3 = new Leaf(),
|
||||
reentered = new Node({ children: [leaf1, leaf2] }),
|
||||
root = new Node({ children: [reentered, leaf3] }),
|
||||
processor = new j$.TreeProcessor({ tree: root, runnableIds: [leaf1.id, leaf3.id, leaf2.id] }),
|
||||
result = processor.processTree();
|
||||
|
||||
expect(result.valid).toBe(true);
|
||||
});
|
||||
|
||||
it("marks the run order valid if a node which can't be re-entered is only entered once", function() {
|
||||
var leaf1 = new Leaf(),
|
||||
leaf2 = new Leaf(),
|
||||
leaf3 = new Leaf(),
|
||||
noReentry = new Node({ noReenter: true }),
|
||||
root = new Node({ children: [noReentry] }),
|
||||
processor = new j$.TreeProcessor({ tree: root, runnableIds: [leaf2.id, leaf1.id, leaf3.id] }),
|
||||
result = processor.processTree();
|
||||
|
||||
expect(result.valid).toBe(true);
|
||||
});
|
||||
|
||||
it("marks the run order valid if a node which can't be re-entered is run directly", function() {
|
||||
var leaf1 = new Leaf(),
|
||||
noReentry = new Node({ noReenter: true }),
|
||||
root = new Node({ children: [noReentry] }),
|
||||
processor = new j$.TreeProcessor({ tree: root, runnableIds: [root.id] }),
|
||||
result = processor.processTree();
|
||||
|
||||
expect(result.valid).toBe(true);
|
||||
});
|
||||
|
||||
it("runs a single leaf", function() {
|
||||
var leaf = new Leaf(),
|
||||
node = new Node({ children: [leaf] }),
|
||||
queueRunner = jasmine.createSpy('queueRunner'),
|
||||
processor = new j$.TreeProcessor({ tree: node, runnableIds: [leaf.id], queueRunnerFactory: queueRunner }),
|
||||
treeComplete = jasmine.createSpy('treeComplete');
|
||||
|
||||
processor.execute(treeComplete);
|
||||
|
||||
expect(queueRunner).toHaveBeenCalledWith({
|
||||
onComplete: treeComplete,
|
||||
onException: jasmine.any(Function),
|
||||
queueableFns: [{ fn: jasmine.any(Function) }]
|
||||
});
|
||||
|
||||
queueRunner.calls.mostRecent().args[0].queueableFns[0].fn('foo');
|
||||
|
||||
expect(leaf.execute).toHaveBeenCalledWith('foo', true);
|
||||
});
|
||||
|
||||
it("runs a node with no children", function() {
|
||||
var node = new Node({ userContext: { node: 'context' } }),
|
||||
root = new Node({ children: [node] }),
|
||||
nodeStart = jasmine.createSpy('nodeStart'),
|
||||
nodeComplete = jasmine.createSpy('nodeComplete'),
|
||||
queueRunner = jasmine.createSpy('queueRunner'),
|
||||
processor = new j$.TreeProcessor({
|
||||
tree: root,
|
||||
runnableIds: [node.id],
|
||||
nodeStart: nodeStart,
|
||||
nodeComplete: nodeComplete,
|
||||
queueRunnerFactory: queueRunner
|
||||
}),
|
||||
treeComplete = jasmine.createSpy('treeComplete'),
|
||||
nodeDone = jasmine.createSpy('nodeDone');
|
||||
|
||||
processor.execute(treeComplete);
|
||||
|
||||
expect(queueRunner).toHaveBeenCalledWith({
|
||||
onComplete: treeComplete,
|
||||
onException: jasmine.any(Function),
|
||||
queueableFns: [{ fn: jasmine.any(Function) }]
|
||||
});
|
||||
|
||||
queueRunner.calls.mostRecent().args[0].queueableFns[0].fn(nodeDone);
|
||||
|
||||
expect(nodeStart).toHaveBeenCalledWith(node);
|
||||
expect(queueRunner).toHaveBeenCalledWith({
|
||||
onComplete: jasmine.any(Function),
|
||||
queueableFns: [],
|
||||
userContext: { node: 'context' },
|
||||
onException: jasmine.any(Function)
|
||||
});
|
||||
|
||||
node.getResult.and.returnValue({ my: 'result' });
|
||||
|
||||
queueRunner.calls.mostRecent().args[0].onComplete();
|
||||
expect(nodeComplete).toHaveBeenCalledWith(node, { my: 'result' });
|
||||
expect(nodeDone).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("runs a node with children", function() {
|
||||
var leaf1 = new Leaf(),
|
||||
leaf2 = new Leaf(),
|
||||
node = new Node({ children: [leaf1, leaf2] }),
|
||||
root = new Node({ children: [node] }),
|
||||
queueRunner = jasmine.createSpy('queueRunner'),
|
||||
processor = new j$.TreeProcessor({
|
||||
tree: root,
|
||||
runnableIds: [node.id],
|
||||
queueRunnerFactory: queueRunner
|
||||
}),
|
||||
treeComplete = jasmine.createSpy('treeComplete'),
|
||||
nodeDone = jasmine.createSpy('nodeDone');
|
||||
|
||||
processor.execute(treeComplete);
|
||||
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn(nodeDone);
|
||||
|
||||
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
expect(queueableFns.length).toBe(2);
|
||||
|
||||
queueableFns[0].fn('foo');
|
||||
expect(leaf1.execute).toHaveBeenCalledWith('foo', true);
|
||||
|
||||
queueableFns[1].fn('bar');
|
||||
expect(leaf2.execute).toHaveBeenCalledWith('bar', true);
|
||||
});
|
||||
|
||||
it("runs a disabled node", function() {
|
||||
var leaf1 = new Leaf(),
|
||||
node = new Node({ children: [leaf1], executable: false }),
|
||||
root = new Node({ children: [node] }),
|
||||
queueRunner = jasmine.createSpy('queueRunner'),
|
||||
nodeStart = jasmine.createSpy('nodeStart'),
|
||||
nodeComplete = jasmine.createSpy('nodeComplete'),
|
||||
processor = new j$.TreeProcessor({
|
||||
tree: root,
|
||||
runnableIds: [node.id],
|
||||
queueRunnerFactory: queueRunner,
|
||||
nodeStart: nodeStart,
|
||||
nodeComplete: nodeComplete
|
||||
}),
|
||||
treeComplete = jasmine.createSpy('treeComplete'),
|
||||
nodeDone = jasmine.createSpy('nodeDone');
|
||||
|
||||
processor.execute(treeComplete);
|
||||
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn(nodeDone);
|
||||
|
||||
expect(nodeStart).toHaveBeenCalledWith(node);
|
||||
|
||||
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
expect(queueableFns.length).toBe(1);
|
||||
|
||||
queueableFns[0].fn('foo');
|
||||
expect(leaf1.execute).toHaveBeenCalledWith('foo', false);
|
||||
|
||||
node.getResult.and.returnValue({ im: 'disabled' });
|
||||
|
||||
queueRunner.calls.mostRecent().args[0].onComplete();
|
||||
expect(nodeComplete).toHaveBeenCalledWith(node, { im: 'disabled' });
|
||||
});
|
||||
|
||||
it("runs beforeAlls for a node with children", function() {
|
||||
var leaf = new Leaf(),
|
||||
node = new Node({
|
||||
children: [leaf],
|
||||
beforeAllFns: ['beforeAll1', 'beforeAll2']
|
||||
}),
|
||||
root = new Node({ children: [node] }),
|
||||
queueRunner = jasmine.createSpy('queueRunner'),
|
||||
processor = new j$.TreeProcessor({
|
||||
tree: root,
|
||||
runnableIds: [node.id],
|
||||
queueRunnerFactory: queueRunner
|
||||
}),
|
||||
treeComplete = jasmine.createSpy('treeComplete'),
|
||||
nodeDone = jasmine.createSpy('nodeDone');
|
||||
|
||||
processor.execute(treeComplete);
|
||||
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn(nodeDone);
|
||||
|
||||
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
|
||||
expect(queueableFns).toEqual(['beforeAll1', 'beforeAll2', { fn: jasmine.any(Function) }]);
|
||||
});
|
||||
|
||||
it("runs afterAlls for a node with children", function() {
|
||||
var leaf = new Leaf(),
|
||||
node = new Node({
|
||||
children: [leaf],
|
||||
afterAllFns: ['afterAll1', 'afterAll2']
|
||||
}),
|
||||
root = new Node({ children: [node] }),
|
||||
queueRunner = jasmine.createSpy('queueRunner'),
|
||||
processor = new j$.TreeProcessor({
|
||||
tree: root,
|
||||
runnableIds: [node.id],
|
||||
queueRunnerFactory: queueRunner
|
||||
}),
|
||||
treeComplete = jasmine.createSpy('treeComplete'),
|
||||
nodeDone = jasmine.createSpy('nodeDone');
|
||||
|
||||
processor.execute(treeComplete);
|
||||
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn(nodeDone);
|
||||
|
||||
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
|
||||
expect(queueableFns).toEqual([{ fn: jasmine.any(Function) }, 'afterAll1', 'afterAll2']);
|
||||
});
|
||||
|
||||
it("does not run beforeAlls or afterAlls for a node with no children", function() {
|
||||
var node = new Node({
|
||||
beforeAllFns: ['before'],
|
||||
afterAllFns: ['after']
|
||||
}),
|
||||
root = new Node({ children: [node] }),
|
||||
queueRunner = jasmine.createSpy('queueRunner'),
|
||||
processor = new j$.TreeProcessor({
|
||||
tree: root,
|
||||
runnableIds: [node.id],
|
||||
queueRunnerFactory: queueRunner
|
||||
}),
|
||||
treeComplete = jasmine.createSpy('treeComplete'),
|
||||
nodeDone = jasmine.createSpy('nodeDone');
|
||||
|
||||
processor.execute(treeComplete);
|
||||
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn(nodeDone);
|
||||
|
||||
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
|
||||
expect(queueableFns).toEqual([]);
|
||||
});
|
||||
|
||||
it("does not run beforeAlls or afterAlls for a disabled node", function() {
|
||||
var leaf = new Leaf(),
|
||||
node = new Node({
|
||||
children: [leaf],
|
||||
beforeAllFns: ['before'],
|
||||
afterAllFns: ['after'],
|
||||
executable: false
|
||||
}),
|
||||
root = new Node({ children: [node] }),
|
||||
queueRunner = jasmine.createSpy('queueRunner'),
|
||||
processor = new j$.TreeProcessor({
|
||||
tree: root,
|
||||
runnableIds: [node.id],
|
||||
queueRunnerFactory: queueRunner
|
||||
}),
|
||||
treeComplete = jasmine.createSpy('treeComplete'),
|
||||
nodeDone = jasmine.createSpy('nodeDone');
|
||||
|
||||
processor.execute(treeComplete);
|
||||
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn(nodeDone);
|
||||
|
||||
queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
|
||||
expect(queueableFns).toEqual([{ fn: jasmine.any(Function) }]);
|
||||
});
|
||||
|
||||
it("runs leaves in the order specified", function() {
|
||||
var leaf1 = new Leaf(),
|
||||
leaf2 = new Leaf(),
|
||||
root = new Node({ children: [leaf1, leaf2] }),
|
||||
queueRunner = jasmine.createSpy('queueRunner'),
|
||||
processor = new j$.TreeProcessor({
|
||||
tree: root,
|
||||
runnableIds: [leaf2.id, leaf1.id],
|
||||
queueRunnerFactory: queueRunner
|
||||
}),
|
||||
treeComplete = jasmine.createSpy('treeComplete');
|
||||
|
||||
processor.execute(treeComplete);
|
||||
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn();
|
||||
|
||||
expect(leaf1.execute).not.toHaveBeenCalled();
|
||||
expect(leaf2.execute).toHaveBeenCalled();
|
||||
|
||||
queueableFns[1].fn();
|
||||
|
||||
expect(leaf1.execute).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("runs specified leaves before non-specified leaves", function() {
|
||||
var specified = new Leaf(),
|
||||
nonSpecified = new Leaf(),
|
||||
root = new Node({ children: [nonSpecified, specified] }),
|
||||
queueRunner = jasmine.createSpy('queueRunner'),
|
||||
processor = new j$.TreeProcessor({
|
||||
tree: root,
|
||||
runnableIds: [specified.id],
|
||||
queueRunnerFactory: queueRunner
|
||||
}),
|
||||
treeComplete = jasmine.createSpy('treeComplete');
|
||||
|
||||
processor.execute(treeComplete);
|
||||
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn();
|
||||
|
||||
expect(nonSpecified.execute).not.toHaveBeenCalled();
|
||||
expect(specified.execute).toHaveBeenCalledWith(undefined, true);
|
||||
|
||||
queueableFns[1].fn();
|
||||
|
||||
expect(nonSpecified.execute).toHaveBeenCalledWith(undefined, false);
|
||||
});
|
||||
|
||||
it("runs nodes and leaves with a specified order", function() {
|
||||
var specifiedLeaf = new Leaf(),
|
||||
childLeaf = new Leaf(),
|
||||
specifiedNode = new Node({ children: [childLeaf] }),
|
||||
root = new Node({ children: [specifiedLeaf, specifiedNode] }),
|
||||
queueRunner = jasmine.createSpy('queueRunner'),
|
||||
processor = new j$.TreeProcessor({
|
||||
tree: root,
|
||||
runnableIds: [specifiedNode.id, specifiedLeaf.id],
|
||||
queueRunnerFactory: queueRunner
|
||||
});
|
||||
|
||||
processor.execute();
|
||||
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
queueableFns[0].fn();
|
||||
|
||||
expect(specifiedLeaf.execute).not.toHaveBeenCalled();
|
||||
var nodeQueueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
nodeQueueableFns[0].fn();
|
||||
|
||||
expect(childLeaf.execute).toHaveBeenCalled();
|
||||
|
||||
queueableFns[1].fn();
|
||||
|
||||
expect(specifiedLeaf.execute).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("runs a node twice if the order specified leaves and re-enters it", function() {
|
||||
var leaf1 = new Leaf(),
|
||||
leaf2 = new Leaf(),
|
||||
leaf3 = new Leaf(),
|
||||
reentered = new Node({ children: [leaf1, leaf2] }),
|
||||
root = new Node({ children: [reentered, leaf3] }),
|
||||
queueRunner = jasmine.createSpy('queueRunner'),
|
||||
processor = new j$.TreeProcessor({
|
||||
tree: root,
|
||||
runnableIds: [leaf1.id, leaf3.id, leaf2.id],
|
||||
queueRunnerFactory: queueRunner
|
||||
});
|
||||
|
||||
processor.execute();
|
||||
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
expect(queueableFns.length).toBe(3);
|
||||
|
||||
queueableFns[0].fn();
|
||||
expect(queueRunner.calls.mostRecent().args[0].queueableFns.length).toBe(1);
|
||||
queueRunner.calls.mostRecent().args[0].queueableFns[0].fn();
|
||||
expect(leaf1.execute).toHaveBeenCalled();
|
||||
|
||||
queueableFns[1].fn();
|
||||
expect(leaf3.execute).toHaveBeenCalled();
|
||||
|
||||
queueableFns[2].fn();
|
||||
expect(queueRunner.calls.count()).toBe(3);
|
||||
expect(queueRunner.calls.mostRecent().args[0].queueableFns.length).toBe(1);
|
||||
queueRunner.calls.mostRecent().args[0].queueableFns[0].fn();
|
||||
expect(leaf2.execute).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("runs nodes in the order they were declared", function() {
|
||||
var leaf1 = new Leaf(),
|
||||
leaf2 = new Leaf(),
|
||||
leaf3 = new Leaf(),
|
||||
parent = new Node({ children: [leaf2, leaf3] }),
|
||||
root = new Node({ children: [leaf1, parent] }),
|
||||
queueRunner = jasmine.createSpy('queueRunner'),
|
||||
processor = new j$.TreeProcessor({
|
||||
tree: root,
|
||||
runnableIds: [root.id],
|
||||
queueRunnerFactory: queueRunner
|
||||
});
|
||||
|
||||
processor.execute();
|
||||
var queueableFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
expect(queueableFns.length).toBe(2);
|
||||
|
||||
queueableFns[0].fn();
|
||||
expect(leaf1.execute).toHaveBeenCalled();
|
||||
|
||||
queueableFns[1].fn();
|
||||
|
||||
var childFns = queueRunner.calls.mostRecent().args[0].queueableFns;
|
||||
expect(childFns.length).toBe(2);
|
||||
childFns[0].fn();
|
||||
expect(leaf2.execute).toHaveBeenCalled();
|
||||
|
||||
childFns[1].fn();
|
||||
expect(leaf3.execute).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -612,8 +612,6 @@ describe("Env integration", function() {
|
||||
expect(calls).toEqual([
|
||||
"before",
|
||||
"first spec",
|
||||
"after",
|
||||
"before",
|
||||
"second spec",
|
||||
"after"
|
||||
]);
|
||||
@@ -1208,7 +1206,7 @@ describe("Env integration", function() {
|
||||
totalSpecsDefined: 1
|
||||
});
|
||||
|
||||
expect(reporter.specDone).not.toHaveBeenCalled();
|
||||
expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({ status: 'disabled' }));
|
||||
expect(reporter.suiteDone.calls.count()).toBe(3);
|
||||
|
||||
done();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
describe("jasmine spec running", function () {
|
||||
var env;
|
||||
var fakeTimer;
|
||||
|
||||
beforeEach(function() {
|
||||
env = new j$.Env();
|
||||
@@ -61,13 +60,17 @@ describe("jasmine spec running", function () {
|
||||
expect(bar).toEqual(0);
|
||||
expect(baz).toEqual(0);
|
||||
expect(quux).toEqual(0);
|
||||
nested.execute(function() {
|
||||
var assertions = function() {
|
||||
expect(foo).toEqual(1);
|
||||
expect(bar).toEqual(1);
|
||||
expect(baz).toEqual(1);
|
||||
expect(quux).toEqual(1);
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
env.addReporter({ jasmineDone: assertions });
|
||||
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it("should permit nested describes", function(done) {
|
||||
@@ -289,7 +292,7 @@ describe("jasmine spec running", function () {
|
||||
env.execute();
|
||||
});
|
||||
|
||||
it('should run beforeAlls and afterAlls as beforeEachs and afterEachs in the order declared when runnablesToRun is provided', function(done) {
|
||||
it('should run beforeAlls and afterAlls in the order declared when runnablesToRun is provided', function(done) {
|
||||
var actions = [],
|
||||
spec,
|
||||
spec2;
|
||||
@@ -342,17 +345,13 @@ describe("jasmine spec running", function () {
|
||||
"inner beforeAll",
|
||||
"runner beforeEach",
|
||||
"inner beforeEach",
|
||||
"it",
|
||||
"it2",
|
||||
"inner afterEach",
|
||||
"runner afterEach",
|
||||
"inner afterAll",
|
||||
"runner afterAll",
|
||||
|
||||
"runner beforeAll",
|
||||
"inner beforeAll",
|
||||
"runner beforeEach",
|
||||
"inner beforeEach",
|
||||
"it2",
|
||||
"it",
|
||||
"inner afterEach",
|
||||
"runner afterEach",
|
||||
"inner afterAll",
|
||||
@@ -363,7 +362,7 @@ describe("jasmine spec running", function () {
|
||||
};
|
||||
|
||||
env.addReporter({jasmineDone: assertions});
|
||||
env.execute([spec.id, spec2.id]);
|
||||
env.execute([spec2.id, spec.id]);
|
||||
});
|
||||
|
||||
it('only runs *Alls once in a focused suite', function(done){
|
||||
@@ -416,9 +415,7 @@ describe("jasmine spec running", function () {
|
||||
'beforeEach',
|
||||
'spec in fdescribe',
|
||||
'afterEach',
|
||||
'afterAll',
|
||||
|
||||
'beforeAll',
|
||||
'beforeEach',
|
||||
'focused spec',
|
||||
'afterEach',
|
||||
@@ -549,10 +546,14 @@ describe("jasmine spec running", function () {
|
||||
pendingSpec = env.it("I am a pending spec");
|
||||
});
|
||||
|
||||
suite.execute(function() {
|
||||
var assertions = function() {
|
||||
expect(pendingSpec.status()).toBe("pending");
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
env.addReporter({jasmineDone: assertions});
|
||||
|
||||
env.execute();
|
||||
});
|
||||
|
||||
// TODO: is this useful? It doesn't catch syntax errors
|
||||
@@ -603,4 +604,96 @@ describe("jasmine spec running", function () {
|
||||
));
|
||||
|
||||
});
|
||||
|
||||
it("re-enters suites that have no *Alls", function(done) {
|
||||
var actions = [],
|
||||
spec1, spec2, spec3;
|
||||
|
||||
env.describe("top", function() {
|
||||
spec1 = env.it("spec1", function() {
|
||||
actions.push("spec1");
|
||||
});
|
||||
|
||||
spec2 = env.it("spec2", function() {
|
||||
actions.push("spec2");
|
||||
});
|
||||
});
|
||||
|
||||
spec3 = env.it("spec3", function() {
|
||||
actions.push("spec3");
|
||||
});
|
||||
|
||||
env.addReporter({
|
||||
jasmineDone: function() {
|
||||
expect(actions).toEqual(["spec2", "spec3", "spec1"]);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
env.execute([spec2.id, spec3.id, spec1.id]);
|
||||
});
|
||||
|
||||
it("refuses to re-enter suites with a beforeAll", function() {
|
||||
var actions = [],
|
||||
spec1, spec2, spec3;
|
||||
|
||||
env.describe("top", function() {
|
||||
env.beforeAll(function() {});
|
||||
|
||||
spec1 = env.it("spec1", function() {
|
||||
actions.push("spec1");
|
||||
});
|
||||
|
||||
spec2 = env.it("spec2", function() {
|
||||
actions.push("spec2");
|
||||
});
|
||||
});
|
||||
|
||||
spec3 = env.it("spec3", function() {
|
||||
actions.push("spec3");
|
||||
});
|
||||
|
||||
env.addReporter({
|
||||
jasmineDone: function() {
|
||||
expect(actions).toEqual([]);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
expect(function() {
|
||||
env.execute([spec2.id, spec3.id, spec1.id]);
|
||||
}).toThrowError(/beforeAll/);
|
||||
});
|
||||
|
||||
it("refuses to re-enter suites with a afterAll", function() {
|
||||
var actions = [],
|
||||
spec1, spec2, spec3;
|
||||
|
||||
env.describe("top", function() {
|
||||
env.afterAll(function() {});
|
||||
|
||||
spec1 = env.it("spec1", function() {
|
||||
actions.push("spec1");
|
||||
});
|
||||
|
||||
spec2 = env.it("spec2", function() {
|
||||
actions.push("spec2");
|
||||
});
|
||||
});
|
||||
|
||||
spec3 = env.it("spec3", function() {
|
||||
actions.push("spec3");
|
||||
});
|
||||
|
||||
env.addReporter({
|
||||
jasmineDone: function() {
|
||||
expect(actions).toEqual([]);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
expect(function() {
|
||||
env.execute([spec2.id, spec3.id, spec1.id]);
|
||||
}).toThrowError(/afterAll/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -100,27 +100,21 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
delete runnableResources[id];
|
||||
};
|
||||
|
||||
var beforeAndAfterFns = function(suite, runnablesExplictlySet) {
|
||||
var beforeAndAfterFns = function(suite) {
|
||||
return function() {
|
||||
var befores = [],
|
||||
afters = [],
|
||||
beforeAlls = [],
|
||||
afterAlls = [];
|
||||
afters = [];
|
||||
|
||||
while(suite) {
|
||||
befores = befores.concat(suite.beforeFns);
|
||||
afters = afters.concat(suite.afterFns);
|
||||
|
||||
if (runnablesExplictlySet()) {
|
||||
beforeAlls = beforeAlls.concat(suite.beforeAllFns);
|
||||
afterAlls = afterAlls.concat(suite.afterAllFns);
|
||||
}
|
||||
|
||||
suite = suite.parentSuite;
|
||||
}
|
||||
|
||||
return {
|
||||
befores: beforeAlls.reverse().concat(befores.reverse()),
|
||||
afters: afters.concat(afterAlls)
|
||||
befores: befores.reverse(),
|
||||
afters: afters
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -190,26 +184,40 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
};
|
||||
|
||||
this.execute = function(runnablesToRun) {
|
||||
if(runnablesToRun) {
|
||||
runnablesExplictlySet = true;
|
||||
} else if (focusedRunnables.length) {
|
||||
runnablesExplictlySet = true;
|
||||
runnablesToRun = focusedRunnables;
|
||||
} else {
|
||||
runnablesToRun = [topSuite.id];
|
||||
if(!runnablesToRun) {
|
||||
if (focusedRunnables.length) {
|
||||
runnablesToRun = focusedRunnables;
|
||||
} else {
|
||||
runnablesToRun = [topSuite.id];
|
||||
}
|
||||
}
|
||||
var processor = new j$.TreeProcessor({
|
||||
tree: topSuite,
|
||||
runnableIds: runnablesToRun,
|
||||
queueRunnerFactory: queueRunnerFactory,
|
||||
nodeStart: function(suite) {
|
||||
currentlyExecutingSuites.push(suite);
|
||||
defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
|
||||
reporter.suiteStarted(suite.result);
|
||||
},
|
||||
nodeComplete: function(suite, result) {
|
||||
if (!suite.disabled) {
|
||||
clearResourcesForRunnable(suite.id);
|
||||
}
|
||||
currentlyExecutingSuites.pop();
|
||||
reporter.suiteDone(result);
|
||||
}
|
||||
});
|
||||
|
||||
var allFns = [];
|
||||
for(var i = 0; i < runnablesToRun.length; i++) {
|
||||
var runnable = runnableLookupTable[runnablesToRun[i]];
|
||||
allFns.push((function(runnable) { return { fn: function(done) { runnable.execute(done); } }; })(runnable));
|
||||
if(!processor.processTree().valid) {
|
||||
throw new Error('Invalid order: would cause a beforeAll or afterAll to be run multiple times');
|
||||
}
|
||||
|
||||
reporter.jasmineStarted({
|
||||
totalSpecsDefined: totalSpecsDefined
|
||||
});
|
||||
|
||||
queueRunnerFactory({queueableFns: allFns, onComplete: reporter.jasmineDone});
|
||||
processor.execute(reporter.jasmineDone);
|
||||
};
|
||||
|
||||
this.addReporter = function(reporterToAdd) {
|
||||
@@ -233,28 +241,12 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
id: getNextSuiteId(),
|
||||
description: description,
|
||||
parentSuite: currentDeclarationSuite,
|
||||
queueRunner: queueRunnerFactory,
|
||||
onStart: suiteStarted,
|
||||
expectationFactory: expectationFactory,
|
||||
expectationResultFactory: expectationResultFactory,
|
||||
runnablesExplictlySetGetter: runnablesExplictlySetGetter,
|
||||
resultCallback: function(attrs) {
|
||||
if (!suite.disabled) {
|
||||
clearResourcesForRunnable(suite.id);
|
||||
}
|
||||
currentlyExecutingSuites.pop();
|
||||
reporter.suiteDone(attrs);
|
||||
}
|
||||
expectationResultFactory: expectationResultFactory
|
||||
});
|
||||
|
||||
runnableLookupTable[suite.id] = suite;
|
||||
return suite;
|
||||
|
||||
function suiteStarted(suite) {
|
||||
currentlyExecutingSuites.push(suite);
|
||||
defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
|
||||
reporter.suiteStarted(suite.result);
|
||||
}
|
||||
};
|
||||
|
||||
this.describe = function(description, specDefinitions) {
|
||||
@@ -326,17 +318,11 @@ getJasmineRequireObj().Env = function(j$) {
|
||||
}
|
||||
}
|
||||
|
||||
var runnablesExplictlySet = false;
|
||||
|
||||
var runnablesExplictlySetGetter = function(){
|
||||
return runnablesExplictlySet;
|
||||
};
|
||||
|
||||
var specFactory = function(description, fn, suite, timeout) {
|
||||
totalSpecsDefined++;
|
||||
var spec = new j$.Spec({
|
||||
id: getNextSpecId(),
|
||||
beforeAndAfterFns: beforeAndAfterFns(suite, runnablesExplictlySetGetter),
|
||||
beforeAndAfterFns: beforeAndAfterFns(suite),
|
||||
expectationFactory: expectationFactory,
|
||||
resultCallback: specResultCallback,
|
||||
getSpecName: function(spec) {
|
||||
|
||||
@@ -40,13 +40,13 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
return this.expectationFactory(actual, this);
|
||||
};
|
||||
|
||||
Spec.prototype.execute = function(onComplete) {
|
||||
Spec.prototype.execute = function(onComplete, enabled) {
|
||||
var self = this;
|
||||
|
||||
this.onStart(this);
|
||||
|
||||
if (this.markedPending || this.disabled) {
|
||||
complete();
|
||||
if (!this.isExecutable() || enabled === false) {
|
||||
complete(enabled);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
userContext: this.userContext()
|
||||
});
|
||||
|
||||
function complete() {
|
||||
self.result.status = self.status();
|
||||
function complete(enabledAgain) {
|
||||
self.result.status = self.status(enabledAgain);
|
||||
self.resultCallback(self.result);
|
||||
|
||||
if (onComplete) {
|
||||
@@ -96,8 +96,13 @@ getJasmineRequireObj().Spec = function(j$) {
|
||||
}
|
||||
};
|
||||
|
||||
Spec.prototype.status = function() {
|
||||
if (this.disabled) {
|
||||
Spec.prototype.getResult = function() {
|
||||
this.result.status = this.status();
|
||||
return this.result;
|
||||
};
|
||||
|
||||
Spec.prototype.status = function(enabled) {
|
||||
if (this.disabled || enabled === false) {
|
||||
return 'disabled';
|
||||
}
|
||||
|
||||
|
||||
@@ -4,18 +4,13 @@ getJasmineRequireObj().Suite = function() {
|
||||
this.id = attrs.id;
|
||||
this.parentSuite = attrs.parentSuite;
|
||||
this.description = attrs.description;
|
||||
this.onStart = attrs.onStart || function() {};
|
||||
this.resultCallback = attrs.resultCallback || function() {};
|
||||
this.clearStack = attrs.clearStack || function(fn) {fn();};
|
||||
this.expectationFactory = attrs.expectationFactory;
|
||||
this.expectationResultFactory = attrs.expectationResultFactory;
|
||||
this.runnablesExplictlySetGetter = attrs.runnablesExplictlySetGetter || function() {};
|
||||
|
||||
this.beforeFns = [];
|
||||
this.afterFns = [];
|
||||
this.beforeAllFns = [];
|
||||
this.afterAllFns = [];
|
||||
this.queueRunner = attrs.queueRunner || function() {};
|
||||
this.disabled = false;
|
||||
|
||||
this.children = [];
|
||||
@@ -78,51 +73,17 @@ getJasmineRequireObj().Suite = function() {
|
||||
}
|
||||
};
|
||||
|
||||
Suite.prototype.execute = function(onComplete) {
|
||||
var self = this;
|
||||
|
||||
this.onStart(this);
|
||||
|
||||
if (this.disabled) {
|
||||
complete();
|
||||
return;
|
||||
}
|
||||
|
||||
var allFns = [];
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
allFns.push(wrapChildAsAsync(this.children[i]));
|
||||
}
|
||||
|
||||
if (this.isExecutable()) {
|
||||
allFns = this.beforeAllFns.concat(allFns);
|
||||
allFns = allFns.concat(this.afterAllFns);
|
||||
}
|
||||
|
||||
this.queueRunner({
|
||||
queueableFns: allFns,
|
||||
onComplete: complete,
|
||||
userContext: this.sharedUserContext(),
|
||||
onException: function() { self.onException.apply(self, arguments); }
|
||||
});
|
||||
|
||||
function complete() {
|
||||
self.result.status = self.status();
|
||||
self.resultCallback(self.result);
|
||||
|
||||
if (onComplete) {
|
||||
onComplete();
|
||||
}
|
||||
}
|
||||
|
||||
function wrapChildAsAsync(child) {
|
||||
return { fn: function(done) { child.execute(done); } };
|
||||
}
|
||||
Suite.prototype.isExecutable = function() {
|
||||
return !this.disabled;
|
||||
};
|
||||
|
||||
Suite.prototype.isExecutable = function() {
|
||||
var runnablesExplicitlySet = this.runnablesExplictlySetGetter();
|
||||
return !runnablesExplicitlySet && hasExecutableChild(this.children);
|
||||
Suite.prototype.canBeReentered = function() {
|
||||
return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0;
|
||||
};
|
||||
|
||||
Suite.prototype.getResult = function() {
|
||||
this.result.status = this.status();
|
||||
return this.result;
|
||||
};
|
||||
|
||||
Suite.prototype.sharedUserContext = function() {
|
||||
@@ -175,17 +136,6 @@ getJasmineRequireObj().Suite = function() {
|
||||
return !args[0];
|
||||
}
|
||||
|
||||
function hasExecutableChild(children) {
|
||||
var foundActive = false;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
if (children[i].isExecutable()) {
|
||||
foundActive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return foundActive;
|
||||
}
|
||||
|
||||
function clone(obj) {
|
||||
var clonedObj = {};
|
||||
for (var prop in obj) {
|
||||
|
||||
203
src/core/TreeProcessor.js
Normal file
203
src/core/TreeProcessor.js
Normal file
@@ -0,0 +1,203 @@
|
||||
getJasmineRequireObj().TreeProcessor = function() {
|
||||
function TreeProcessor(attrs) {
|
||||
var tree = attrs.tree,
|
||||
runnableIds = attrs.runnableIds,
|
||||
queueRunnerFactory = attrs.queueRunnerFactory,
|
||||
nodeStart = attrs.nodeStart || function() {},
|
||||
nodeComplete = attrs.nodeComplete || function() {},
|
||||
stats = { valid: true },
|
||||
processed = false,
|
||||
defaultMin = Infinity,
|
||||
defaultMax = 1 - Infinity;
|
||||
|
||||
this.processTree = function() {
|
||||
processNode(tree, false);
|
||||
processed = true;
|
||||
return stats;
|
||||
};
|
||||
|
||||
this.execute = function(done) {
|
||||
if (!processed) {
|
||||
this.processTree();
|
||||
}
|
||||
|
||||
if (!stats.valid) {
|
||||
throw 'invalid order';
|
||||
}
|
||||
|
||||
var childFns = wrapChildren(tree, 0);
|
||||
|
||||
queueRunnerFactory({
|
||||
queueableFns: childFns,
|
||||
onException: function() {
|
||||
tree.onException.apply(tree, arguments);
|
||||
},
|
||||
onComplete: done
|
||||
});
|
||||
};
|
||||
|
||||
function runnableIndex(id) {
|
||||
for (var i = 0; i < runnableIds.length; i++) {
|
||||
if (runnableIds[i] === id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processNode(node, parentEnabled) {
|
||||
var executableIndex = runnableIndex(node.id);
|
||||
|
||||
if (executableIndex !== undefined) {
|
||||
parentEnabled = true;
|
||||
}
|
||||
|
||||
parentEnabled = parentEnabled && node.isExecutable();
|
||||
|
||||
if (!node.children) {
|
||||
stats[node.id] = {
|
||||
executable: parentEnabled && node.isExecutable(),
|
||||
segments: [{
|
||||
index: 0,
|
||||
owner: node,
|
||||
nodes: [node],
|
||||
min: startingMin(executableIndex),
|
||||
max: startingMax(executableIndex)
|
||||
}]
|
||||
};
|
||||
} else {
|
||||
var hasExecutableChild = false;
|
||||
|
||||
for (var i = 0; i < node.children.length; i++) {
|
||||
var child = node.children[i];
|
||||
|
||||
processNode(child, parentEnabled);
|
||||
|
||||
if (!stats.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
var childStats = stats[child.id];
|
||||
|
||||
hasExecutableChild = hasExecutableChild || childStats.executable;
|
||||
}
|
||||
|
||||
stats[node.id] = {
|
||||
executable: hasExecutableChild
|
||||
};
|
||||
|
||||
segmentChildren(node, stats[node.id], executableIndex);
|
||||
|
||||
if (!node.canBeReentered() && stats[node.id].segments.length > 1) {
|
||||
stats = { valid: false };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startingMin(executableIndex) {
|
||||
return executableIndex === undefined ? defaultMin : executableIndex;
|
||||
}
|
||||
|
||||
function startingMax(executableIndex) {
|
||||
return executableIndex === undefined ? defaultMax : executableIndex;
|
||||
}
|
||||
|
||||
function segmentChildren(node, nodeStats, executableIndex) {
|
||||
var currentSegment = { index: 0, owner: node, nodes: [], min: startingMin(executableIndex), max: startingMax(executableIndex) },
|
||||
result = [currentSegment],
|
||||
lastMax = defaultMax,
|
||||
orderedChildSegments = orderChildSegments(node.children);
|
||||
|
||||
function isSegmentBoundary(minIndex) {
|
||||
return lastMax !== defaultMax && minIndex !== defaultMin && lastMax < minIndex - 1;
|
||||
}
|
||||
|
||||
for (var i = 0; i < orderedChildSegments.length; i++) {
|
||||
var childSegment = orderedChildSegments[i],
|
||||
maxIndex = childSegment.max,
|
||||
minIndex = childSegment.min;
|
||||
|
||||
if (isSegmentBoundary(minIndex)) {
|
||||
currentSegment = {index: result.length, owner: node, nodes: [], min: defaultMin, max: defaultMin};
|
||||
result.push(currentSegment);
|
||||
}
|
||||
|
||||
currentSegment.nodes.push(childSegment);
|
||||
currentSegment.min = Math.min(currentSegment.min, minIndex);
|
||||
currentSegment.max = Math.max(currentSegment.max, maxIndex);
|
||||
lastMax = maxIndex;
|
||||
}
|
||||
|
||||
nodeStats.segments = result;
|
||||
}
|
||||
|
||||
function orderChildSegments(array) {
|
||||
var result = [];
|
||||
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
var child = array[i],
|
||||
segments = stats[child.id].segments;
|
||||
|
||||
for (var j = 0; j < segments.length; j++) {
|
||||
result.push(segments[j]);
|
||||
}
|
||||
}
|
||||
|
||||
result.sort(function(a, b) {
|
||||
if (a.min === null) {
|
||||
return b.min === null ? 0 : 1;
|
||||
}
|
||||
|
||||
if (b.min === null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return a.min - b.min;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function executeNode(node, segmentNumber) {
|
||||
if (node.children) {
|
||||
return {
|
||||
fn: function(done) {
|
||||
nodeStart(node);
|
||||
|
||||
queueRunnerFactory({
|
||||
onComplete: function() {
|
||||
nodeComplete(node, node.getResult());
|
||||
done();
|
||||
},
|
||||
queueableFns: wrapChildren(node, segmentNumber),
|
||||
userContext: node.sharedUserContext(),
|
||||
onException: function() {
|
||||
node.onException.apply(node, arguments);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
fn: function(done) { node.execute(done, stats[node.id].executable); }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function wrapChildren(node, segmentNumber) {
|
||||
var result = [],
|
||||
segmentChildren = stats[node.id].segments[segmentNumber].nodes;
|
||||
|
||||
for (var i = 0; i < segmentChildren.length; i++) {
|
||||
result.push(executeNode(segmentChildren[i].owner, segmentChildren[i].index));
|
||||
}
|
||||
|
||||
if (!stats[node.id].executable) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return node.beforeAllFns.concat(result).concat(node.afterAllFns);
|
||||
}
|
||||
}
|
||||
|
||||
return TreeProcessor;
|
||||
};
|
||||
@@ -43,6 +43,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
|
||||
j$.StringMatching = jRequire.StringMatching(j$);
|
||||
j$.Suite = jRequire.Suite();
|
||||
j$.Timer = jRequire.Timer();
|
||||
j$.TreeProcessor = jRequire.TreeProcessor();
|
||||
j$.version = jRequire.version();
|
||||
|
||||
j$.matchers = jRequire.requireMatchers(jRequire, j$);
|
||||
|
||||
Reference in New Issue
Block a user