Skip to content

Commit

Permalink
Add option fail-on-failing-test-suite to not fail test run if there w…
Browse files Browse the repository at this point in the history
…ere no infrastructure problem
  • Loading branch information
ilgonmic committed Oct 18, 2021
1 parent 28b4824 commit eaf9283
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 31 deletions.
88 changes: 57 additions & 31 deletions lib/cli/run-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,49 +19,62 @@ const PluginLoader = require('../plugin-loader');

/**
* Exits Mocha when tests + code under test has finished execution (default)
* @param {number} code - Exit code; typically # of failures
* @param {number} failOnFailingTestSuite - Exit code; typically # of failures
* @ignore
* @private
*/
const exitMochaLater = code => {
process.on('exit', () => {
process.exitCode = Math.min(code, 255);
});
const exitMochaLater = failOnFailingTestSuite => {
return code => {
process.on('exit', () => {
if (failOnFailingTestSuite) {
process.exitCode = Math.min(code, 255);
} else {
process.exitCode = 0;
}
});
};
};

/**
* Exits Mocha when Mocha itself has finished execution, regardless of
* what the tests or code under test is doing.
* @param {number} code - Exit code; typically # of failures
* @param {number} failOnFailingTestSuite - Exit code; typically # of failures
* @ignore
* @private
*/
const exitMocha = code => {
const clampedCode = Math.min(code, 255);
let draining = 0;

// Eagerly set the process's exit code in case stream.write doesn't
// execute its callback before the process terminates.
process.exitCode = clampedCode;

// flush output for Node.js Windows pipe bug
// https://github.com/joyent/node/issues/6247 is just one bug example
// https://github.com/visionmedia/mocha/issues/333 has a good discussion
const done = () => {
if (!draining--) {
process.exit(clampedCode);
const exitMocha = failOnFailingTestSuite => {
return code => {
let clampedCode;
if (failOnFailingTestSuite) {
clampedCode = Math.min(code, 255);
} else {
clampedCode = 0;
}
};
let draining = 0;

const streams = [process.stdout, process.stderr];
// Eagerly set the process's exit code in case stream.write doesn't
// execute its callback before the process terminates.
process.exitCode = clampedCode;

streams.forEach(stream => {
// submit empty write request and wait for completion
draining += 1;
stream.write('', done);
});
// flush output for Node.js Windows pipe bug
// https://github.com/joyent/node/issues/6247 is just one bug example
// https://github.com/visionmedia/mocha/issues/333 has a good discussion
const done = () => {
if (!draining--) {
process.exit(clampedCode);
}
};

const streams = [process.stdout, process.stderr];

done();
streams.forEach(stream => {
// submit empty write request and wait for completion
draining += 1;
stream.write('', done);
});

done();
};
};

/**
Expand Down Expand Up @@ -111,19 +124,28 @@ exports.handleRequires = async (requires = [], {ignoredPlugins = []} = {}) => {
* @param {Mocha} mocha - Mocha instance
* @param {Options} [opts] - Command line options
* @param {boolean} [opts.exit] - Whether or not to force-exit after tests are complete
* @param {boolean} [opts.failOnFailingTestSuite] - Whether or not to fail test run if tests were failed
* @param {Object} fileCollectParams - Parameters that control test
* file collection. See `lib/cli/collect-files.js`.
* @returns {Promise<Runner>}
* @private
*/
const singleRun = async (mocha, {exit}, fileCollectParams) => {
const singleRun = async (
mocha,
{exit, failOnFailingTestSuite},
fileCollectParams
) => {
const files = collectFiles(fileCollectParams);
debug('single run with %d file(s)', files.length);
mocha.files = files;

// handles ESM modules
await mocha.loadFilesAsync();
return mocha.run(exit ? exitMocha : exitMochaLater);
return mocha.run(
exit
? exitMocha(failOnFailingTestSuite)
: exitMochaLater(failOnFailingTestSuite)
);
};

/**
Expand All @@ -145,7 +167,11 @@ const parallelRun = async (mocha, options, fileCollectParams) => {
mocha.files = files;

// note that we DO NOT load any files here; this is handled by the worker
return mocha.run(options.exit ? exitMocha : exitMochaLater);
return mocha.run(
options.exit
? exitMocha(options.failOnFailingTestSuite)
: exitMochaLater(options.failOnFailingTestSuite)
);
};

/**
Expand Down
1 change: 1 addition & 0 deletions lib/cli/run-option-metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const TYPES = (exports.types = {
'diff',
'dry-run',
'exit',
'fail-on-failing-test-suite',
'fail-zero',
'forbid-only',
'forbid-pending',
Expand Down
5 changes: 5 additions & 0 deletions lib/cli/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ exports.builder = yargs =>
requiresArg: true,
coerce: list
},
'fail-on-failing-test-suite': {
default: true,
description: 'Fail test run if tests were failed',
group: GROUPS.RULES
},
'fail-zero': {
description: 'Fail test run if no test(s) encountered',
group: GROUPS.RULES
Expand Down
16 changes: 16 additions & 0 deletions lib/mocha.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ exports.run = function(...args) {
* @param {boolean} [options.delay] - Delay root suite execution?
* @param {boolean} [options.diff] - Show diff on failure?
* @param {boolean} [options.dryRun] - Report tests without running them?
* @param {boolean} [options.failOnFailingTestSuite] - Fail test run if tests were failed?
* @param {boolean} [options.failZero] - Fail test run if zero tests?
* @param {string} [options.fgrep] - Test filter given string.
* @param {boolean} [options.forbidOnly] - Tests marked `only` fail the suite?
Expand Down Expand Up @@ -222,6 +223,7 @@ function Mocha(options = {}) {
'delay',
'diff',
'dryRun',
'failOnFailingTestSuite',
'failZero',
'forbidOnly',
'forbidPending',
Expand Down Expand Up @@ -926,6 +928,20 @@ Mocha.prototype.failZero = function(failZero) {
return this;
};

/**
* Fail test run if tests were failed.
*
* @public
* @see [CLI option](../#-fail-on-failing-test-suite)
* @param {boolean} [failOnFailingTestSuite=true] - Whether to fail test run.
* @return {Mocha} this
* @chainable
*/
Mocha.prototype.failOnFailingTestSuite = function(failOnFailingTestSuite) {
this.options.failOnFailingTestSuite = failOnFailingTestSuite !== false;
return this;
};

/**
* Causes tests marked `only` to fail the suite.
*
Expand Down

0 comments on commit eaf9283

Please sign in to comment.