From 7842b4d4dca1e076b0d26d554f9dce67484cd7be Mon Sep 17 00:00:00 2001 From: Ruy Adorno Date: Thu, 19 Nov 2020 17:50:07 -0500 Subject: [PATCH] fix: npm version usage - Fix `npm version` unexpected arg count usage - Add tests for lib/version.js Fixes: https://github.com/npm/statusboard/issues/182 PR-URL: https://github.com/npm/cli/pull/2205 Credit: @ruyadorno Close: #2205 Reviewed-by: @nlf --- lib/version.js | 4 +- test/lib/version.js | 160 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 test/lib/version.js diff --git a/lib/version.js b/lib/version.js index 98068490d85b1..abdd8d552b20c 100644 --- a/lib/version.js +++ b/lib/version.js @@ -1,3 +1,5 @@ +'use strict' + const libversion = require('libnpmversion') const npm = require('./npm.js') const output = require('./utils/output.js') @@ -42,7 +44,7 @@ const version = async args => { path: npm.prefix, })) default: - throw version.usage + throw usage } } diff --git a/test/lib/version.js b/test/lib/version.js new file mode 100644 index 0000000000000..f36132253fa32 --- /dev/null +++ b/test/lib/version.js @@ -0,0 +1,160 @@ +const t = require('tap') +const requireInject = require('require-inject') + +let result = [] + +const noop = () => null +const npm = { + flatOptions: { + json: false, + }, + prefix: '', + version: '1.0.0', +} +const mocks = { + libnpmversion: noop, + '../../lib/npm.js': npm, + '../../lib/utils/output.js': (...msg) => { + for (const m of msg) + result.push(m) + }, + '../../lib/utils/usage.js': () => 'usage instructions', +} + +const version = requireInject('../../lib/version.js', mocks) + +const _processVersions = process.versions +t.afterEach(cb => { + npm.flatOptions.json = false + npm.prefix = '' + process.versions = _processVersions + result = [] + cb() +}) + +t.test('no args', t => { + const prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'test-version-no-args', + version: '3.2.1', + }), + }) + npm.prefix = prefix + Object.defineProperty(process, 'versions', { value: { node: '1.0.0' } }) + + version([], err => { + if (err) + throw err + + t.deepEqual( + result, + [{ + 'test-version-no-args': '3.2.1', + node: '1.0.0', + npm: '1.0.0', + }], + 'should output expected values for various versions in npm' + ) + + t.end() + }) +}) + +t.test('too many args', t => { + version(['foo', 'bar'], err => { + t.match( + err, + 'usage instructions', + 'should throw usage instructions error' + ) + + t.end() + }) +}) + +t.test('completion', t => { + const { completion } = version + + const testComp = (argv, expect) => { + completion({ conf: { argv: { remain: argv } } }, (err, res) => { + t.ifError(err) + t.strictSame(res, expect, argv.join(' ')) + }) + } + + testComp(['npm', 'version'], [ + 'major', + 'minor', + 'patch', + 'premajor', + 'preminor', + 'prepatch', + 'prerelease', + 'from-git', + ]) + testComp(['npm', 'version', 'major'], []) + + t.end() +}) + +t.test('failure reading package.json', t => { + const prefix = t.testdir({}) + npm.prefix = prefix + + version([], err => { + if (err) + throw err + + t.deepEqual( + result, + [{ + npm: '1.0.0', + node: '1.0.0', + }], + 'should not have package name on returning object' + ) + + t.end() + }) +}) + +t.test('--json option', t => { + const prefix = t.testdir({}) + npm.flatOptions.json = true + npm.prefix = prefix + Object.defineProperty(process, 'versions', { value: {} }) + + version([], err => { + if (err) + throw err + t.deepEqual( + result, + ['{\n "npm": "1.0.0"\n}'], + 'should return json stringified result' + ) + t.end() + }) +}) + +t.test('with one arg', t => { + const version = requireInject('../../lib/version.js', { + ...mocks, + libnpmversion: (arg, opts) => { + t.equal(arg, 'major', 'should forward expected value') + t.deepEqual( + opts, + { + json: false, + path: '', + }, + 'should forward expected options' + ) + t.end() + }, + }) + + version(['major'], err => { + if (err) + throw err + }) +})