diff --git a/bin/mocha.js b/bin/mocha.js old mode 100644 new mode 100755 index fb58e65fcd..dee9d3a67d --- a/bin/mocha.js +++ b/bin/mocha.js @@ -10,6 +10,7 @@ * @private */ +const os = require('os'); const {loadOptions} = require('../lib/cli/options'); const { unparseNodeFlags, @@ -109,7 +110,13 @@ if (mochaArgs['node-option'] || Object.keys(nodeArgs).length || hasInspect) { proc.on('exit', (code, signal) => { process.on('exit', () => { if (signal) { - process.kill(process.pid, signal); + const numericSignal = + typeof signal === 'string' ? os.constants.signals[signal] : signal; + if (mochaArgs['posix-exit-codes'] === true) { + process.exit(128 + numericSignal); + } else { + process.kill(process.pid, signal); + } } else { process.exit(code); } @@ -126,7 +133,7 @@ if (mochaArgs['node-option'] || Object.keys(nodeArgs).length || hasInspect) { // be needed. if (!args.parallel || args.jobs < 2) { // win32 does not support SIGTERM, so use next best thing. - if (require('os').platform() === 'win32') { + if (os.platform() === 'win32') { proc.kill('SIGKILL'); } else { // using SIGKILL won't cleanly close the output streams, which can result diff --git a/lib/cli/run-option-metadata.js b/lib/cli/run-option-metadata.js index 492608fbdd..91a0282e7b 100644 --- a/lib/cli/run-option-metadata.js +++ b/lib/cli/run-option-metadata.js @@ -45,6 +45,7 @@ const TYPES = (exports.types = { 'list-reporters', 'no-colors', 'parallel', + 'posix-exit-codes', 'recursive', 'sort', 'watch' diff --git a/lib/cli/run.js b/lib/cli/run.js index fbbe510e94..a4830e97e6 100644 --- a/lib/cli/run.js +++ b/lib/cli/run.js @@ -190,6 +190,10 @@ exports.builder = yargs => description: 'Run tests in parallel', group: GROUPS.RULES }, + 'posix-exit-codes': { + description: 'Use posix exit codes for fatal signals', + group: GROUPS.RULES + }, recursive: { description: 'Look for tests in subdirectories', group: GROUPS.FILES diff --git a/test/integration/fixtures/signals-sigabrt.fixture.js b/test/integration/fixtures/signals-sigabrt.fixture.js new file mode 100644 index 0000000000..037111097b --- /dev/null +++ b/test/integration/fixtures/signals-sigabrt.fixture.js @@ -0,0 +1,7 @@ +'use strict'; + +describe('signal suite', function () { + it('test SIGABRT', function () { + process.kill(process.pid, 'SIGABRT'); + }); +}); diff --git a/test/integration/fixtures/signals-sigterm.fixture.js b/test/integration/fixtures/signals-sigterm.fixture.js new file mode 100644 index 0000000000..2f1d01c700 --- /dev/null +++ b/test/integration/fixtures/signals-sigterm.fixture.js @@ -0,0 +1,7 @@ +'use strict'; + +describe('signal suite', function () { + it('test SIGTERM', function () { + process.kill(process.pid, 'SIGTERM'); + }); +}); diff --git a/test/integration/options/posixExitCodes.spec.js b/test/integration/options/posixExitCodes.spec.js new file mode 100644 index 0000000000..f33f65a0ff --- /dev/null +++ b/test/integration/options/posixExitCodes.spec.js @@ -0,0 +1,46 @@ +'use strict'; + +var helpers = require('../helpers'); +var runMocha = helpers.runMocha; + +describe('--posix-exit-codes', function () { + describe('when enabled with node options', function () { + var args = ['--no-warnings', '--posix-exit-codes']; + + it('should exit with code 134 on SIGABRT', function (done) { + var fixture = 'signals-sigabrt.fixture.js'; + runMocha(fixture, args, function postmortem(err, res) { + if (err) { + return done(err); + } + expect(res.code, 'to be', 134); + done(); + }); + }); + + it('should exit with code 143 on SIGTERM', function (done) { + var fixture = 'signals-sigterm.fixture.js'; + runMocha(fixture, args, function postmortem(err, res) { + if (err) { + return done(err); + } + expect(res.code, 'to be', 143); + done(); + }); + }); + }); + + describe('when not enabled with node options', function () { + it('should exit with code null on SIGABRT', function (done) { + var fixture = 'signals-sigabrt.fixture.js'; + var args = ['--no-warnings']; + runMocha(fixture, args, function postmortem(err, res) { + if (err) { + return done(err); + } + expect(res.code, 'to be', null); + done(); + }); + }); + }); +});