Extract tree running out into a separate class
This commit is contained in:
@@ -108,6 +108,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
|
|||||||
j$.SuiteBuilder = jRequire.SuiteBuilder(j$);
|
j$.SuiteBuilder = jRequire.SuiteBuilder(j$);
|
||||||
j$.Timer = jRequire.Timer();
|
j$.Timer = jRequire.Timer();
|
||||||
j$.TreeProcessor = jRequire.TreeProcessor(j$);
|
j$.TreeProcessor = jRequire.TreeProcessor(j$);
|
||||||
|
j$.TreeRunner = jRequire.TreeRunner(j$);
|
||||||
j$.version = jRequire.version();
|
j$.version = jRequire.version();
|
||||||
j$.Order = jRequire.Order();
|
j$.Order = jRequire.Order();
|
||||||
j$.DiffBuilder = jRequire.DiffBuilder(j$);
|
j$.DiffBuilder = jRequire.DiffBuilder(j$);
|
||||||
@@ -1961,7 +1962,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
function specResultCallback(spec, result, next) {
|
function specResultCallback(spec, result, next) {
|
||||||
runableResources.clearForRunable(spec.id);
|
runableResources.clearForRunable(spec.id);
|
||||||
runner.currentSpec = null;
|
runner.setCurrentSpec(null);
|
||||||
|
|
||||||
if (result.status === 'failed') {
|
if (result.status === 'failed') {
|
||||||
runner.hasFailures = true;
|
runner.hasFailures = true;
|
||||||
@@ -1971,7 +1972,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function specStarted(spec, suite, next) {
|
function specStarted(spec, suite, next) {
|
||||||
runner.currentSpec = spec;
|
runner.setCurrentSpec(spec);
|
||||||
runableResources.initForRunable(spec.id, suite.id);
|
runableResources.initForRunable(spec.id, suite.id);
|
||||||
reportDispatcher.specStarted(spec.result).then(next);
|
reportDispatcher.specStarted(spec.result).then(next);
|
||||||
}
|
}
|
||||||
@@ -9413,7 +9414,7 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
#getConfig;
|
#getConfig;
|
||||||
#reportSpecDone;
|
#reportSpecDone;
|
||||||
#executedBefore;
|
#executedBefore;
|
||||||
#currentlyExecutingSuites;
|
#currentRunableTracker;
|
||||||
|
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
this.#topSuite = options.topSuite;
|
this.#topSuite = options.topSuite;
|
||||||
@@ -9428,19 +9429,23 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
this.#reportSpecDone = options.reportSpecDone;
|
this.#reportSpecDone = options.reportSpecDone;
|
||||||
this.hasFailures = false;
|
this.hasFailures = false;
|
||||||
this.#executedBefore = false;
|
this.#executedBefore = false;
|
||||||
|
this.#currentRunableTracker = new CurrentRunableTracker();
|
||||||
|
}
|
||||||
|
|
||||||
this.#currentlyExecutingSuites = [];
|
currentSpec() {
|
||||||
this.currentSpec = null;
|
return this.#currentRunableTracker.currentSpec();
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentSpec(spec) {
|
||||||
|
this.#currentRunableTracker.setCurrentSpec(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRunable() {
|
currentRunable() {
|
||||||
return this.currentSpec || this.currentSuite();
|
return this.#currentRunableTracker.currentRunable();
|
||||||
}
|
}
|
||||||
|
|
||||||
currentSuite() {
|
currentSuite() {
|
||||||
return this.#currentlyExecutingSuites[
|
return this.#currentRunableTracker.currentSuite();
|
||||||
this.#currentlyExecutingSuites.length - 1
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parallelReset() {
|
parallelReset() {
|
||||||
@@ -9508,15 +9513,28 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
parallel: false
|
parallel: false
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#currentlyExecutingSuites.push(this.#topSuite);
|
this.#currentRunableTracker.pushSuite(this.#topSuite);
|
||||||
await this.#executeTopSuite();
|
const treeRunner = new j$.TreeRunner({
|
||||||
|
executionTree: this.#executionTree,
|
||||||
|
globalErrors: this.#globalErrors,
|
||||||
|
runableResources: this.#runableResources,
|
||||||
|
reportDispatcher: this.#reportDispatcher,
|
||||||
|
runQueue: this.#runQueue,
|
||||||
|
getConfig: this.#getConfig,
|
||||||
|
reportChildrenOfBeforeAllFailure: this.#reportChildrenOfBeforeAllFailure.bind(
|
||||||
|
this
|
||||||
|
),
|
||||||
|
currentRunableTracker: this.#currentRunableTracker
|
||||||
|
});
|
||||||
|
await treeRunner.execute();
|
||||||
|
this.hasFailures = this.hasFailures || treeRunner.hasFailures;
|
||||||
|
|
||||||
if (this.#topSuite.hadBeforeAllFailure) {
|
if (this.#topSuite.hadBeforeAllFailure) {
|
||||||
await this.#reportChildrenOfBeforeAllFailure(this.#topSuite);
|
await this.#reportChildrenOfBeforeAllFailure(this.#topSuite);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#runableResources.clearForRunable(this.#topSuite.id);
|
this.#runableResources.clearForRunable(this.#topSuite.id);
|
||||||
this.#currentlyExecutingSuites.pop();
|
this.#currentRunableTracker.popSuite();
|
||||||
let overallStatus, incompleteReason, incompleteCode;
|
let overallStatus, incompleteReason, incompleteCode;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -9563,152 +9581,6 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
return jasmineDoneInfo;
|
return jasmineDoneInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
async #executeTopSuite() {
|
|
||||||
const wrappedChildren = this.#wrapNodes(
|
|
||||||
this.#executionTree.childrenOfTopSuite()
|
|
||||||
);
|
|
||||||
const queueableFns = this.#addBeforeAndAfterAlls(
|
|
||||||
this.#topSuite,
|
|
||||||
wrappedChildren
|
|
||||||
);
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
this.#runQueueWithSkipPolicy({
|
|
||||||
queueableFns,
|
|
||||||
userContext: this.#topSuite.sharedUserContext(),
|
|
||||||
onException: function() {
|
|
||||||
this.#topSuite.handleException.apply(this.#topSuite, arguments);
|
|
||||||
}.bind(this),
|
|
||||||
onComplete: resolve,
|
|
||||||
onMultipleDone: this.#topSuite.onMultipleDone
|
|
||||||
? this.#topSuite.onMultipleDone.bind(this.#topSuite)
|
|
||||||
: null
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#executeSuiteSegment(suite, segmentNumber, done) {
|
|
||||||
const wrappedChildren = this.#wrapNodes(
|
|
||||||
this.#executionTree.childrenOfSuiteSegment(suite, segmentNumber)
|
|
||||||
);
|
|
||||||
const onStart = {
|
|
||||||
fn: next => {
|
|
||||||
this.#suiteSegmentStart(suite, next);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const queueableFns = [
|
|
||||||
onStart,
|
|
||||||
...this.#addBeforeAndAfterAlls(suite, wrappedChildren)
|
|
||||||
];
|
|
||||||
|
|
||||||
this.#runQueueWithSkipPolicy({
|
|
||||||
// TODO: if onComplete always takes 0-1 arguments (and it probably does)
|
|
||||||
// then it can be switched to an arrow fn with a named arg.
|
|
||||||
onComplete: function() {
|
|
||||||
const args = Array.prototype.slice.call(arguments, [0]);
|
|
||||||
this.#suiteSegmentComplete(suite, suite.getResult(), () => {
|
|
||||||
done.apply(undefined, args);
|
|
||||||
});
|
|
||||||
}.bind(this),
|
|
||||||
queueableFns,
|
|
||||||
userContext: suite.sharedUserContext(),
|
|
||||||
onException: function() {
|
|
||||||
suite.handleException.apply(suite, arguments);
|
|
||||||
},
|
|
||||||
onMultipleDone: suite.onMultipleDone
|
|
||||||
? suite.onMultipleDone.bind(suite)
|
|
||||||
: null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#executeSpec(spec, done) {
|
|
||||||
const config = this.#getConfig();
|
|
||||||
spec.execute(
|
|
||||||
this.#runQueueWithSkipPolicy.bind(this),
|
|
||||||
this.#globalErrors,
|
|
||||||
done,
|
|
||||||
this.#executionTree.isExcluded(spec),
|
|
||||||
config.failSpecWithNoExpectations,
|
|
||||||
config.detectLateRejectionHandling
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#wrapNodes(nodes) {
|
|
||||||
return nodes.map(node => {
|
|
||||||
return {
|
|
||||||
fn: done => {
|
|
||||||
if (node.suite) {
|
|
||||||
this.#executeSuiteSegment(node.suite, node.segmentNumber, done);
|
|
||||||
} else {
|
|
||||||
this.#executeSpec(node.spec, done);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#addBeforeAndAfterAlls(suite, wrappedChildren) {
|
|
||||||
if (this.#executionTree.isExcluded(suite)) {
|
|
||||||
return wrappedChildren;
|
|
||||||
}
|
|
||||||
|
|
||||||
return suite.beforeAllFns
|
|
||||||
.concat(wrappedChildren)
|
|
||||||
.concat(suite.afterAllFns);
|
|
||||||
}
|
|
||||||
|
|
||||||
#suiteSegmentStart(suite, next) {
|
|
||||||
this.#currentlyExecutingSuites.push(suite);
|
|
||||||
this.#runableResources.initForRunable(suite.id, suite.parentSuite.id);
|
|
||||||
this.#reportDispatcher.suiteStarted(suite.result).then(next);
|
|
||||||
suite.startTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
#suiteSegmentComplete(suite, result, next) {
|
|
||||||
suite.cleanupBeforeAfter();
|
|
||||||
|
|
||||||
if (suite !== this.currentSuite()) {
|
|
||||||
throw new Error('Tried to complete the wrong suite');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.#runableResources.clearForRunable(suite.id);
|
|
||||||
this.#currentlyExecutingSuites.pop();
|
|
||||||
|
|
||||||
if (result.status === 'failed') {
|
|
||||||
this.hasFailures = true;
|
|
||||||
}
|
|
||||||
suite.endTimer();
|
|
||||||
|
|
||||||
if (suite.hadBeforeAllFailure) {
|
|
||||||
this.#reportChildrenOfBeforeAllFailure(suite).then(() => {
|
|
||||||
this.#reportSuiteDone(suite, result, next);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.#reportSuiteDone(suite, result, next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#runQueueWithSkipPolicy(options) {
|
|
||||||
if (options.isLeaf) {
|
|
||||||
// A spec
|
|
||||||
options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy;
|
|
||||||
} else {
|
|
||||||
// A suite
|
|
||||||
if (this.#getConfig().stopOnSpecFailure) {
|
|
||||||
options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy;
|
|
||||||
} else {
|
|
||||||
options.SkipPolicy = j$.SkipAfterBeforeAllErrorPolicy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.#runQueue(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
#reportSuiteDone(suite, result, next) {
|
|
||||||
suite.reportedDone = true;
|
|
||||||
this.#reportDispatcher.suiteDone(result).then(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
async #reportChildrenOfBeforeAllFailure(suite) {
|
async #reportChildrenOfBeforeAllFailure(suite) {
|
||||||
for (const child of suite.children) {
|
for (const child of suite.children) {
|
||||||
if (child instanceof j$.Suite) {
|
if (child instanceof j$.Suite) {
|
||||||
@@ -9745,6 +9617,41 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CurrentRunableTracker {
|
||||||
|
#currentSpec;
|
||||||
|
#currentlyExecutingSuites;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.#currentlyExecutingSuites = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRunable() {
|
||||||
|
return this.currentSpec() || this.currentSuite();
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSpec() {
|
||||||
|
return this.#currentSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentSpec(spec) {
|
||||||
|
this.#currentSpec = spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSuite() {
|
||||||
|
return this.#currentlyExecutingSuites[
|
||||||
|
this.#currentlyExecutingSuites.length - 1
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
pushSuite(suite) {
|
||||||
|
this.#currentlyExecutingSuites.push(suite);
|
||||||
|
}
|
||||||
|
|
||||||
|
popSuite() {
|
||||||
|
this.#currentlyExecutingSuites.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Runner;
|
return Runner;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -11500,16 +11407,18 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ExecutionTree {
|
class ExecutionTree {
|
||||||
#topSuite;
|
|
||||||
#stats;
|
#stats;
|
||||||
|
|
||||||
constructor(topSuite, stats) {
|
constructor(topSuite, stats) {
|
||||||
this.#topSuite = topSuite;
|
Object.defineProperty(this, 'topSuite', {
|
||||||
|
writable: false,
|
||||||
|
value: topSuite
|
||||||
|
});
|
||||||
this.#stats = stats;
|
this.#stats = stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
childrenOfTopSuite() {
|
childrenOfTopSuite() {
|
||||||
return this.childrenOfSuiteSegment(this.#topSuite, 0);
|
return this.childrenOfSuiteSegment(this.topSuite, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
childrenOfSuiteSegment(suite, segmentNumber) {
|
childrenOfSuiteSegment(suite, segmentNumber) {
|
||||||
@@ -11612,6 +11521,181 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
|
|||||||
return TreeProcessor;
|
return TreeProcessor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getJasmineRequireObj().TreeRunner = function(j$) {
|
||||||
|
class TreeRunner {
|
||||||
|
#executionTree;
|
||||||
|
#globalErrors;
|
||||||
|
#runableResources;
|
||||||
|
#reportDispatcher;
|
||||||
|
#runQueue;
|
||||||
|
#getConfig;
|
||||||
|
#reportChildrenOfBeforeAllFailure;
|
||||||
|
#currentRunableTracker;
|
||||||
|
|
||||||
|
constructor(attrs) {
|
||||||
|
this.#executionTree = attrs.executionTree;
|
||||||
|
this.#globalErrors = attrs.globalErrors;
|
||||||
|
this.#runableResources = attrs.runableResources;
|
||||||
|
this.#reportDispatcher = attrs.reportDispatcher;
|
||||||
|
this.#runQueue = attrs.runQueue;
|
||||||
|
this.#getConfig = attrs.getConfig;
|
||||||
|
this.#reportChildrenOfBeforeAllFailure =
|
||||||
|
attrs.reportChildrenOfBeforeAllFailure;
|
||||||
|
this.#currentRunableTracker = attrs.currentRunableTracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute() {
|
||||||
|
this.hasFailures = false;
|
||||||
|
const topSuite = this.#executionTree.topSuite;
|
||||||
|
const wrappedChildren = this.#wrapNodes(
|
||||||
|
this.#executionTree.childrenOfTopSuite()
|
||||||
|
);
|
||||||
|
const queueableFns = this.#addBeforeAndAfterAlls(
|
||||||
|
topSuite,
|
||||||
|
wrappedChildren
|
||||||
|
);
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
this.#runQueueWithSkipPolicy({
|
||||||
|
queueableFns,
|
||||||
|
userContext: this.#executionTree.topSuite.sharedUserContext(),
|
||||||
|
onException: function() {
|
||||||
|
topSuite.handleException.apply(topSuite, arguments);
|
||||||
|
}.bind(this),
|
||||||
|
onComplete: resolve,
|
||||||
|
onMultipleDone: topSuite.onMultipleDone
|
||||||
|
? topSuite.onMultipleDone.bind(topSuite)
|
||||||
|
: null
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#wrapNodes(nodes) {
|
||||||
|
return nodes.map(node => {
|
||||||
|
return {
|
||||||
|
fn: done => {
|
||||||
|
if (node.suite) {
|
||||||
|
this.#executeSuiteSegment(node.suite, node.segmentNumber, done);
|
||||||
|
} else {
|
||||||
|
this.#executeSpec(node.spec, done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#executeSpec(spec, done) {
|
||||||
|
const config = this.#getConfig();
|
||||||
|
spec.execute(
|
||||||
|
this.#runQueueWithSkipPolicy.bind(this),
|
||||||
|
this.#globalErrors,
|
||||||
|
done,
|
||||||
|
this.#executionTree.isExcluded(spec),
|
||||||
|
config.failSpecWithNoExpectations,
|
||||||
|
config.detectLateRejectionHandling
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#executeSuiteSegment(suite, segmentNumber, done) {
|
||||||
|
const wrappedChildren = this.#wrapNodes(
|
||||||
|
this.#executionTree.childrenOfSuiteSegment(suite, segmentNumber)
|
||||||
|
);
|
||||||
|
const onStart = {
|
||||||
|
fn: next => {
|
||||||
|
this.#suiteSegmentStart(suite, next);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const queueableFns = [
|
||||||
|
onStart,
|
||||||
|
...this.#addBeforeAndAfterAlls(suite, wrappedChildren)
|
||||||
|
];
|
||||||
|
|
||||||
|
this.#runQueueWithSkipPolicy({
|
||||||
|
// TODO: if onComplete always takes 0-1 arguments (and it probably does)
|
||||||
|
// then it can be switched to an arrow fn with a named arg.
|
||||||
|
onComplete: function() {
|
||||||
|
const args = Array.prototype.slice.call(arguments, [0]);
|
||||||
|
this.#suiteSegmentComplete(suite, suite.getResult(), () => {
|
||||||
|
done.apply(undefined, args);
|
||||||
|
});
|
||||||
|
}.bind(this),
|
||||||
|
queueableFns,
|
||||||
|
userContext: suite.sharedUserContext(),
|
||||||
|
onException: function() {
|
||||||
|
suite.handleException.apply(suite, arguments);
|
||||||
|
},
|
||||||
|
onMultipleDone: suite.onMultipleDone
|
||||||
|
? suite.onMultipleDone.bind(suite)
|
||||||
|
: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#suiteSegmentStart(suite, next) {
|
||||||
|
this.#currentRunableTracker.pushSuite(suite);
|
||||||
|
this.#runableResources.initForRunable(suite.id, suite.parentSuite.id);
|
||||||
|
this.#reportDispatcher.suiteStarted(suite.result).then(next);
|
||||||
|
suite.startTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
#suiteSegmentComplete(suite, result, next) {
|
||||||
|
suite.cleanupBeforeAfter();
|
||||||
|
|
||||||
|
if (suite !== this.#currentRunableTracker.currentSuite()) {
|
||||||
|
throw new Error('Tried to complete the wrong suite');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#runableResources.clearForRunable(suite.id);
|
||||||
|
this.#currentRunableTracker.popSuite();
|
||||||
|
|
||||||
|
if (result.status === 'failed') {
|
||||||
|
this.hasFailures = true;
|
||||||
|
}
|
||||||
|
suite.endTimer();
|
||||||
|
|
||||||
|
if (suite.hadBeforeAllFailure) {
|
||||||
|
this.#reportChildrenOfBeforeAllFailure(suite).then(() => {
|
||||||
|
this.#reportSuiteDone(suite, result, next);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.#reportSuiteDone(suite, result, next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#reportSuiteDone(suite, result, next) {
|
||||||
|
suite.reportedDone = true;
|
||||||
|
this.#reportDispatcher.suiteDone(result).then(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
#addBeforeAndAfterAlls(suite, wrappedChildren) {
|
||||||
|
if (this.#executionTree.isExcluded(suite)) {
|
||||||
|
return wrappedChildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
return suite.beforeAllFns
|
||||||
|
.concat(wrappedChildren)
|
||||||
|
.concat(suite.afterAllFns);
|
||||||
|
}
|
||||||
|
|
||||||
|
#runQueueWithSkipPolicy(options) {
|
||||||
|
if (options.isLeaf) {
|
||||||
|
// A spec
|
||||||
|
options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy;
|
||||||
|
} else {
|
||||||
|
// A suite
|
||||||
|
if (this.#getConfig().stopOnSpecFailure) {
|
||||||
|
options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy;
|
||||||
|
} else {
|
||||||
|
options.SkipPolicy = j$.SkipAfterBeforeAllErrorPolicy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.#runQueue(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TreeRunner;
|
||||||
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().UserContext = function(j$) {
|
getJasmineRequireObj().UserContext = function(j$) {
|
||||||
function UserContext() {}
|
function UserContext() {}
|
||||||
|
|
||||||
|
|||||||
@@ -765,7 +765,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
function specResultCallback(spec, result, next) {
|
function specResultCallback(spec, result, next) {
|
||||||
runableResources.clearForRunable(spec.id);
|
runableResources.clearForRunable(spec.id);
|
||||||
runner.currentSpec = null;
|
runner.setCurrentSpec(null);
|
||||||
|
|
||||||
if (result.status === 'failed') {
|
if (result.status === 'failed') {
|
||||||
runner.hasFailures = true;
|
runner.hasFailures = true;
|
||||||
@@ -775,7 +775,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function specStarted(spec, suite, next) {
|
function specStarted(spec, suite, next) {
|
||||||
runner.currentSpec = spec;
|
runner.setCurrentSpec(spec);
|
||||||
runableResources.initForRunable(spec.id, suite.id);
|
runableResources.initForRunable(spec.id, suite.id);
|
||||||
reportDispatcher.specStarted(spec.result).then(next);
|
reportDispatcher.specStarted(spec.result).then(next);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
#getConfig;
|
#getConfig;
|
||||||
#reportSpecDone;
|
#reportSpecDone;
|
||||||
#executedBefore;
|
#executedBefore;
|
||||||
#currentlyExecutingSuites;
|
#currentRunableTracker;
|
||||||
|
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
this.#topSuite = options.topSuite;
|
this.#topSuite = options.topSuite;
|
||||||
@@ -27,19 +27,23 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
this.#reportSpecDone = options.reportSpecDone;
|
this.#reportSpecDone = options.reportSpecDone;
|
||||||
this.hasFailures = false;
|
this.hasFailures = false;
|
||||||
this.#executedBefore = false;
|
this.#executedBefore = false;
|
||||||
|
this.#currentRunableTracker = new CurrentRunableTracker();
|
||||||
|
}
|
||||||
|
|
||||||
this.#currentlyExecutingSuites = [];
|
currentSpec() {
|
||||||
this.currentSpec = null;
|
return this.#currentRunableTracker.currentSpec();
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentSpec(spec) {
|
||||||
|
this.#currentRunableTracker.setCurrentSpec(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRunable() {
|
currentRunable() {
|
||||||
return this.currentSpec || this.currentSuite();
|
return this.#currentRunableTracker.currentRunable();
|
||||||
}
|
}
|
||||||
|
|
||||||
currentSuite() {
|
currentSuite() {
|
||||||
return this.#currentlyExecutingSuites[
|
return this.#currentRunableTracker.currentSuite();
|
||||||
this.#currentlyExecutingSuites.length - 1
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parallelReset() {
|
parallelReset() {
|
||||||
@@ -107,15 +111,28 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
parallel: false
|
parallel: false
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#currentlyExecutingSuites.push(this.#topSuite);
|
this.#currentRunableTracker.pushSuite(this.#topSuite);
|
||||||
await this.#executeTopSuite();
|
const treeRunner = new j$.TreeRunner({
|
||||||
|
executionTree: this.#executionTree,
|
||||||
|
globalErrors: this.#globalErrors,
|
||||||
|
runableResources: this.#runableResources,
|
||||||
|
reportDispatcher: this.#reportDispatcher,
|
||||||
|
runQueue: this.#runQueue,
|
||||||
|
getConfig: this.#getConfig,
|
||||||
|
reportChildrenOfBeforeAllFailure: this.#reportChildrenOfBeforeAllFailure.bind(
|
||||||
|
this
|
||||||
|
),
|
||||||
|
currentRunableTracker: this.#currentRunableTracker
|
||||||
|
});
|
||||||
|
await treeRunner.execute();
|
||||||
|
this.hasFailures = this.hasFailures || treeRunner.hasFailures;
|
||||||
|
|
||||||
if (this.#topSuite.hadBeforeAllFailure) {
|
if (this.#topSuite.hadBeforeAllFailure) {
|
||||||
await this.#reportChildrenOfBeforeAllFailure(this.#topSuite);
|
await this.#reportChildrenOfBeforeAllFailure(this.#topSuite);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#runableResources.clearForRunable(this.#topSuite.id);
|
this.#runableResources.clearForRunable(this.#topSuite.id);
|
||||||
this.#currentlyExecutingSuites.pop();
|
this.#currentRunableTracker.popSuite();
|
||||||
let overallStatus, incompleteReason, incompleteCode;
|
let overallStatus, incompleteReason, incompleteCode;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -162,152 +179,6 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
return jasmineDoneInfo;
|
return jasmineDoneInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
async #executeTopSuite() {
|
|
||||||
const wrappedChildren = this.#wrapNodes(
|
|
||||||
this.#executionTree.childrenOfTopSuite()
|
|
||||||
);
|
|
||||||
const queueableFns = this.#addBeforeAndAfterAlls(
|
|
||||||
this.#topSuite,
|
|
||||||
wrappedChildren
|
|
||||||
);
|
|
||||||
|
|
||||||
await new Promise(resolve => {
|
|
||||||
this.#runQueueWithSkipPolicy({
|
|
||||||
queueableFns,
|
|
||||||
userContext: this.#topSuite.sharedUserContext(),
|
|
||||||
onException: function() {
|
|
||||||
this.#topSuite.handleException.apply(this.#topSuite, arguments);
|
|
||||||
}.bind(this),
|
|
||||||
onComplete: resolve,
|
|
||||||
onMultipleDone: this.#topSuite.onMultipleDone
|
|
||||||
? this.#topSuite.onMultipleDone.bind(this.#topSuite)
|
|
||||||
: null
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#executeSuiteSegment(suite, segmentNumber, done) {
|
|
||||||
const wrappedChildren = this.#wrapNodes(
|
|
||||||
this.#executionTree.childrenOfSuiteSegment(suite, segmentNumber)
|
|
||||||
);
|
|
||||||
const onStart = {
|
|
||||||
fn: next => {
|
|
||||||
this.#suiteSegmentStart(suite, next);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const queueableFns = [
|
|
||||||
onStart,
|
|
||||||
...this.#addBeforeAndAfterAlls(suite, wrappedChildren)
|
|
||||||
];
|
|
||||||
|
|
||||||
this.#runQueueWithSkipPolicy({
|
|
||||||
// TODO: if onComplete always takes 0-1 arguments (and it probably does)
|
|
||||||
// then it can be switched to an arrow fn with a named arg.
|
|
||||||
onComplete: function() {
|
|
||||||
const args = Array.prototype.slice.call(arguments, [0]);
|
|
||||||
this.#suiteSegmentComplete(suite, suite.getResult(), () => {
|
|
||||||
done.apply(undefined, args);
|
|
||||||
});
|
|
||||||
}.bind(this),
|
|
||||||
queueableFns,
|
|
||||||
userContext: suite.sharedUserContext(),
|
|
||||||
onException: function() {
|
|
||||||
suite.handleException.apply(suite, arguments);
|
|
||||||
},
|
|
||||||
onMultipleDone: suite.onMultipleDone
|
|
||||||
? suite.onMultipleDone.bind(suite)
|
|
||||||
: null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#executeSpec(spec, done) {
|
|
||||||
const config = this.#getConfig();
|
|
||||||
spec.execute(
|
|
||||||
this.#runQueueWithSkipPolicy.bind(this),
|
|
||||||
this.#globalErrors,
|
|
||||||
done,
|
|
||||||
this.#executionTree.isExcluded(spec),
|
|
||||||
config.failSpecWithNoExpectations,
|
|
||||||
config.detectLateRejectionHandling
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#wrapNodes(nodes) {
|
|
||||||
return nodes.map(node => {
|
|
||||||
return {
|
|
||||||
fn: done => {
|
|
||||||
if (node.suite) {
|
|
||||||
this.#executeSuiteSegment(node.suite, node.segmentNumber, done);
|
|
||||||
} else {
|
|
||||||
this.#executeSpec(node.spec, done);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#addBeforeAndAfterAlls(suite, wrappedChildren) {
|
|
||||||
if (this.#executionTree.isExcluded(suite)) {
|
|
||||||
return wrappedChildren;
|
|
||||||
}
|
|
||||||
|
|
||||||
return suite.beforeAllFns
|
|
||||||
.concat(wrappedChildren)
|
|
||||||
.concat(suite.afterAllFns);
|
|
||||||
}
|
|
||||||
|
|
||||||
#suiteSegmentStart(suite, next) {
|
|
||||||
this.#currentlyExecutingSuites.push(suite);
|
|
||||||
this.#runableResources.initForRunable(suite.id, suite.parentSuite.id);
|
|
||||||
this.#reportDispatcher.suiteStarted(suite.result).then(next);
|
|
||||||
suite.startTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
#suiteSegmentComplete(suite, result, next) {
|
|
||||||
suite.cleanupBeforeAfter();
|
|
||||||
|
|
||||||
if (suite !== this.currentSuite()) {
|
|
||||||
throw new Error('Tried to complete the wrong suite');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.#runableResources.clearForRunable(suite.id);
|
|
||||||
this.#currentlyExecutingSuites.pop();
|
|
||||||
|
|
||||||
if (result.status === 'failed') {
|
|
||||||
this.hasFailures = true;
|
|
||||||
}
|
|
||||||
suite.endTimer();
|
|
||||||
|
|
||||||
if (suite.hadBeforeAllFailure) {
|
|
||||||
this.#reportChildrenOfBeforeAllFailure(suite).then(() => {
|
|
||||||
this.#reportSuiteDone(suite, result, next);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.#reportSuiteDone(suite, result, next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#runQueueWithSkipPolicy(options) {
|
|
||||||
if (options.isLeaf) {
|
|
||||||
// A spec
|
|
||||||
options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy;
|
|
||||||
} else {
|
|
||||||
// A suite
|
|
||||||
if (this.#getConfig().stopOnSpecFailure) {
|
|
||||||
options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy;
|
|
||||||
} else {
|
|
||||||
options.SkipPolicy = j$.SkipAfterBeforeAllErrorPolicy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.#runQueue(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
#reportSuiteDone(suite, result, next) {
|
|
||||||
suite.reportedDone = true;
|
|
||||||
this.#reportDispatcher.suiteDone(result).then(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
async #reportChildrenOfBeforeAllFailure(suite) {
|
async #reportChildrenOfBeforeAllFailure(suite) {
|
||||||
for (const child of suite.children) {
|
for (const child of suite.children) {
|
||||||
if (child instanceof j$.Suite) {
|
if (child instanceof j$.Suite) {
|
||||||
@@ -344,5 +215,40 @@ getJasmineRequireObj().Runner = function(j$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CurrentRunableTracker {
|
||||||
|
#currentSpec;
|
||||||
|
#currentlyExecutingSuites;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.#currentlyExecutingSuites = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRunable() {
|
||||||
|
return this.currentSpec() || this.currentSuite();
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSpec() {
|
||||||
|
return this.#currentSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentSpec(spec) {
|
||||||
|
this.#currentSpec = spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSuite() {
|
||||||
|
return this.#currentlyExecutingSuites[
|
||||||
|
this.#currentlyExecutingSuites.length - 1
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
pushSuite(suite) {
|
||||||
|
this.#currentlyExecutingSuites.push(suite);
|
||||||
|
}
|
||||||
|
|
||||||
|
popSuite() {
|
||||||
|
this.#currentlyExecutingSuites.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Runner;
|
return Runner;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -101,16 +101,18 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ExecutionTree {
|
class ExecutionTree {
|
||||||
#topSuite;
|
|
||||||
#stats;
|
#stats;
|
||||||
|
|
||||||
constructor(topSuite, stats) {
|
constructor(topSuite, stats) {
|
||||||
this.#topSuite = topSuite;
|
Object.defineProperty(this, 'topSuite', {
|
||||||
|
writable: false,
|
||||||
|
value: topSuite
|
||||||
|
});
|
||||||
this.#stats = stats;
|
this.#stats = stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
childrenOfTopSuite() {
|
childrenOfTopSuite() {
|
||||||
return this.childrenOfSuiteSegment(this.#topSuite, 0);
|
return this.childrenOfSuiteSegment(this.topSuite, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
childrenOfSuiteSegment(suite, segmentNumber) {
|
childrenOfSuiteSegment(suite, segmentNumber) {
|
||||||
|
|||||||
174
src/core/TreeRunner.js
Normal file
174
src/core/TreeRunner.js
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
getJasmineRequireObj().TreeRunner = function(j$) {
|
||||||
|
class TreeRunner {
|
||||||
|
#executionTree;
|
||||||
|
#globalErrors;
|
||||||
|
#runableResources;
|
||||||
|
#reportDispatcher;
|
||||||
|
#runQueue;
|
||||||
|
#getConfig;
|
||||||
|
#reportChildrenOfBeforeAllFailure;
|
||||||
|
#currentRunableTracker;
|
||||||
|
|
||||||
|
constructor(attrs) {
|
||||||
|
this.#executionTree = attrs.executionTree;
|
||||||
|
this.#globalErrors = attrs.globalErrors;
|
||||||
|
this.#runableResources = attrs.runableResources;
|
||||||
|
this.#reportDispatcher = attrs.reportDispatcher;
|
||||||
|
this.#runQueue = attrs.runQueue;
|
||||||
|
this.#getConfig = attrs.getConfig;
|
||||||
|
this.#reportChildrenOfBeforeAllFailure =
|
||||||
|
attrs.reportChildrenOfBeforeAllFailure;
|
||||||
|
this.#currentRunableTracker = attrs.currentRunableTracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute() {
|
||||||
|
this.hasFailures = false;
|
||||||
|
const topSuite = this.#executionTree.topSuite;
|
||||||
|
const wrappedChildren = this.#wrapNodes(
|
||||||
|
this.#executionTree.childrenOfTopSuite()
|
||||||
|
);
|
||||||
|
const queueableFns = this.#addBeforeAndAfterAlls(
|
||||||
|
topSuite,
|
||||||
|
wrappedChildren
|
||||||
|
);
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
this.#runQueueWithSkipPolicy({
|
||||||
|
queueableFns,
|
||||||
|
userContext: this.#executionTree.topSuite.sharedUserContext(),
|
||||||
|
onException: function() {
|
||||||
|
topSuite.handleException.apply(topSuite, arguments);
|
||||||
|
}.bind(this),
|
||||||
|
onComplete: resolve,
|
||||||
|
onMultipleDone: topSuite.onMultipleDone
|
||||||
|
? topSuite.onMultipleDone.bind(topSuite)
|
||||||
|
: null
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#wrapNodes(nodes) {
|
||||||
|
return nodes.map(node => {
|
||||||
|
return {
|
||||||
|
fn: done => {
|
||||||
|
if (node.suite) {
|
||||||
|
this.#executeSuiteSegment(node.suite, node.segmentNumber, done);
|
||||||
|
} else {
|
||||||
|
this.#executeSpec(node.spec, done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#executeSpec(spec, done) {
|
||||||
|
const config = this.#getConfig();
|
||||||
|
spec.execute(
|
||||||
|
this.#runQueueWithSkipPolicy.bind(this),
|
||||||
|
this.#globalErrors,
|
||||||
|
done,
|
||||||
|
this.#executionTree.isExcluded(spec),
|
||||||
|
config.failSpecWithNoExpectations,
|
||||||
|
config.detectLateRejectionHandling
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#executeSuiteSegment(suite, segmentNumber, done) {
|
||||||
|
const wrappedChildren = this.#wrapNodes(
|
||||||
|
this.#executionTree.childrenOfSuiteSegment(suite, segmentNumber)
|
||||||
|
);
|
||||||
|
const onStart = {
|
||||||
|
fn: next => {
|
||||||
|
this.#suiteSegmentStart(suite, next);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const queueableFns = [
|
||||||
|
onStart,
|
||||||
|
...this.#addBeforeAndAfterAlls(suite, wrappedChildren)
|
||||||
|
];
|
||||||
|
|
||||||
|
this.#runQueueWithSkipPolicy({
|
||||||
|
// TODO: if onComplete always takes 0-1 arguments (and it probably does)
|
||||||
|
// then it can be switched to an arrow fn with a named arg.
|
||||||
|
onComplete: function() {
|
||||||
|
const args = Array.prototype.slice.call(arguments, [0]);
|
||||||
|
this.#suiteSegmentComplete(suite, suite.getResult(), () => {
|
||||||
|
done.apply(undefined, args);
|
||||||
|
});
|
||||||
|
}.bind(this),
|
||||||
|
queueableFns,
|
||||||
|
userContext: suite.sharedUserContext(),
|
||||||
|
onException: function() {
|
||||||
|
suite.handleException.apply(suite, arguments);
|
||||||
|
},
|
||||||
|
onMultipleDone: suite.onMultipleDone
|
||||||
|
? suite.onMultipleDone.bind(suite)
|
||||||
|
: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#suiteSegmentStart(suite, next) {
|
||||||
|
this.#currentRunableTracker.pushSuite(suite);
|
||||||
|
this.#runableResources.initForRunable(suite.id, suite.parentSuite.id);
|
||||||
|
this.#reportDispatcher.suiteStarted(suite.result).then(next);
|
||||||
|
suite.startTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
#suiteSegmentComplete(suite, result, next) {
|
||||||
|
suite.cleanupBeforeAfter();
|
||||||
|
|
||||||
|
if (suite !== this.#currentRunableTracker.currentSuite()) {
|
||||||
|
throw new Error('Tried to complete the wrong suite');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#runableResources.clearForRunable(suite.id);
|
||||||
|
this.#currentRunableTracker.popSuite();
|
||||||
|
|
||||||
|
if (result.status === 'failed') {
|
||||||
|
this.hasFailures = true;
|
||||||
|
}
|
||||||
|
suite.endTimer();
|
||||||
|
|
||||||
|
if (suite.hadBeforeAllFailure) {
|
||||||
|
this.#reportChildrenOfBeforeAllFailure(suite).then(() => {
|
||||||
|
this.#reportSuiteDone(suite, result, next);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.#reportSuiteDone(suite, result, next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#reportSuiteDone(suite, result, next) {
|
||||||
|
suite.reportedDone = true;
|
||||||
|
this.#reportDispatcher.suiteDone(result).then(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
#addBeforeAndAfterAlls(suite, wrappedChildren) {
|
||||||
|
if (this.#executionTree.isExcluded(suite)) {
|
||||||
|
return wrappedChildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
return suite.beforeAllFns
|
||||||
|
.concat(wrappedChildren)
|
||||||
|
.concat(suite.afterAllFns);
|
||||||
|
}
|
||||||
|
|
||||||
|
#runQueueWithSkipPolicy(options) {
|
||||||
|
if (options.isLeaf) {
|
||||||
|
// A spec
|
||||||
|
options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy;
|
||||||
|
} else {
|
||||||
|
// A suite
|
||||||
|
if (this.#getConfig().stopOnSpecFailure) {
|
||||||
|
options.SkipPolicy = j$.CompleteOnFirstErrorSkipPolicy;
|
||||||
|
} else {
|
||||||
|
options.SkipPolicy = j$.SkipAfterBeforeAllErrorPolicy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.#runQueue(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TreeRunner;
|
||||||
|
};
|
||||||
@@ -84,6 +84,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
|
|||||||
j$.SuiteBuilder = jRequire.SuiteBuilder(j$);
|
j$.SuiteBuilder = jRequire.SuiteBuilder(j$);
|
||||||
j$.Timer = jRequire.Timer();
|
j$.Timer = jRequire.Timer();
|
||||||
j$.TreeProcessor = jRequire.TreeProcessor(j$);
|
j$.TreeProcessor = jRequire.TreeProcessor(j$);
|
||||||
|
j$.TreeRunner = jRequire.TreeRunner(j$);
|
||||||
j$.version = jRequire.version();
|
j$.version = jRequire.version();
|
||||||
j$.Order = jRequire.Order();
|
j$.Order = jRequire.Order();
|
||||||
j$.DiffBuilder = jRequire.DiffBuilder(j$);
|
j$.DiffBuilder = jRequire.DiffBuilder(j$);
|
||||||
|
|||||||
Reference in New Issue
Block a user