From 12e4155cd33c8d5ce50c3d56d1809783b6fb12a4 Mon Sep 17 00:00:00 2001 From: Pierre Vanduynslager Date: Mon, 16 Jul 2018 16:28:07 -0400 Subject: [PATCH] refactor: pass `argv` via `proxyquire` for cli tests --- bin/semantic-release.js | 10 ++-- cli.js | 12 ++--- test/cli.test.js | 117 ++++++++++++++++------------------------ 3 files changed, 58 insertions(+), 81 deletions(-) diff --git a/bin/semantic-release.js b/bin/semantic-release.js index e7ab35de..8019452c 100755 --- a/bin/semantic-release.js +++ b/bin/semantic-release.js @@ -37,6 +37,10 @@ execa }); // Node 8+ from this point on -require('../cli')().catch(() => { - process.exitCode = 1; -}); +require('../cli')() + .then(exitCode => { + process.exitCode = exitCode; + }) + .catch(() => { + process.exitCode = 1; + }); diff --git a/cli.js b/cli.js index d78acaa3..42ed2685 100755 --- a/cli.js +++ b/cli.js @@ -1,3 +1,5 @@ +const {argv} = require('process'); + const stringList = { type: 'string', array: true, @@ -36,11 +38,10 @@ Usage: .exitProcess(false); try { - const {help, version, ...opts} = cli.argv; + const {help, version, ...opts} = cli.parse(argv.slice(2)); if (Boolean(help) || Boolean(version)) { - process.exitCode = 0; - return; + return 0; } // Set the `noCi` options as yargs sets the `ci` options instead (because arg starts with `--no`) @@ -52,13 +53,12 @@ Usage: // Debug must be enabled before other requires in order to work require('debug').enable('semantic-release:*'); } - await require('.')(opts); - process.exitCode = 0; + return 0; } catch (err) { if (err.name !== 'YError') { console.error(err); } - process.exitCode = 1; + return 1; } }; diff --git a/test/cli.test.js b/test/cli.test.js index 6946fe8a..5aaab711 100644 --- a/test/cli.test.js +++ b/test/cli.test.js @@ -1,14 +1,10 @@ import test from 'ava'; import proxyquire from 'proxyquire'; -import clearModule from 'clear-module'; import {stub} from 'sinon'; -// Save the current process.env and process.argv -const envBackup = Object.assign({}, process.env); -const argvBackup = Object.assign({}, process.argv); +const requireNoCache = proxyquire.noPreserveCache(); test.beforeEach(t => { - clearModule('yargs'); t.context.logs = ''; t.context.errors = ''; t.context.stdout = stub(process.stdout, 'write').callsFake(val => { @@ -20,18 +16,13 @@ test.beforeEach(t => { }); test.afterEach.always(t => { - process.env = envBackup; - process.argv = argvBackup; t.context.stdout.restore(); t.context.stderr.restore(); - delete process.exitCode; }); test.serial('Pass options to semantic-release API', async t => { const run = stub().resolves(true); - const cli = proxyquire('../cli', {'.': run}); - - process.argv = [ + const argv = [ '', '', '-b', @@ -68,8 +59,9 @@ test.serial('Pass options to semantic-release API', async t => { '--debug', '-d', ]; + const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}}); - await cli(); + const exitCode = await cli(); t.is(run.args[0][0].branch, 'master'); t.is(run.args[0][0].repositoryUrl, 'https://github/com/owner/repo.git'); @@ -86,14 +78,12 @@ test.serial('Pass options to semantic-release API', async t => { t.is(run.args[0][0].debug, true); t.is(run.args[0][0].dryRun, true); - t.is(process.exitCode, 0); + t.is(exitCode, 0); }); test.serial('Pass options to semantic-release API with alias arguments', async t => { const run = stub().resolves(true); - const cli = proxyquire('../cli', {'.': run}); - - process.argv = [ + const argv = [ '', '', '--branch', @@ -107,8 +97,9 @@ test.serial('Pass options to semantic-release API with alias arguments', async t 'config2', '--dry-run', ]; + const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}}); - await cli(); + const exitCode = await cli(); t.is(run.args[0][0].branch, 'master'); t.is(run.args[0][0].repositoryUrl, 'https://github/com/owner/repo.git'); @@ -116,122 +107,104 @@ test.serial('Pass options to semantic-release API with alias arguments', async t t.deepEqual(run.args[0][0].extends, ['config1', 'config2']); t.is(run.args[0][0].dryRun, true); - t.is(process.exitCode, 0); + t.is(exitCode, 0); }); test.serial('Pass unknown options to semantic-release API', async t => { const run = stub().resolves(true); - const cli = proxyquire('../cli', {'.': run}); + const argv = ['', '', '--bool', '--first-option', 'value1', '--second-option', 'value2', '--second-option', 'value3']; + const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}}); - process.argv = [ - '', - '', - '--bool', - '--first-option', - 'value1', - '--second-option', - 'value2', - '--second-option', - 'value3', - ]; - - await cli(); + const exitCode = await cli(); t.is(run.args[0][0].bool, true); t.is(run.args[0][0].firstOption, 'value1'); t.deepEqual(run.args[0][0].secondOption, ['value2', 'value3']); - t.is(process.exitCode, 0); + t.is(exitCode, 0); }); test.serial('Pass empty Array to semantic-release API for list option set to "false"', async t => { const run = stub().resolves(true); - const cli = proxyquire('../cli', {'.': run}); + const argv = ['', '', '--publish', 'false']; + const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}}); - process.argv = ['', '', '--publish', 'false']; - - await cli(); + const exitCode = await cli(); t.deepEqual(run.args[0][0].publish, []); - t.is(process.exitCode, 0); + t.is(exitCode, 0); }); test.serial('Do not set properties in option for which arg is not in command line', async t => { const run = stub().resolves(true); - const cli = proxyquire('../cli', {'.': run}); - - process.argv = ['', '', '-b', 'master']; + const argv = ['', '', '-b', 'master']; + const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}}); await cli(); - t.false(Reflect.apply(Object.prototype.hasOwnProperty, run.args[0][0], ['ci'])); - t.false(Reflect.apply(Object.prototype.hasOwnProperty, run.args[0][0], ['d'])); - t.false(Reflect.apply(Object.prototype.hasOwnProperty, run.args[0][0], ['dry-run'])); - t.false(Reflect.apply(Object.prototype.hasOwnProperty, run.args[0][0], ['debug'])); - t.false(Reflect.apply(Object.prototype.hasOwnProperty, run.args[0][0], ['r'])); - t.false(Reflect.apply(Object.prototype.hasOwnProperty, run.args[0][0], ['t'])); + t.false('ci' in run.args[0][0]); + t.false('d' in run.args[0][0]); + t.false('dry-run' in run.args[0][0]); + t.false('debug' in run.args[0][0]); + t.false('r' in run.args[0][0]); + t.false('t' in run.args[0][0]); }); test.serial('Set "noCi" options to "true" with "--no-ci"', async t => { const run = stub().resolves(true); - const cli = proxyquire('../cli', {'.': run}); + const argv = ['', '', '--no-ci']; + const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}}); - process.argv = ['', '', '--no-ci']; - - await cli(); + const exitCode = await cli(); t.is(run.args[0][0].noCi, true); - t.is(process.exitCode, 0); + t.is(exitCode, 0); }); test.serial('Display help', async t => { const run = stub().resolves(true); - const cli = proxyquire('../cli', {'.': run}); + const argv = ['', '', '--help']; + const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}}); - process.argv = ['', '', '--help']; - - await cli(); + const exitCode = await cli(); t.regex(t.context.logs, /Run automated package publishing/); - t.is(process.exitCode, 0); + t.is(exitCode, 0); }); test.serial('Returns error code and prints help if called with a command', async t => { const run = stub().resolves(true); - const cli = proxyquire('../cli', {'.': run}); + const argv = ['', '', 'pre']; + const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}}); - process.argv = ['', '', 'pre']; - - await cli(); + const exitCode = await cli(); t.regex(t.context.errors, /Run automated package publishing/); t.regex(t.context.errors, /Too many non-option arguments/); - t.is(process.exitCode, 1); + t.is(exitCode, 1); }); test.serial('Return error code if multiple plugin are set for single plugin', async t => { const run = stub().resolves(true); - const cli = proxyquire('../cli', {'.': run}); + const argv = ['', '', '--analyze-commits', 'analyze1', 'analyze2']; + const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}}); - process.argv = ['', '', '--analyze-commits', 'analyze1', 'analyze2']; - - await cli(); + const exitCode = await cli(); t.regex(t.context.errors, /Run automated package publishing/); t.regex(t.context.errors, /Too many non-option arguments/); - t.is(process.exitCode, 1); + t.is(exitCode, 1); }); test.serial('Return error code if semantic-release throw error', async t => { const run = stub().rejects(new Error('semantic-release error')); - const cli = proxyquire('../cli', {'.': run}); + const argv = ['', '']; + const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}}); - process.argv = ['', '']; - - await cli(); + const exitCode = await cli(); t.regex(t.context.errors, /semantic-release error/); - t.is(process.exitCode, 1); + t.is(exitCode, 1); });