Report start and end events for specs/suites that are skipped due to a beforeAll error

This is noisier, but it maintains compatibility with reporters that assume
(quite reasonably) that all specs and suites are either filtered out or
reported.
This commit is contained in:
Steve Gravrock
2021-12-11 12:34:23 -08:00
parent f1cf6ee419
commit 0b1385c3d3
7 changed files with 397 additions and 95 deletions

View File

@@ -729,7 +729,14 @@ getJasmineRequireObj().Env = function(j$) {
hasFailures = true;
}
suite.endTimer();
reporter.suiteDone(result, next);
if (suite.hadBeforeAllFailure) {
reportChildrenOfBeforeAllFailure(suite).then(function() {
reporter.suiteDone(result, next);
});
} else {
reporter.suiteDone(result, next);
}
},
orderChildren: function(node) {
return order.sort(node.children);
@@ -775,51 +782,92 @@ getJasmineRequireObj().Env = function(j$) {
currentlyExecutingSuites.push(topSuite);
processor.execute(function() {
clearResourcesForRunnable(topSuite.id);
currentlyExecutingSuites.pop();
var overallStatus, incompleteReason;
(async function() {
if (topSuite.hadBeforeAllFailure) {
await reportChildrenOfBeforeAllFailure(topSuite);
}
if (
hasFailures ||
topSuite.result.failedExpectations.length > 0
) {
overallStatus = 'failed';
} else if (focusedRunnables.length > 0) {
overallStatus = 'incomplete';
incompleteReason = 'fit() or fdescribe() was found';
} else if (totalSpecsDefined === 0) {
overallStatus = 'incomplete';
incompleteReason = 'No specs found';
} else {
overallStatus = 'passed';
}
clearResourcesForRunnable(topSuite.id);
currentlyExecutingSuites.pop();
var overallStatus, incompleteReason;
/**
* 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
};
reporter.jasmineDone(jasmineDoneInfo, function() {
done(jasmineDoneInfo);
});
if (
hasFailures ||
topSuite.result.failedExpectations.length > 0
) {
overallStatus = 'failed';
} else if (focusedRunnables.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: topSuite.result.failedExpectations,
deprecationWarnings: topSuite.result.deprecationWarnings
};
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);
markNotRun(child);
await new Promise(function(resolve) {
reporter.suiteDone(child.result, resolve);
});
} /* a spec */ else {
await new Promise(function(resolve) {
reporter.specStarted(child.result, resolve);
});
await new Promise(function(resolve) {
markNotRun(child);
reporter.specDone(child.result, resolve);
});
}
}
function markNotRun(runnable) {
runnable.addExpectationResult(
false,
{
passed: false,
message: 'Not run because a beforeAll function failed'
},
true
);
runnable.result.status = 'failed';
}
}
};
/**

View File

@@ -25,6 +25,12 @@ getJasmineRequireObj().SkipAfterBeforeAllErrorPolicy = function(j$) {
SkipAfterBeforeAllErrorPolicy.prototype.fnErrored = function(fnIx) {
if (this.queueableFns_[fnIx].type === 'beforeAll') {
this.skipping_ = true;
// Failures need to be reported for each contained spec. But we can't do
// that from here because reporting is async. This function isn't async
// (and can't be without greatly complicating QueueRunner). Mark the
// failure so that the code that reports the suite result (which is
// already async) can detect the failure and report the specs.
this.queueableFns_[fnIx].suite.hadBeforeAllFailure = true;
}
};

View File

@@ -103,7 +103,7 @@ getJasmineRequireObj().Suite = function(j$) {
};
Suite.prototype.beforeAll = function(fn) {
this.beforeAllFns.push({ ...fn, type: 'beforeAll' });
this.beforeAllFns.push({ ...fn, type: 'beforeAll', suite: this });
};
Suite.prototype.afterEach = function(fn) {