Extract tree running out into a separate class

This commit is contained in:
Steve Gravrock
2025-08-18 16:50:04 -07:00
parent a3e1abfa12
commit 63774597f0
6 changed files with 489 additions and 322 deletions

View File

@@ -108,6 +108,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
j$.SuiteBuilder = jRequire.SuiteBuilder(j$);
j$.Timer = jRequire.Timer();
j$.TreeProcessor = jRequire.TreeProcessor(j$);
j$.TreeRunner = jRequire.TreeRunner(j$);
j$.version = jRequire.version();
j$.Order = jRequire.Order();
j$.DiffBuilder = jRequire.DiffBuilder(j$);
@@ -1961,7 +1962,7 @@ getJasmineRequireObj().Env = function(j$) {
function specResultCallback(spec, result, next) {
runableResources.clearForRunable(spec.id);
runner.currentSpec = null;
runner.setCurrentSpec(null);
if (result.status === 'failed') {
runner.hasFailures = true;
@@ -1971,7 +1972,7 @@ getJasmineRequireObj().Env = function(j$) {
}
function specStarted(spec, suite, next) {
runner.currentSpec = spec;
runner.setCurrentSpec(spec);
runableResources.initForRunable(spec.id, suite.id);
reportDispatcher.specStarted(spec.result).then(next);
}
@@ -9413,7 +9414,7 @@ getJasmineRequireObj().Runner = function(j$) {
#getConfig;
#reportSpecDone;
#executedBefore;
#currentlyExecutingSuites;
#currentRunableTracker;
constructor(options) {
this.#topSuite = options.topSuite;
@@ -9428,19 +9429,23 @@ getJasmineRequireObj().Runner = function(j$) {
this.#reportSpecDone = options.reportSpecDone;
this.hasFailures = false;
this.#executedBefore = false;
this.#currentRunableTracker = new CurrentRunableTracker();
}
this.#currentlyExecutingSuites = [];
this.currentSpec = null;
currentSpec() {
return this.#currentRunableTracker.currentSpec();
}
setCurrentSpec(spec) {
this.#currentRunableTracker.setCurrentSpec(spec);
}
currentRunable() {
return this.currentSpec || this.currentSuite();
return this.#currentRunableTracker.currentRunable();
}
currentSuite() {
return this.#currentlyExecutingSuites[
this.#currentlyExecutingSuites.length - 1
];
return this.#currentRunableTracker.currentSuite();
}
parallelReset() {
@@ -9508,15 +9513,28 @@ getJasmineRequireObj().Runner = function(j$) {
parallel: false
});
this.#currentlyExecutingSuites.push(this.#topSuite);
await this.#executeTopSuite();
this.#currentRunableTracker.pushSuite(this.#topSuite);
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) {
await this.#reportChildrenOfBeforeAllFailure(this.#topSuite);
}
this.#runableResources.clearForRunable(this.#topSuite.id);
this.#currentlyExecutingSuites.pop();
this.#currentRunableTracker.popSuite();
let overallStatus, incompleteReason, incompleteCode;
if (
@@ -9563,152 +9581,6 @@ getJasmineRequireObj().Runner = function(j$) {
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) {
for (const child of suite.children) {
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;
};
@@ -11500,16 +11407,18 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
}
class ExecutionTree {
#topSuite;
#stats;
constructor(topSuite, stats) {
this.#topSuite = topSuite;
Object.defineProperty(this, 'topSuite', {
writable: false,
value: topSuite
});
this.#stats = stats;
}
childrenOfTopSuite() {
return this.childrenOfSuiteSegment(this.#topSuite, 0);
return this.childrenOfSuiteSegment(this.topSuite, 0);
}
childrenOfSuiteSegment(suite, segmentNumber) {
@@ -11612,6 +11521,181 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
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$) {
function UserContext() {}

View File

@@ -765,7 +765,7 @@ getJasmineRequireObj().Env = function(j$) {
function specResultCallback(spec, result, next) {
runableResources.clearForRunable(spec.id);
runner.currentSpec = null;
runner.setCurrentSpec(null);
if (result.status === 'failed') {
runner.hasFailures = true;
@@ -775,7 +775,7 @@ getJasmineRequireObj().Env = function(j$) {
}
function specStarted(spec, suite, next) {
runner.currentSpec = spec;
runner.setCurrentSpec(spec);
runableResources.initForRunable(spec.id, suite.id);
reportDispatcher.specStarted(spec.result).then(next);
}

View File

@@ -12,7 +12,7 @@ getJasmineRequireObj().Runner = function(j$) {
#getConfig;
#reportSpecDone;
#executedBefore;
#currentlyExecutingSuites;
#currentRunableTracker;
constructor(options) {
this.#topSuite = options.topSuite;
@@ -27,19 +27,23 @@ getJasmineRequireObj().Runner = function(j$) {
this.#reportSpecDone = options.reportSpecDone;
this.hasFailures = false;
this.#executedBefore = false;
this.#currentRunableTracker = new CurrentRunableTracker();
}
this.#currentlyExecutingSuites = [];
this.currentSpec = null;
currentSpec() {
return this.#currentRunableTracker.currentSpec();
}
setCurrentSpec(spec) {
this.#currentRunableTracker.setCurrentSpec(spec);
}
currentRunable() {
return this.currentSpec || this.currentSuite();
return this.#currentRunableTracker.currentRunable();
}
currentSuite() {
return this.#currentlyExecutingSuites[
this.#currentlyExecutingSuites.length - 1
];
return this.#currentRunableTracker.currentSuite();
}
parallelReset() {
@@ -107,15 +111,28 @@ getJasmineRequireObj().Runner = function(j$) {
parallel: false
});
this.#currentlyExecutingSuites.push(this.#topSuite);
await this.#executeTopSuite();
this.#currentRunableTracker.pushSuite(this.#topSuite);
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) {
await this.#reportChildrenOfBeforeAllFailure(this.#topSuite);
}
this.#runableResources.clearForRunable(this.#topSuite.id);
this.#currentlyExecutingSuites.pop();
this.#currentRunableTracker.popSuite();
let overallStatus, incompleteReason, incompleteCode;
if (
@@ -162,152 +179,6 @@ getJasmineRequireObj().Runner = function(j$) {
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) {
for (const child of suite.children) {
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;
};

View File

@@ -101,16 +101,18 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
}
class ExecutionTree {
#topSuite;
#stats;
constructor(topSuite, stats) {
this.#topSuite = topSuite;
Object.defineProperty(this, 'topSuite', {
writable: false,
value: topSuite
});
this.#stats = stats;
}
childrenOfTopSuite() {
return this.childrenOfSuiteSegment(this.#topSuite, 0);
return this.childrenOfSuiteSegment(this.topSuite, 0);
}
childrenOfSuiteSegment(suite, segmentNumber) {

174
src/core/TreeRunner.js Normal file
View 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;
};

View File

@@ -84,6 +84,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
j$.SuiteBuilder = jRequire.SuiteBuilder(j$);
j$.Timer = jRequire.Timer();
j$.TreeProcessor = jRequire.TreeProcessor(j$);
j$.TreeRunner = jRequire.TreeRunner(j$);
j$.version = jRequire.version();
j$.Order = jRequire.Order();
j$.DiffBuilder = jRequire.DiffBuilder(j$);