Extracted most suite-running code out of Env
This commit is contained in:
@@ -91,6 +91,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
|
|||||||
);
|
);
|
||||||
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
||||||
j$.RunableResources = jRequire.RunableResources(j$);
|
j$.RunableResources = jRequire.RunableResources(j$);
|
||||||
|
j$.Runner = jRequire.Runner(j$);
|
||||||
j$.Spec = jRequire.Spec(j$);
|
j$.Spec = jRequire.Spec(j$);
|
||||||
j$.Spy = jRequire.Spy(j$);
|
j$.Spy = jRequire.Spy(j$);
|
||||||
j$.SpyFactory = jRequire.SpyFactory(j$);
|
j$.SpyFactory = jRequire.SpyFactory(j$);
|
||||||
@@ -791,7 +792,12 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
return this.asyncExpectationFactory(actual, this);
|
return this.asyncExpectationFactory(actual, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
Spec.prototype.execute = function(queueRunnerFactory, onComplete, excluded, failSpecWithNoExp) {
|
Spec.prototype.execute = function(
|
||||||
|
queueRunnerFactory,
|
||||||
|
onComplete,
|
||||||
|
excluded,
|
||||||
|
failSpecWithNoExp
|
||||||
|
) {
|
||||||
const onStart = {
|
const onStart = {
|
||||||
fn: done => {
|
fn: done => {
|
||||||
this.timer.start();
|
this.timer.start();
|
||||||
@@ -1112,15 +1118,13 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const runableResources = new j$.RunableResources(function() {
|
const runableResources = new j$.RunableResources(function() {
|
||||||
const r = currentRunable();
|
const r = runner.currentRunable();
|
||||||
return r ? r.id : null;
|
return r ? r.id : null;
|
||||||
});
|
});
|
||||||
|
|
||||||
let currentSpec = null;
|
|
||||||
const currentlyExecutingSuites = [];
|
|
||||||
let hasFailures = false;
|
|
||||||
let reporter;
|
let reporter;
|
||||||
let topSuite;
|
let topSuite;
|
||||||
|
let runner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents the available options to configure Jasmine.
|
* This represents the available options to configure Jasmine.
|
||||||
@@ -1222,14 +1226,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
verboseDeprecations: false
|
verboseDeprecations: false
|
||||||
};
|
};
|
||||||
|
|
||||||
function currentSuite() {
|
|
||||||
return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
function currentRunable() {
|
|
||||||
return currentSpec || currentSuite();
|
|
||||||
}
|
|
||||||
|
|
||||||
let globalErrors = null;
|
let globalErrors = null;
|
||||||
|
|
||||||
function installGlobalErrors() {
|
function installGlobalErrors() {
|
||||||
@@ -1401,7 +1397,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
function routeLateFailure(expectationResult) {
|
function routeLateFailure(expectationResult) {
|
||||||
// Report the result on the nearest ancestor suite that hasn't already
|
// Report the result on the nearest ancestor suite that hasn't already
|
||||||
// been reported done.
|
// been reported done.
|
||||||
for (let r = currentRunable(); r; r = r.parentSuite) {
|
for (let r = runner.currentRunable(); r; r = r.parentSuite) {
|
||||||
if (!r.reportedDone) {
|
if (!r.reportedDone) {
|
||||||
if (r === topSuite) {
|
if (r === topSuite) {
|
||||||
expectationResult.globalErrorType = 'lateError';
|
expectationResult.globalErrorType = 'lateError';
|
||||||
@@ -1427,7 +1423,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function addExpectationResult(passed, result) {
|
function addExpectationResult(passed, result) {
|
||||||
if (currentRunable() !== spec) {
|
if (runner.currentRunable() !== spec) {
|
||||||
recordLateExpectation(spec, runableType, result);
|
recordLateExpectation(spec, runableType, result);
|
||||||
}
|
}
|
||||||
return spec.addExpectationResult(passed, result);
|
return spec.addExpectationResult(passed, result);
|
||||||
@@ -1457,7 +1453,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @param {Object} [options] Optional extra options, as described above
|
* @param {Object} [options] Optional extra options, as described above
|
||||||
*/
|
*/
|
||||||
this.deprecated = function(deprecation, options) {
|
this.deprecated = function(deprecation, options) {
|
||||||
const runable = currentRunable() || topSuite;
|
const runable = runner.currentRunable() || topSuite;
|
||||||
deprecator.addDeprecationWarning(runable, deprecation, options);
|
deprecator.addDeprecationWarning(runable, deprecation, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1487,7 +1483,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
options.onException =
|
options.onException =
|
||||||
options.onException ||
|
options.onException ||
|
||||||
function(e) {
|
function(e) {
|
||||||
(currentRunable() || topSuite).handleException(e);
|
(runner.currentRunable() || topSuite).handleException(e);
|
||||||
};
|
};
|
||||||
options.deprecated = self.deprecated;
|
options.deprecated = self.deprecated;
|
||||||
|
|
||||||
@@ -1594,6 +1590,17 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
recordLateError
|
recordLateError
|
||||||
);
|
);
|
||||||
|
|
||||||
|
runner = new j$.Runner({
|
||||||
|
topSuite,
|
||||||
|
totalSpecsDefined: () => suiteBuilder.totalSpecsDefined,
|
||||||
|
focusedRunables: () => suiteBuilder.focusedRunables,
|
||||||
|
runableResources,
|
||||||
|
reporter,
|
||||||
|
queueRunnerFactory,
|
||||||
|
getConfig: () => config,
|
||||||
|
reportSpecDone
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the specs.
|
* Executes the specs.
|
||||||
*
|
*
|
||||||
@@ -1626,195 +1633,15 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @return {Promise<JasmineDoneInfo>}
|
* @return {Promise<JasmineDoneInfo>}
|
||||||
*/
|
*/
|
||||||
this.execute = function(runablesToRun, onComplete) {
|
this.execute = function(runablesToRun, onComplete) {
|
||||||
if (this._executedBefore) {
|
|
||||||
topSuite.reset();
|
|
||||||
}
|
|
||||||
this._executedBefore = true;
|
|
||||||
runableResources.initForRunable(topSuite.id);
|
|
||||||
installGlobalErrors();
|
installGlobalErrors();
|
||||||
|
|
||||||
if (!runablesToRun) {
|
return runner.execute(runablesToRun).then(function(jasmineDoneInfo) {
|
||||||
if (suiteBuilder.focusedRunables.length) {
|
if (onComplete) {
|
||||||
runablesToRun = suiteBuilder.focusedRunables;
|
onComplete();
|
||||||
} else {
|
|
||||||
runablesToRun = [topSuite.id];
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const order = new j$.Order({
|
return jasmineDoneInfo;
|
||||||
random: config.random,
|
|
||||||
seed: config.seed
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const processor = new j$.TreeProcessor({
|
|
||||||
tree: topSuite,
|
|
||||||
runnableIds: runablesToRun,
|
|
||||||
queueRunnerFactory: queueRunnerFactory,
|
|
||||||
failSpecWithNoExpectations: config.failSpecWithNoExpectations,
|
|
||||||
nodeStart: function(suite, next) {
|
|
||||||
currentlyExecutingSuites.push(suite);
|
|
||||||
runableResources.initForRunable(suite.id, suite.parentSuite.id);
|
|
||||||
reporter.suiteStarted(suite.result, next);
|
|
||||||
suite.startTimer();
|
|
||||||
},
|
|
||||||
nodeComplete: function(suite, result, next) {
|
|
||||||
if (suite !== currentSuite()) {
|
|
||||||
throw new Error('Tried to complete the wrong suite');
|
|
||||||
}
|
|
||||||
|
|
||||||
runableResources.clearForRunable(suite.id);
|
|
||||||
currentlyExecutingSuites.pop();
|
|
||||||
|
|
||||||
if (result.status === 'failed') {
|
|
||||||
hasFailures = true;
|
|
||||||
}
|
|
||||||
suite.endTimer();
|
|
||||||
|
|
||||||
if (suite.hadBeforeAllFailure) {
|
|
||||||
reportChildrenOfBeforeAllFailure(suite).then(function() {
|
|
||||||
reportSuiteDone(suite, result, next);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
reportSuiteDone(suite, result, next);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
orderChildren: function(node) {
|
|
||||||
return order.sort(node.children);
|
|
||||||
},
|
|
||||||
excludeNode: function(spec) {
|
|
||||||
return !config.specFilter(spec);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!processor.processTree().valid) {
|
|
||||||
throw new Error(
|
|
||||||
'Invalid order: would cause a beforeAll or afterAll to be run multiple times'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const jasmineTimer = new j$.Timer();
|
|
||||||
jasmineTimer.start();
|
|
||||||
|
|
||||||
return new Promise(function(resolve) {
|
|
||||||
runAll(function(jasmineDoneInfo) {
|
|
||||||
if (onComplete) {
|
|
||||||
onComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(jasmineDoneInfo);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function runAll(done) {
|
|
||||||
/**
|
|
||||||
* Information passed to the {@link Reporter#jasmineStarted} event.
|
|
||||||
* @typedef JasmineStartedInfo
|
|
||||||
* @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
|
|
||||||
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
reporter.jasmineStarted(
|
|
||||||
{
|
|
||||||
totalSpecsDefined: suiteBuilder.totalSpecsDefined,
|
|
||||||
order: order
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
currentlyExecutingSuites.push(topSuite);
|
|
||||||
|
|
||||||
processor.execute(function() {
|
|
||||||
(async function() {
|
|
||||||
if (topSuite.hadBeforeAllFailure) {
|
|
||||||
await reportChildrenOfBeforeAllFailure(topSuite);
|
|
||||||
}
|
|
||||||
|
|
||||||
runableResources.clearForRunable(topSuite.id);
|
|
||||||
currentlyExecutingSuites.pop();
|
|
||||||
let overallStatus, incompleteReason;
|
|
||||||
|
|
||||||
if (
|
|
||||||
hasFailures ||
|
|
||||||
topSuite.result.failedExpectations.length > 0
|
|
||||||
) {
|
|
||||||
overallStatus = 'failed';
|
|
||||||
} else if (suiteBuilder.focusedRunables.length > 0) {
|
|
||||||
overallStatus = 'incomplete';
|
|
||||||
incompleteReason = 'fit() or fdescribe() was found';
|
|
||||||
} else if (suiteBuilder.totalSpecsDefined === 0) {
|
|
||||||
overallStatus = 'incomplete';
|
|
||||||
incompleteReason = 'No specs found';
|
|
||||||
} else {
|
|
||||||
overallStatus = 'passed';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Information passed to the {@link Reporter#jasmineDone} event.
|
|
||||||
* @typedef JasmineDoneInfo
|
|
||||||
* @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
|
|
||||||
* @property {Int} totalTime - The total time (in ms) that it took to execute the suite
|
|
||||||
* @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
|
|
||||||
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
|
||||||
* @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
|
|
||||||
* @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
|
|
||||||
* @since 2.4.0
|
|
||||||
*/
|
|
||||||
const jasmineDoneInfo = {
|
|
||||||
overallStatus: overallStatus,
|
|
||||||
totalTime: jasmineTimer.elapsed(),
|
|
||||||
incompleteReason: incompleteReason,
|
|
||||||
order: order,
|
|
||||||
failedExpectations: topSuite.result.failedExpectations,
|
|
||||||
deprecationWarnings: topSuite.result.deprecationWarnings
|
|
||||||
};
|
|
||||||
topSuite.reportedDone = true;
|
|
||||||
reporter.jasmineDone(jasmineDoneInfo, function() {
|
|
||||||
done(jasmineDoneInfo);
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function reportChildrenOfBeforeAllFailure(suite) {
|
|
||||||
for (const child of suite.children) {
|
|
||||||
if (child instanceof j$.Suite) {
|
|
||||||
await new Promise(function(resolve) {
|
|
||||||
reporter.suiteStarted(child.result, resolve);
|
|
||||||
});
|
|
||||||
await reportChildrenOfBeforeAllFailure(child);
|
|
||||||
|
|
||||||
// Marking the suite passed is consistent with how suites that
|
|
||||||
// contain failed specs but no suite-level failures are reported.
|
|
||||||
child.result.status = 'passed';
|
|
||||||
|
|
||||||
await new Promise(function(resolve) {
|
|
||||||
reporter.suiteDone(child.result, resolve);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
/* a spec */
|
|
||||||
await new Promise(function(resolve) {
|
|
||||||
reporter.specStarted(child.result, resolve);
|
|
||||||
});
|
|
||||||
|
|
||||||
child.addExpectationResult(
|
|
||||||
false,
|
|
||||||
{
|
|
||||||
passed: false,
|
|
||||||
message:
|
|
||||||
'Not run because a beforeAll function failed. The ' +
|
|
||||||
'beforeAll failure will be reported on the suite that ' +
|
|
||||||
'caused it.'
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
child.result.status = 'failed';
|
|
||||||
|
|
||||||
await new Promise(function(resolve) {
|
|
||||||
reportSpecDone(child, child.result, resolve);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1898,7 +1725,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function ensureIsNotNested(method) {
|
function ensureIsNotNested(method) {
|
||||||
const runable = currentRunable();
|
const runable = runner.currentRunable();
|
||||||
if (runable !== null && runable !== undefined) {
|
if (runable !== null && runable !== undefined) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'" + method + "' should only be used in 'describe' function"
|
"'" + method + "' should only be used in 'describe' function"
|
||||||
@@ -1923,17 +1750,17 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
function specResultCallback(spec, result, next) {
|
function specResultCallback(spec, result, next) {
|
||||||
runableResources.clearForRunable(spec.id);
|
runableResources.clearForRunable(spec.id);
|
||||||
currentSpec = null;
|
runner.currentSpec = null;
|
||||||
|
|
||||||
if (result.status === 'failed') {
|
if (result.status === 'failed') {
|
||||||
hasFailures = true;
|
runner.hasFailures = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
reportSpecDone(spec, result, next);
|
reportSpecDone(spec, result, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
function specStarted(spec, suite, next) {
|
function specStarted(spec, suite, next) {
|
||||||
currentSpec = spec;
|
runner.currentSpec = spec;
|
||||||
runableResources.initForRunable(spec.id, suite.id);
|
runableResources.initForRunable(spec.id, suite.id);
|
||||||
reporter.specStarted(spec.result, next);
|
reporter.specStarted(spec.result, next);
|
||||||
}
|
}
|
||||||
@@ -1943,11 +1770,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
reporter.specDone(result, next);
|
reporter.specDone(result, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
function reportSuiteDone(suite, result, next) {
|
|
||||||
suite.reportedDone = true;
|
|
||||||
reporter.suiteDone(result, next);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.it = function(description, fn, timeout) {
|
this.it = function(description, fn, timeout) {
|
||||||
ensureIsNotNested('it');
|
ensureIsNotNested('it');
|
||||||
return suiteBuilder.it(description, fn, timeout).metadata;
|
return suiteBuilder.it(description, fn, timeout).metadata;
|
||||||
@@ -1972,12 +1794,15 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @param {*} value The value of the property
|
* @param {*} value The value of the property
|
||||||
*/
|
*/
|
||||||
this.setSpecProperty = function(key, value) {
|
this.setSpecProperty = function(key, value) {
|
||||||
if (!currentRunable() || currentRunable() == currentSuite()) {
|
if (
|
||||||
|
!runner.currentRunable() ||
|
||||||
|
runner.currentRunable() == runner.currentSuite()
|
||||||
|
) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'setSpecProperty' was used when there was no current spec"
|
"'setSpecProperty' was used when there was no current spec"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
currentRunable().setSpecProperty(key, value);
|
runner.currentRunable().setSpecProperty(key, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1989,16 +1814,16 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @param {*} value The value of the property
|
* @param {*} value The value of the property
|
||||||
*/
|
*/
|
||||||
this.setSuiteProperty = function(key, value) {
|
this.setSuiteProperty = function(key, value) {
|
||||||
if (!currentSuite()) {
|
if (!runner.currentSuite()) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'setSuiteProperty' was used when there was no current suite"
|
"'setSuiteProperty' was used when there was no current suite"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
currentSuite().setSuiteProperty(key, value);
|
runner.currentSuite().setSuiteProperty(key, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.debugLog = function(msg) {
|
this.debugLog = function(msg) {
|
||||||
const maybeSpec = currentRunable();
|
const maybeSpec = runner.currentRunable();
|
||||||
|
|
||||||
if (!maybeSpec || !maybeSpec.debugLog) {
|
if (!maybeSpec || !maybeSpec.debugLog) {
|
||||||
throw new Error("'debugLog' was called when there was no current spec");
|
throw new Error("'debugLog' was called when there was no current spec");
|
||||||
@@ -2008,23 +1833,23 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.expect = function(actual) {
|
this.expect = function(actual) {
|
||||||
if (!currentRunable()) {
|
if (!runner.currentRunable()) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'expect' was used when there was no current spec, this could be because an asynchronous test timed out"
|
"'expect' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentRunable().expect(actual);
|
return runner.currentRunable().expect(actual);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.expectAsync = function(actual) {
|
this.expectAsync = function(actual) {
|
||||||
if (!currentRunable()) {
|
if (!runner.currentRunable()) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out"
|
"'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentRunable().expectAsync(actual);
|
return runner.currentRunable().expectAsync(actual);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.beforeEach = function(beforeEachFunction, timeout) {
|
this.beforeEach = function(beforeEachFunction, timeout) {
|
||||||
@@ -2056,7 +1881,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.fail = function(error) {
|
this.fail = function(error) {
|
||||||
if (!currentRunable()) {
|
if (!runner.currentRunable()) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'fail' was used when there was no current spec, this could be because an asynchronous test timed out"
|
"'fail' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||||
);
|
);
|
||||||
@@ -2076,7 +1901,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRunable().addExpectationResult(false, {
|
runner.currentRunable().addExpectationResult(false, {
|
||||||
matcherName: '',
|
matcherName: '',
|
||||||
passed: false,
|
passed: false,
|
||||||
expected: '',
|
expected: '',
|
||||||
@@ -8422,6 +8247,233 @@ getJasmineRequireObj().RunableResources = function(j$) {
|
|||||||
return RunableResources;
|
return RunableResources;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getJasmineRequireObj().Runner = function(j$) {
|
||||||
|
class Runner {
|
||||||
|
constructor(options) {
|
||||||
|
this.topSuite_ = options.topSuite;
|
||||||
|
this.totalSpecsDefined_ = options.totalSpecsDefined;
|
||||||
|
this.focusedRunables_ = options.focusedRunables;
|
||||||
|
this.runableResources_ = options.runableResources;
|
||||||
|
this.queueRunnerFactory_ = options.queueRunnerFactory;
|
||||||
|
this.reporter_ = options.reporter;
|
||||||
|
this.getConfig_ = options.getConfig;
|
||||||
|
this.reportSpecDone_ = options.reportSpecDone;
|
||||||
|
this.hasFailures = false;
|
||||||
|
this.executedBefore_ = false;
|
||||||
|
|
||||||
|
this.currentlyExecutingSuites_ = [];
|
||||||
|
this.currentSpec = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRunable() {
|
||||||
|
return this.currentSpec || this.currentSuite();
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSuite() {
|
||||||
|
return this.currentlyExecutingSuites_[
|
||||||
|
this.currentlyExecutingSuites_.length - 1
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Although execute returns a promise, it isn't async for backwards
|
||||||
|
// compatibility: The "Invalid order" exception needs to be propagated
|
||||||
|
// synchronously from Env#execute.
|
||||||
|
// TODO: make this and Env#execute async in the next major release
|
||||||
|
execute(runablesToRun) {
|
||||||
|
if (this.executedBefore_) {
|
||||||
|
this.topSuite_.reset();
|
||||||
|
}
|
||||||
|
this.executedBefore_ = true;
|
||||||
|
|
||||||
|
this.hasFailures = false;
|
||||||
|
const totalSpecsDefined = this.totalSpecsDefined_();
|
||||||
|
const focusedRunables = this.focusedRunables_();
|
||||||
|
const config = this.getConfig_();
|
||||||
|
|
||||||
|
if (!runablesToRun) {
|
||||||
|
if (focusedRunables.length) {
|
||||||
|
runablesToRun = focusedRunables;
|
||||||
|
} else {
|
||||||
|
runablesToRun = [this.topSuite_.id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const order = new j$.Order({
|
||||||
|
random: config.random,
|
||||||
|
seed: config.seed
|
||||||
|
});
|
||||||
|
|
||||||
|
const processor = new j$.TreeProcessor({
|
||||||
|
tree: this.topSuite_,
|
||||||
|
runnableIds: runablesToRun,
|
||||||
|
queueRunnerFactory: this.queueRunnerFactory_,
|
||||||
|
failSpecWithNoExpectations: config.failSpecWithNoExpectations,
|
||||||
|
nodeStart: (suite, next) => {
|
||||||
|
this.currentlyExecutingSuites_.push(suite);
|
||||||
|
this.runableResources_.initForRunable(suite.id, suite.parentSuite.id);
|
||||||
|
this.reporter_.suiteStarted(suite.result, next);
|
||||||
|
suite.startTimer();
|
||||||
|
},
|
||||||
|
nodeComplete: (suite, result, next) => {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
orderChildren: function(node) {
|
||||||
|
return order.sort(node.children);
|
||||||
|
},
|
||||||
|
excludeNode: function(spec) {
|
||||||
|
return !config.specFilter(spec);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!processor.processTree().valid) {
|
||||||
|
throw new Error(
|
||||||
|
'Invalid order: would cause a beforeAll or afterAll to be run multiple times'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.runableResources_.initForRunable(this.topSuite_.id);
|
||||||
|
const jasmineTimer = new j$.Timer();
|
||||||
|
jasmineTimer.start();
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
/**
|
||||||
|
* Information passed to the {@link Reporter#jasmineStarted} event.
|
||||||
|
* @typedef JasmineStartedInfo
|
||||||
|
* @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
|
||||||
|
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
this.reporter_.jasmineStarted(
|
||||||
|
{
|
||||||
|
totalSpecsDefined,
|
||||||
|
order: order
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.currentlyExecutingSuites_.push(this.topSuite_);
|
||||||
|
|
||||||
|
processor.execute(() => {
|
||||||
|
(async () => {
|
||||||
|
if (this.topSuite_.hadBeforeAllFailure) {
|
||||||
|
await this.reportChildrenOfBeforeAllFailure_(this.topSuite_);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.runableResources_.clearForRunable(this.topSuite_.id);
|
||||||
|
this.currentlyExecutingSuites_.pop();
|
||||||
|
let overallStatus, incompleteReason;
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.hasFailures ||
|
||||||
|
this.topSuite_.result.failedExpectations.length > 0
|
||||||
|
) {
|
||||||
|
overallStatus = 'failed';
|
||||||
|
} else if (focusedRunables.length > 0) {
|
||||||
|
overallStatus = 'incomplete';
|
||||||
|
incompleteReason = 'fit() or fdescribe() was found';
|
||||||
|
} else if (totalSpecsDefined === 0) {
|
||||||
|
overallStatus = 'incomplete';
|
||||||
|
incompleteReason = 'No specs found';
|
||||||
|
} else {
|
||||||
|
overallStatus = 'passed';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information passed to the {@link Reporter#jasmineDone} event.
|
||||||
|
* @typedef JasmineDoneInfo
|
||||||
|
* @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
|
||||||
|
* @property {Int} totalTime - The total time (in ms) that it took to execute the suite
|
||||||
|
* @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
|
||||||
|
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
||||||
|
* @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
|
||||||
|
* @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
const jasmineDoneInfo = {
|
||||||
|
overallStatus: overallStatus,
|
||||||
|
totalTime: jasmineTimer.elapsed(),
|
||||||
|
incompleteReason: incompleteReason,
|
||||||
|
order: order,
|
||||||
|
failedExpectations: this.topSuite_.result.failedExpectations,
|
||||||
|
deprecationWarnings: this.topSuite_.result.deprecationWarnings
|
||||||
|
};
|
||||||
|
this.topSuite_.reportedDone = true;
|
||||||
|
this.reporter_.jasmineDone(jasmineDoneInfo, function() {
|
||||||
|
resolve(jasmineDoneInfo);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
reportSuiteDone_(suite, result, next) {
|
||||||
|
suite.reportedDone = true;
|
||||||
|
this.reporter_.suiteDone(result, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
async reportChildrenOfBeforeAllFailure_(suite) {
|
||||||
|
for (const child of suite.children) {
|
||||||
|
if (child instanceof j$.Suite) {
|
||||||
|
await new Promise(resolve => {
|
||||||
|
this.reporter_.suiteStarted(child.result, resolve);
|
||||||
|
});
|
||||||
|
await this.reportChildrenOfBeforeAllFailure_(child);
|
||||||
|
|
||||||
|
// Marking the suite passed is consistent with how suites that
|
||||||
|
// contain failed specs but no suite-level failures are reported.
|
||||||
|
child.result.status = 'passed';
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
this.reporter_.suiteDone(child.result, resolve);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
/* a spec */
|
||||||
|
await new Promise(resolve => {
|
||||||
|
this.reporter_.specStarted(child.result, resolve);
|
||||||
|
});
|
||||||
|
|
||||||
|
child.addExpectationResult(
|
||||||
|
false,
|
||||||
|
{
|
||||||
|
passed: false,
|
||||||
|
message:
|
||||||
|
'Not run because a beforeAll function failed. The ' +
|
||||||
|
'beforeAll failure will be reported on the suite that ' +
|
||||||
|
'caused it.'
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
child.result.status = 'failed';
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
this.reportSpecDone_(child, child.result, resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Runner;
|
||||||
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) {
|
getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) {
|
||||||
function SkipAfterBeforeAllErrorPolicy(queueableFns) {
|
function SkipAfterBeforeAllErrorPolicy(queueableFns) {
|
||||||
this.queueableFns_ = queueableFns;
|
this.queueableFns_ = queueableFns;
|
||||||
|
|||||||
259
src/core/Env.js
259
src/core/Env.js
@@ -25,15 +25,13 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const runableResources = new j$.RunableResources(function() {
|
const runableResources = new j$.RunableResources(function() {
|
||||||
const r = currentRunable();
|
const r = runner.currentRunable();
|
||||||
return r ? r.id : null;
|
return r ? r.id : null;
|
||||||
});
|
});
|
||||||
|
|
||||||
let currentSpec = null;
|
|
||||||
const currentlyExecutingSuites = [];
|
|
||||||
let hasFailures = false;
|
|
||||||
let reporter;
|
let reporter;
|
||||||
let topSuite;
|
let topSuite;
|
||||||
|
let runner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This represents the available options to configure Jasmine.
|
* This represents the available options to configure Jasmine.
|
||||||
@@ -135,14 +133,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
verboseDeprecations: false
|
verboseDeprecations: false
|
||||||
};
|
};
|
||||||
|
|
||||||
function currentSuite() {
|
|
||||||
return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
function currentRunable() {
|
|
||||||
return currentSpec || currentSuite();
|
|
||||||
}
|
|
||||||
|
|
||||||
let globalErrors = null;
|
let globalErrors = null;
|
||||||
|
|
||||||
function installGlobalErrors() {
|
function installGlobalErrors() {
|
||||||
@@ -314,7 +304,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
function routeLateFailure(expectationResult) {
|
function routeLateFailure(expectationResult) {
|
||||||
// Report the result on the nearest ancestor suite that hasn't already
|
// Report the result on the nearest ancestor suite that hasn't already
|
||||||
// been reported done.
|
// been reported done.
|
||||||
for (let r = currentRunable(); r; r = r.parentSuite) {
|
for (let r = runner.currentRunable(); r; r = r.parentSuite) {
|
||||||
if (!r.reportedDone) {
|
if (!r.reportedDone) {
|
||||||
if (r === topSuite) {
|
if (r === topSuite) {
|
||||||
expectationResult.globalErrorType = 'lateError';
|
expectationResult.globalErrorType = 'lateError';
|
||||||
@@ -340,7 +330,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function addExpectationResult(passed, result) {
|
function addExpectationResult(passed, result) {
|
||||||
if (currentRunable() !== spec) {
|
if (runner.currentRunable() !== spec) {
|
||||||
recordLateExpectation(spec, runableType, result);
|
recordLateExpectation(spec, runableType, result);
|
||||||
}
|
}
|
||||||
return spec.addExpectationResult(passed, result);
|
return spec.addExpectationResult(passed, result);
|
||||||
@@ -370,7 +360,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @param {Object} [options] Optional extra options, as described above
|
* @param {Object} [options] Optional extra options, as described above
|
||||||
*/
|
*/
|
||||||
this.deprecated = function(deprecation, options) {
|
this.deprecated = function(deprecation, options) {
|
||||||
const runable = currentRunable() || topSuite;
|
const runable = runner.currentRunable() || topSuite;
|
||||||
deprecator.addDeprecationWarning(runable, deprecation, options);
|
deprecator.addDeprecationWarning(runable, deprecation, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -400,7 +390,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
options.onException =
|
options.onException =
|
||||||
options.onException ||
|
options.onException ||
|
||||||
function(e) {
|
function(e) {
|
||||||
(currentRunable() || topSuite).handleException(e);
|
(runner.currentRunable() || topSuite).handleException(e);
|
||||||
};
|
};
|
||||||
options.deprecated = self.deprecated;
|
options.deprecated = self.deprecated;
|
||||||
|
|
||||||
@@ -507,6 +497,17 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
recordLateError
|
recordLateError
|
||||||
);
|
);
|
||||||
|
|
||||||
|
runner = new j$.Runner({
|
||||||
|
topSuite,
|
||||||
|
totalSpecsDefined: () => suiteBuilder.totalSpecsDefined,
|
||||||
|
focusedRunables: () => suiteBuilder.focusedRunables,
|
||||||
|
runableResources,
|
||||||
|
reporter,
|
||||||
|
queueRunnerFactory,
|
||||||
|
getConfig: () => config,
|
||||||
|
reportSpecDone
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the specs.
|
* Executes the specs.
|
||||||
*
|
*
|
||||||
@@ -539,195 +540,15 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @return {Promise<JasmineDoneInfo>}
|
* @return {Promise<JasmineDoneInfo>}
|
||||||
*/
|
*/
|
||||||
this.execute = function(runablesToRun, onComplete) {
|
this.execute = function(runablesToRun, onComplete) {
|
||||||
if (this._executedBefore) {
|
|
||||||
topSuite.reset();
|
|
||||||
}
|
|
||||||
this._executedBefore = true;
|
|
||||||
runableResources.initForRunable(topSuite.id);
|
|
||||||
installGlobalErrors();
|
installGlobalErrors();
|
||||||
|
|
||||||
if (!runablesToRun) {
|
return runner.execute(runablesToRun).then(function(jasmineDoneInfo) {
|
||||||
if (suiteBuilder.focusedRunables.length) {
|
if (onComplete) {
|
||||||
runablesToRun = suiteBuilder.focusedRunables;
|
onComplete();
|
||||||
} else {
|
|
||||||
runablesToRun = [topSuite.id];
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const order = new j$.Order({
|
return jasmineDoneInfo;
|
||||||
random: config.random,
|
|
||||||
seed: config.seed
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const processor = new j$.TreeProcessor({
|
|
||||||
tree: topSuite,
|
|
||||||
runnableIds: runablesToRun,
|
|
||||||
queueRunnerFactory: queueRunnerFactory,
|
|
||||||
failSpecWithNoExpectations: config.failSpecWithNoExpectations,
|
|
||||||
nodeStart: function(suite, next) {
|
|
||||||
currentlyExecutingSuites.push(suite);
|
|
||||||
runableResources.initForRunable(suite.id, suite.parentSuite.id);
|
|
||||||
reporter.suiteStarted(suite.result, next);
|
|
||||||
suite.startTimer();
|
|
||||||
},
|
|
||||||
nodeComplete: function(suite, result, next) {
|
|
||||||
if (suite !== currentSuite()) {
|
|
||||||
throw new Error('Tried to complete the wrong suite');
|
|
||||||
}
|
|
||||||
|
|
||||||
runableResources.clearForRunable(suite.id);
|
|
||||||
currentlyExecutingSuites.pop();
|
|
||||||
|
|
||||||
if (result.status === 'failed') {
|
|
||||||
hasFailures = true;
|
|
||||||
}
|
|
||||||
suite.endTimer();
|
|
||||||
|
|
||||||
if (suite.hadBeforeAllFailure) {
|
|
||||||
reportChildrenOfBeforeAllFailure(suite).then(function() {
|
|
||||||
reportSuiteDone(suite, result, next);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
reportSuiteDone(suite, result, next);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
orderChildren: function(node) {
|
|
||||||
return order.sort(node.children);
|
|
||||||
},
|
|
||||||
excludeNode: function(spec) {
|
|
||||||
return !config.specFilter(spec);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!processor.processTree().valid) {
|
|
||||||
throw new Error(
|
|
||||||
'Invalid order: would cause a beforeAll or afterAll to be run multiple times'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const jasmineTimer = new j$.Timer();
|
|
||||||
jasmineTimer.start();
|
|
||||||
|
|
||||||
return new Promise(function(resolve) {
|
|
||||||
runAll(function(jasmineDoneInfo) {
|
|
||||||
if (onComplete) {
|
|
||||||
onComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(jasmineDoneInfo);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function runAll(done) {
|
|
||||||
/**
|
|
||||||
* Information passed to the {@link Reporter#jasmineStarted} event.
|
|
||||||
* @typedef JasmineStartedInfo
|
|
||||||
* @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
|
|
||||||
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
reporter.jasmineStarted(
|
|
||||||
{
|
|
||||||
totalSpecsDefined: suiteBuilder.totalSpecsDefined,
|
|
||||||
order: order
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
currentlyExecutingSuites.push(topSuite);
|
|
||||||
|
|
||||||
processor.execute(function() {
|
|
||||||
(async function() {
|
|
||||||
if (topSuite.hadBeforeAllFailure) {
|
|
||||||
await reportChildrenOfBeforeAllFailure(topSuite);
|
|
||||||
}
|
|
||||||
|
|
||||||
runableResources.clearForRunable(topSuite.id);
|
|
||||||
currentlyExecutingSuites.pop();
|
|
||||||
let overallStatus, incompleteReason;
|
|
||||||
|
|
||||||
if (
|
|
||||||
hasFailures ||
|
|
||||||
topSuite.result.failedExpectations.length > 0
|
|
||||||
) {
|
|
||||||
overallStatus = 'failed';
|
|
||||||
} else if (suiteBuilder.focusedRunables.length > 0) {
|
|
||||||
overallStatus = 'incomplete';
|
|
||||||
incompleteReason = 'fit() or fdescribe() was found';
|
|
||||||
} else if (suiteBuilder.totalSpecsDefined === 0) {
|
|
||||||
overallStatus = 'incomplete';
|
|
||||||
incompleteReason = 'No specs found';
|
|
||||||
} else {
|
|
||||||
overallStatus = 'passed';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Information passed to the {@link Reporter#jasmineDone} event.
|
|
||||||
* @typedef JasmineDoneInfo
|
|
||||||
* @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
|
|
||||||
* @property {Int} totalTime - The total time (in ms) that it took to execute the suite
|
|
||||||
* @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
|
|
||||||
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
|
||||||
* @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
|
|
||||||
* @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
|
|
||||||
* @since 2.4.0
|
|
||||||
*/
|
|
||||||
const jasmineDoneInfo = {
|
|
||||||
overallStatus: overallStatus,
|
|
||||||
totalTime: jasmineTimer.elapsed(),
|
|
||||||
incompleteReason: incompleteReason,
|
|
||||||
order: order,
|
|
||||||
failedExpectations: topSuite.result.failedExpectations,
|
|
||||||
deprecationWarnings: topSuite.result.deprecationWarnings
|
|
||||||
};
|
|
||||||
topSuite.reportedDone = true;
|
|
||||||
reporter.jasmineDone(jasmineDoneInfo, function() {
|
|
||||||
done(jasmineDoneInfo);
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function reportChildrenOfBeforeAllFailure(suite) {
|
|
||||||
for (const child of suite.children) {
|
|
||||||
if (child instanceof j$.Suite) {
|
|
||||||
await new Promise(function(resolve) {
|
|
||||||
reporter.suiteStarted(child.result, resolve);
|
|
||||||
});
|
|
||||||
await reportChildrenOfBeforeAllFailure(child);
|
|
||||||
|
|
||||||
// Marking the suite passed is consistent with how suites that
|
|
||||||
// contain failed specs but no suite-level failures are reported.
|
|
||||||
child.result.status = 'passed';
|
|
||||||
|
|
||||||
await new Promise(function(resolve) {
|
|
||||||
reporter.suiteDone(child.result, resolve);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
/* a spec */
|
|
||||||
await new Promise(function(resolve) {
|
|
||||||
reporter.specStarted(child.result, resolve);
|
|
||||||
});
|
|
||||||
|
|
||||||
child.addExpectationResult(
|
|
||||||
false,
|
|
||||||
{
|
|
||||||
passed: false,
|
|
||||||
message:
|
|
||||||
'Not run because a beforeAll function failed. The ' +
|
|
||||||
'beforeAll failure will be reported on the suite that ' +
|
|
||||||
'caused it.'
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
child.result.status = 'failed';
|
|
||||||
|
|
||||||
await new Promise(function(resolve) {
|
|
||||||
reportSpecDone(child, child.result, resolve);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -811,7 +632,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function ensureIsNotNested(method) {
|
function ensureIsNotNested(method) {
|
||||||
const runable = currentRunable();
|
const runable = runner.currentRunable();
|
||||||
if (runable !== null && runable !== undefined) {
|
if (runable !== null && runable !== undefined) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'" + method + "' should only be used in 'describe' function"
|
"'" + method + "' should only be used in 'describe' function"
|
||||||
@@ -836,17 +657,17 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
|
|
||||||
function specResultCallback(spec, result, next) {
|
function specResultCallback(spec, result, next) {
|
||||||
runableResources.clearForRunable(spec.id);
|
runableResources.clearForRunable(spec.id);
|
||||||
currentSpec = null;
|
runner.currentSpec = null;
|
||||||
|
|
||||||
if (result.status === 'failed') {
|
if (result.status === 'failed') {
|
||||||
hasFailures = true;
|
runner.hasFailures = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
reportSpecDone(spec, result, next);
|
reportSpecDone(spec, result, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
function specStarted(spec, suite, next) {
|
function specStarted(spec, suite, next) {
|
||||||
currentSpec = spec;
|
runner.currentSpec = spec;
|
||||||
runableResources.initForRunable(spec.id, suite.id);
|
runableResources.initForRunable(spec.id, suite.id);
|
||||||
reporter.specStarted(spec.result, next);
|
reporter.specStarted(spec.result, next);
|
||||||
}
|
}
|
||||||
@@ -856,11 +677,6 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
reporter.specDone(result, next);
|
reporter.specDone(result, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
function reportSuiteDone(suite, result, next) {
|
|
||||||
suite.reportedDone = true;
|
|
||||||
reporter.suiteDone(result, next);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.it = function(description, fn, timeout) {
|
this.it = function(description, fn, timeout) {
|
||||||
ensureIsNotNested('it');
|
ensureIsNotNested('it');
|
||||||
return suiteBuilder.it(description, fn, timeout).metadata;
|
return suiteBuilder.it(description, fn, timeout).metadata;
|
||||||
@@ -885,12 +701,15 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @param {*} value The value of the property
|
* @param {*} value The value of the property
|
||||||
*/
|
*/
|
||||||
this.setSpecProperty = function(key, value) {
|
this.setSpecProperty = function(key, value) {
|
||||||
if (!currentRunable() || currentRunable() == currentSuite()) {
|
if (
|
||||||
|
!runner.currentRunable() ||
|
||||||
|
runner.currentRunable() == runner.currentSuite()
|
||||||
|
) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'setSpecProperty' was used when there was no current spec"
|
"'setSpecProperty' was used when there was no current spec"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
currentRunable().setSpecProperty(key, value);
|
runner.currentRunable().setSpecProperty(key, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -902,16 +721,16 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
* @param {*} value The value of the property
|
* @param {*} value The value of the property
|
||||||
*/
|
*/
|
||||||
this.setSuiteProperty = function(key, value) {
|
this.setSuiteProperty = function(key, value) {
|
||||||
if (!currentSuite()) {
|
if (!runner.currentSuite()) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'setSuiteProperty' was used when there was no current suite"
|
"'setSuiteProperty' was used when there was no current suite"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
currentSuite().setSuiteProperty(key, value);
|
runner.currentSuite().setSuiteProperty(key, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.debugLog = function(msg) {
|
this.debugLog = function(msg) {
|
||||||
const maybeSpec = currentRunable();
|
const maybeSpec = runner.currentRunable();
|
||||||
|
|
||||||
if (!maybeSpec || !maybeSpec.debugLog) {
|
if (!maybeSpec || !maybeSpec.debugLog) {
|
||||||
throw new Error("'debugLog' was called when there was no current spec");
|
throw new Error("'debugLog' was called when there was no current spec");
|
||||||
@@ -921,23 +740,23 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.expect = function(actual) {
|
this.expect = function(actual) {
|
||||||
if (!currentRunable()) {
|
if (!runner.currentRunable()) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'expect' was used when there was no current spec, this could be because an asynchronous test timed out"
|
"'expect' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentRunable().expect(actual);
|
return runner.currentRunable().expect(actual);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.expectAsync = function(actual) {
|
this.expectAsync = function(actual) {
|
||||||
if (!currentRunable()) {
|
if (!runner.currentRunable()) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out"
|
"'expectAsync' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentRunable().expectAsync(actual);
|
return runner.currentRunable().expectAsync(actual);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.beforeEach = function(beforeEachFunction, timeout) {
|
this.beforeEach = function(beforeEachFunction, timeout) {
|
||||||
@@ -969,7 +788,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.fail = function(error) {
|
this.fail = function(error) {
|
||||||
if (!currentRunable()) {
|
if (!runner.currentRunable()) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"'fail' was used when there was no current spec, this could be because an asynchronous test timed out"
|
"'fail' was used when there was no current spec, this could be because an asynchronous test timed out"
|
||||||
);
|
);
|
||||||
@@ -989,7 +808,7 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRunable().addExpectationResult(false, {
|
runner.currentRunable().addExpectationResult(false, {
|
||||||
matcherName: '',
|
matcherName: '',
|
||||||
passed: false,
|
passed: false,
|
||||||
expected: '',
|
expected: '',
|
||||||
|
|||||||
226
src/core/Runner.js
Normal file
226
src/core/Runner.js
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
getJasmineRequireObj().Runner = function(j$) {
|
||||||
|
class Runner {
|
||||||
|
constructor(options) {
|
||||||
|
this.topSuite_ = options.topSuite;
|
||||||
|
this.totalSpecsDefined_ = options.totalSpecsDefined;
|
||||||
|
this.focusedRunables_ = options.focusedRunables;
|
||||||
|
this.runableResources_ = options.runableResources;
|
||||||
|
this.queueRunnerFactory_ = options.queueRunnerFactory;
|
||||||
|
this.reporter_ = options.reporter;
|
||||||
|
this.getConfig_ = options.getConfig;
|
||||||
|
this.reportSpecDone_ = options.reportSpecDone;
|
||||||
|
this.hasFailures = false;
|
||||||
|
this.executedBefore_ = false;
|
||||||
|
|
||||||
|
this.currentlyExecutingSuites_ = [];
|
||||||
|
this.currentSpec = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRunable() {
|
||||||
|
return this.currentSpec || this.currentSuite();
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSuite() {
|
||||||
|
return this.currentlyExecutingSuites_[
|
||||||
|
this.currentlyExecutingSuites_.length - 1
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Although execute returns a promise, it isn't async for backwards
|
||||||
|
// compatibility: The "Invalid order" exception needs to be propagated
|
||||||
|
// synchronously from Env#execute.
|
||||||
|
// TODO: make this and Env#execute async in the next major release
|
||||||
|
execute(runablesToRun) {
|
||||||
|
if (this.executedBefore_) {
|
||||||
|
this.topSuite_.reset();
|
||||||
|
}
|
||||||
|
this.executedBefore_ = true;
|
||||||
|
|
||||||
|
this.hasFailures = false;
|
||||||
|
const totalSpecsDefined = this.totalSpecsDefined_();
|
||||||
|
const focusedRunables = this.focusedRunables_();
|
||||||
|
const config = this.getConfig_();
|
||||||
|
|
||||||
|
if (!runablesToRun) {
|
||||||
|
if (focusedRunables.length) {
|
||||||
|
runablesToRun = focusedRunables;
|
||||||
|
} else {
|
||||||
|
runablesToRun = [this.topSuite_.id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const order = new j$.Order({
|
||||||
|
random: config.random,
|
||||||
|
seed: config.seed
|
||||||
|
});
|
||||||
|
|
||||||
|
const processor = new j$.TreeProcessor({
|
||||||
|
tree: this.topSuite_,
|
||||||
|
runnableIds: runablesToRun,
|
||||||
|
queueRunnerFactory: this.queueRunnerFactory_,
|
||||||
|
failSpecWithNoExpectations: config.failSpecWithNoExpectations,
|
||||||
|
nodeStart: (suite, next) => {
|
||||||
|
this.currentlyExecutingSuites_.push(suite);
|
||||||
|
this.runableResources_.initForRunable(suite.id, suite.parentSuite.id);
|
||||||
|
this.reporter_.suiteStarted(suite.result, next);
|
||||||
|
suite.startTimer();
|
||||||
|
},
|
||||||
|
nodeComplete: (suite, result, next) => {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
orderChildren: function(node) {
|
||||||
|
return order.sort(node.children);
|
||||||
|
},
|
||||||
|
excludeNode: function(spec) {
|
||||||
|
return !config.specFilter(spec);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!processor.processTree().valid) {
|
||||||
|
throw new Error(
|
||||||
|
'Invalid order: would cause a beforeAll or afterAll to be run multiple times'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.runableResources_.initForRunable(this.topSuite_.id);
|
||||||
|
const jasmineTimer = new j$.Timer();
|
||||||
|
jasmineTimer.start();
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
/**
|
||||||
|
* Information passed to the {@link Reporter#jasmineStarted} event.
|
||||||
|
* @typedef JasmineStartedInfo
|
||||||
|
* @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
|
||||||
|
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
|
this.reporter_.jasmineStarted(
|
||||||
|
{
|
||||||
|
totalSpecsDefined,
|
||||||
|
order: order
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.currentlyExecutingSuites_.push(this.topSuite_);
|
||||||
|
|
||||||
|
processor.execute(() => {
|
||||||
|
(async () => {
|
||||||
|
if (this.topSuite_.hadBeforeAllFailure) {
|
||||||
|
await this.reportChildrenOfBeforeAllFailure_(this.topSuite_);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.runableResources_.clearForRunable(this.topSuite_.id);
|
||||||
|
this.currentlyExecutingSuites_.pop();
|
||||||
|
let overallStatus, incompleteReason;
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.hasFailures ||
|
||||||
|
this.topSuite_.result.failedExpectations.length > 0
|
||||||
|
) {
|
||||||
|
overallStatus = 'failed';
|
||||||
|
} else if (focusedRunables.length > 0) {
|
||||||
|
overallStatus = 'incomplete';
|
||||||
|
incompleteReason = 'fit() or fdescribe() was found';
|
||||||
|
} else if (totalSpecsDefined === 0) {
|
||||||
|
overallStatus = 'incomplete';
|
||||||
|
incompleteReason = 'No specs found';
|
||||||
|
} else {
|
||||||
|
overallStatus = 'passed';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information passed to the {@link Reporter#jasmineDone} event.
|
||||||
|
* @typedef JasmineDoneInfo
|
||||||
|
* @property {OverallStatus} overallStatus - The overall result of the suite: 'passed', 'failed', or 'incomplete'.
|
||||||
|
* @property {Int} totalTime - The total time (in ms) that it took to execute the suite
|
||||||
|
* @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
|
||||||
|
* @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
|
||||||
|
* @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
|
||||||
|
* @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
|
||||||
|
* @since 2.4.0
|
||||||
|
*/
|
||||||
|
const jasmineDoneInfo = {
|
||||||
|
overallStatus: overallStatus,
|
||||||
|
totalTime: jasmineTimer.elapsed(),
|
||||||
|
incompleteReason: incompleteReason,
|
||||||
|
order: order,
|
||||||
|
failedExpectations: this.topSuite_.result.failedExpectations,
|
||||||
|
deprecationWarnings: this.topSuite_.result.deprecationWarnings
|
||||||
|
};
|
||||||
|
this.topSuite_.reportedDone = true;
|
||||||
|
this.reporter_.jasmineDone(jasmineDoneInfo, function() {
|
||||||
|
resolve(jasmineDoneInfo);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
reportSuiteDone_(suite, result, next) {
|
||||||
|
suite.reportedDone = true;
|
||||||
|
this.reporter_.suiteDone(result, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
async reportChildrenOfBeforeAllFailure_(suite) {
|
||||||
|
for (const child of suite.children) {
|
||||||
|
if (child instanceof j$.Suite) {
|
||||||
|
await new Promise(resolve => {
|
||||||
|
this.reporter_.suiteStarted(child.result, resolve);
|
||||||
|
});
|
||||||
|
await this.reportChildrenOfBeforeAllFailure_(child);
|
||||||
|
|
||||||
|
// Marking the suite passed is consistent with how suites that
|
||||||
|
// contain failed specs but no suite-level failures are reported.
|
||||||
|
child.result.status = 'passed';
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
this.reporter_.suiteDone(child.result, resolve);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
/* a spec */
|
||||||
|
await new Promise(resolve => {
|
||||||
|
this.reporter_.specStarted(child.result, resolve);
|
||||||
|
});
|
||||||
|
|
||||||
|
child.addExpectationResult(
|
||||||
|
false,
|
||||||
|
{
|
||||||
|
passed: false,
|
||||||
|
message:
|
||||||
|
'Not run because a beforeAll function failed. The ' +
|
||||||
|
'beforeAll failure will be reported on the suite that ' +
|
||||||
|
'caused it.'
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
child.result.status = 'failed';
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
this.reportSpecDone_(child, child.result, resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Runner;
|
||||||
|
};
|
||||||
@@ -69,6 +69,7 @@ var getJasmineRequireObj = (function(jasmineGlobal) {
|
|||||||
);
|
);
|
||||||
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
|
||||||
j$.RunableResources = jRequire.RunableResources(j$);
|
j$.RunableResources = jRequire.RunableResources(j$);
|
||||||
|
j$.Runner = jRequire.Runner(j$);
|
||||||
j$.Spec = jRequire.Spec(j$);
|
j$.Spec = jRequire.Spec(j$);
|
||||||
j$.Spy = jRequire.Spy(j$);
|
j$.Spy = jRequire.Spy(j$);
|
||||||
j$.SpyFactory = jRequire.SpyFactory(j$);
|
j$.SpyFactory = jRequire.SpyFactory(j$);
|
||||||
|
|||||||
Reference in New Issue
Block a user