diff --git a/lib/command.js b/lib/command.js index 8c6c6ee00..7ee670a03 100644 --- a/lib/command.js +++ b/lib/command.js @@ -256,6 +256,9 @@ module.exports = function command (yargs, usage, validation, globalMiddleware) { // fail's throwing would cause an unhandled rejection. } }) + .then(() => { + yargs.getUsageInstance().clearCachedHelpMessage() + }) } else { if (handlerFinishCommand) { handlerFinishCommand(handlerResult) diff --git a/lib/usage.js b/lib/usage.js index 0dd150178..2aeb7c7ea 100644 --- a/lib/usage.js +++ b/lib/usage.js @@ -411,6 +411,12 @@ module.exports = function usage (yargs, y18n) { cachedHelpMessage = this.help() } + // however this snapshot must be cleared afterwards + // not to be be used by next calls to parse + self.clearCachedHelpMessage = function () { + cachedHelpMessage = undefined + } + // given a set of keys, place any keys that are // ungrouped under the 'Options:' grouping. function addUngroupedKeys (keys, aliases, groups) { diff --git a/test/helpers/utils.js b/test/helpers/utils.js index 764e37d31..76c09e7fe 100644 --- a/test/helpers/utils.js +++ b/test/helpers/utils.js @@ -34,8 +34,7 @@ exports.checkOutput = function checkOutput (f, argv, cb) { } process.emit = function emit (ev, value) { if (ev === 'uncaughtException') { - done() - cb(value) + cb(value, done()) return true } diff --git a/test/usage.js b/test/usage.js index 1875cf140..78aa4d249 100644 --- a/test/usage.js +++ b/test/usage.js @@ -8,7 +8,7 @@ const yargs = require('../') const rebase = require('../yargs').rebase const YError = require('../lib/yerror') -require('chai').should() +const should = require('chai').should() const noop = () => {} @@ -3430,4 +3430,76 @@ describe('usage tests', () => { ]) }) }) + + describe('help message caching', () => { + it('should display proper usage when an async handler fails', (done) => { + const y = yargs() + .command('cmd', 'test command', {}, () => { + return new Promise((resolve, reject) => + setTimeout(reject, 10) + ) + }) + .exitProcess(false) + + checkUsage( + () => { + y.parse('cmd') + setTimeout(() => process.exit(1), 100) + }, + undefined, + (err, r) => { + should.not.exist(err) + should.exist(r.errors[0]) + r.errors[0].split('\n').should.deep.equal([ + '_mocha cmd', + '', + 'test command', + '', + 'Options:', + ' --help Show help [boolean]', + ' --version Show version number [boolean]' + ]) + done() + } + ) + }) + + it('should not display a cached help message for the next parsing', (done) => { + const y = yargs() + .command('cmd', 'test command', {}, () => { + return new Promise((resolve, reject) => + setTimeout(resolve, 10) + ) + }) + .demandCommand(1, 'You need at least one command before moving on') + .exitProcess(false) + + checkUsage( + () => { + y.parse('cmd') + setTimeout(() => { + y.parse('') + setTimeout(() => process.exit(1), 100) + }, 100) + }, + undefined, + (err, r) => { + should.exist(err) + err.message.should.equal('You need at least one command before moving on') + should.exist(r.errors[0]) + r.errors[0].split('\n').should.deep.equal([ + '_mocha ', + '', + 'Commands:', + ' _mocha cmd test command', + '', + 'Options:', + ' --help Show help [boolean]', + ' --version Show version number [boolean]' + ]) + done() + } + ) + }) + }) })