diff options
author | isaacs <i@izs.me> | 2021-02-01 23:34:05 +0300 |
---|---|---|
committer | isaacs <i@izs.me> | 2021-02-01 23:42:06 +0300 |
commit | 8c5ca2f516f5ac87f3bbd7f1fd95c0b283a21f14 (patch) | |
tree | 762fcc67e7958778f7d3a4a705c44bc2bab595f7 | |
parent | 13a5e31781cdaa37d3f007e1c8583c7cb591c62a (diff) |
test: Add test for npm-usage.js, and fix 'npm --long' output
-rw-r--r-- | lib/access.js | 3 | ||||
-rw-r--r-- | lib/utils/npm-usage.js | 58 | ||||
-rw-r--r-- | tap-snapshots/test-lib-utils-npm-usage.js-TAP.test.js | 495 | ||||
-rw-r--r-- | test/lib/utils/npm-usage.js | 126 |
4 files changed, 647 insertions, 35 deletions
diff --git a/lib/access.js b/lib/access.js index 68c6e628d..8a372d90c 100644 --- a/lib/access.js +++ b/lib/access.js @@ -8,7 +8,6 @@ const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const usageUtil = require('./utils/usage.js') const getIdentity = require('./utils/get-identity.js') -const { prefix } = npm const usage = usageUtil( 'npm access', @@ -165,7 +164,7 @@ const getPackage = async (name, requireScope) => { return name.trim() else { try { - const pkg = await readPackageJson(path.resolve(prefix, 'package.json')) + const pkg = await readPackageJson(path.resolve(npm.prefix, 'package.json')) name = pkg.name } catch (err) { if (err.code === 'ENOENT') { diff --git a/lib/utils/npm-usage.js b/lib/utils/npm-usage.js index 3ecf068ed..d4261f79d 100644 --- a/lib/utils/npm-usage.js +++ b/lib/utils/npm-usage.js @@ -6,6 +6,8 @@ const { cmdList } = require('./cmd-list') module.exports = (valid = true) => { npm.config.set('loglevel', 'silent') + const usesBrowser = npm.config.get('viewer') === 'browser' + ? ' (in a browser)' : '' npm.log.level = 'silent' output(` Usage: npm <command> @@ -16,8 +18,8 @@ npm test run this project's tests npm run <foo> run the script named <foo> npm <command> -h quick help on <command> npm -l display usage info for all commands -npm help <term> search for help on <term> (in a browser) -npm help npm more involved overview (in a browser) +npm help <term> search for help on <term>${usesBrowser} +npm help npm more involved overview${usesBrowser} All commands: ${npm.config.get('long') ? usages() : ('\n ' + wrap(cmdList))} @@ -40,44 +42,34 @@ npm@${npm.version} ${dirname(dirname(__dirname))} } const wrap = (arr) => { - var out = [''] - var l = 0 - var line + const out = [''] - line = process.stdout.columns - if (!line) - line = 60 - else - line = Math.min(60, Math.max(line - 16, 24)) + const line = !process.stdout.columns ? 60 + : Math.min(60, Math.max(process.stdout.columns - 16, 24)) - arr.sort(function (a, b) { - return a < b ? -1 : 1 - }) - .forEach(function (c) { - if (out[l].length + c.length + 2 < line) - out[l] += ', ' + c - else { - out[l++] += ',' - out[l] = c - } - }) + let l = 0 + for (const c of arr.sort((a, b) => a < b ? -1 : 1)) { + if (out[l].length + c.length + 2 < line) + out[l] += ', ' + c + else { + out[l++] += ',' + out[l] = c + } + } return out.join('\n ').substr(2) } const usages = () => { // return a string of <command>: <usage> - var maxLen = 0 - return cmdList.reduce(function (set, c) { - set.push([c, require(`./${npm.deref(c)}.js`).usage || '']) + let maxLen = 0 + return cmdList.reduce((set, c) => { + set.push([c, require(`../${npm.deref(c)}.js`).usage || + /* istanbul ignore next - all commands should have usage */ '']) maxLen = Math.max(maxLen, c.length) return set - }, []).sort((a, b) => { - return a[0].localeCompare(b[0]) - }).map(function (item) { - var c = item[0] - var usage = item[1] - return '\n ' + - c + (new Array(maxLen - c.length + 2).join(' ')) + - (usage.split('\n').join('\n' + (new Array(maxLen + 6).join(' ')))) - }).join('\n') + }, []) + .sort((a, b) => a[0].localeCompare(b[0])) + .map(([c, usage]) => `\n ${c}${' '.repeat(maxLen - c.length + 1)}${ + (usage.split('\n').join('\n' + ' '.repeat(maxLen + 5)))}`) + .join('\n') } diff --git a/tap-snapshots/test-lib-utils-npm-usage.js-TAP.test.js b/tap-snapshots/test-lib-utils-npm-usage.js-TAP.test.js new file mode 100644 index 000000000..72c2c8158 --- /dev/null +++ b/tap-snapshots/test-lib-utils-npm-usage.js-TAP.test.js @@ -0,0 +1,495 @@ +/* IMPORTANT + * This snapshot file is auto-generated, but designed for humans. + * It should be checked into source control and tracked carefully. + * Re-generate by setting TAP_SNAPSHOT=1 and running tests. + * Make sure to inspect the output below. Do not ignore changes! + */ +'use strict' +exports[`test/lib/utils/npm-usage.js TAP basic usage > must match snapshot 1`] = ` + +Usage: npm <command> + +npm install install all the dependencies in your project +npm install <foo> add the <foo> dependency to your project +npm test run this project's tests +npm run <foo> run the script named <foo> +npm <command> -h quick help on <command> +npm -l display usage info for all commands +npm help <term> search for help on <term> +npm help npm more involved overview + +All commands: + + access, adduser, audit, bin, bugs, cache, ci, completion, + config, dedupe, deprecate, diff, dist-tag, docs, doctor, + edit, exec, explain, explore, find-dupes, fund, get, help, + hook, init, install, install-ci-test, install-test, link, + ll, login, logout, ls, org, outdated, owner, pack, ping, + prefix, profile, prune, publish, rebuild, repo, restart, + root, run-script, search, set, set-script, shrinkwrap, star, + stars, start, stop, team, test, token, uninstall, unpublish, + unstar, update, version, view, whoami + +Specify configs in the ini-formatted file: + /some/config/file/.npmrc +or on the command line via: npm <command> --key=value + +More configuration info: npm help config +Configuration fields: npm help 7 config + +npm@7.99.9999 {BASEDIR} + +` + +exports[`test/lib/utils/npm-usage.js TAP did you mean? > must match snapshot 1`] = ` + +Usage: npm <command> + +npm install install all the dependencies in your project +npm install <foo> add the <foo> dependency to your project +npm test run this project's tests +npm run <foo> run the script named <foo> +npm <command> -h quick help on <command> +npm -l display usage info for all commands +npm help <term> search for help on <term> +npm help npm more involved overview + +All commands: + + access, adduser, audit, bin, bugs, cache, ci, completion, + config, dedupe, deprecate, diff, dist-tag, docs, doctor, + edit, exec, explain, explore, find-dupes, fund, get, help, + hook, init, install, install-ci-test, install-test, link, + ll, login, logout, ls, org, outdated, owner, pack, ping, + prefix, profile, prune, publish, rebuild, repo, restart, + root, run-script, search, set, set-script, shrinkwrap, star, + stars, start, stop, team, test, token, uninstall, unpublish, + unstar, update, version, view, whoami + +Specify configs in the ini-formatted file: + /some/config/file/.npmrc +or on the command line via: npm <command> --key=value + +More configuration info: npm help config +Configuration fields: npm help 7 config + +npm@7.99.9999 {BASEDIR} + +` + +exports[`test/lib/utils/npm-usage.js TAP did you mean? > must match snapshot 2`] = ` + +Did you mean one of these? + install + uninstall +` + +exports[`test/lib/utils/npm-usage.js TAP set process.stdout.columns columns=0 > must match snapshot 1`] = ` + +Usage: npm <command> + +npm install install all the dependencies in your project +npm install <foo> add the <foo> dependency to your project +npm test run this project's tests +npm run <foo> run the script named <foo> +npm <command> -h quick help on <command> +npm -l display usage info for all commands +npm help <term> search for help on <term> +npm help npm more involved overview + +All commands: + + access, adduser, audit, bin, bugs, cache, ci, completion, + config, dedupe, deprecate, diff, dist-tag, docs, doctor, + edit, exec, explain, explore, find-dupes, fund, get, help, + hook, init, install, install-ci-test, install-test, link, + ll, login, logout, ls, org, outdated, owner, pack, ping, + prefix, profile, prune, publish, rebuild, repo, restart, + root, run-script, search, set, set-script, shrinkwrap, star, + stars, start, stop, team, test, token, uninstall, unpublish, + unstar, update, version, view, whoami + +Specify configs in the ini-formatted file: + /some/config/file/.npmrc +or on the command line via: npm <command> --key=value + +More configuration info: npm help config +Configuration fields: npm help 7 config + +npm@7.99.9999 {BASEDIR} + +` + +exports[`test/lib/utils/npm-usage.js TAP set process.stdout.columns columns=90 > must match snapshot 1`] = ` + +Usage: npm <command> + +npm install install all the dependencies in your project +npm install <foo> add the <foo> dependency to your project +npm test run this project's tests +npm run <foo> run the script named <foo> +npm <command> -h quick help on <command> +npm -l display usage info for all commands +npm help <term> search for help on <term> +npm help npm more involved overview + +All commands: + + access, adduser, audit, bin, bugs, cache, ci, completion, + config, dedupe, deprecate, diff, dist-tag, docs, doctor, + edit, exec, explain, explore, find-dupes, fund, get, help, + hook, init, install, install-ci-test, install-test, link, + ll, login, logout, ls, org, outdated, owner, pack, ping, + prefix, profile, prune, publish, rebuild, repo, restart, + root, run-script, search, set, set-script, shrinkwrap, star, + stars, start, stop, team, test, token, uninstall, unpublish, + unstar, update, version, view, whoami + +Specify configs in the ini-formatted file: + /some/config/file/.npmrc +or on the command line via: npm <command> --key=value + +More configuration info: npm help config +Configuration fields: npm help 7 config + +npm@7.99.9999 {BASEDIR} + +` + +exports[`test/lib/utils/npm-usage.js TAP with browser > must match snapshot 1`] = ` + +Usage: npm <command> + +npm install install all the dependencies in your project +npm install <foo> add the <foo> dependency to your project +npm test run this project's tests +npm run <foo> run the script named <foo> +npm <command> -h quick help on <command> +npm -l display usage info for all commands +npm help <term> search for help on <term> (in a browser) +npm help npm more involved overview (in a browser) + +All commands: + + access, adduser, audit, bin, bugs, cache, ci, completion, + config, dedupe, deprecate, diff, dist-tag, docs, doctor, + edit, exec, explain, explore, find-dupes, fund, get, help, + hook, init, install, install-ci-test, install-test, link, + ll, login, logout, ls, org, outdated, owner, pack, ping, + prefix, profile, prune, publish, rebuild, repo, restart, + root, run-script, search, set, set-script, shrinkwrap, star, + stars, start, stop, team, test, token, uninstall, unpublish, + unstar, update, version, view, whoami + +Specify configs in the ini-formatted file: + /some/config/file/.npmrc +or on the command line via: npm <command> --key=value + +More configuration info: npm help config +Configuration fields: npm help 7 config + +npm@7.99.9999 {BASEDIR} + +` + +exports[`test/lib/utils/npm-usage.js TAP with long > must match snapshot 1`] = ` + +Usage: npm <command> + +npm install install all the dependencies in your project +npm install <foo> add the <foo> dependency to your project +npm test run this project's tests +npm run <foo> run the script named <foo> +npm <command> -h quick help on <command> +npm -l display usage info for all commands +npm help <term> search for help on <term> +npm help npm more involved overview + +All commands: + + access npm access public [<package>] + npm access restricted [<package>] + npm access grant <read-only|read-write> <scope:team> [<package>] + npm access revoke <scope:team> [<package>] + npm access 2fa-required [<package>] + npm access 2fa-not-required [<package>] + npm access ls-packages [<user>|<scope>|<scope:team>] + npm access ls-collaborators [<package> [<user>]] + npm access edit [<package>] + + adduser npm adduser [--registry=url] [--scope=@orgname] [--always-auth] + + aliases: login, add-user + + audit npm audit [--json] [--production] + npm audit fix [--force|--package-lock-only|--dry-run|--production|--only=(dev|prod)] + + bin npm bin [-g] + + bugs npm bugs [<pkgname>] + + alias: issues + + cache npm cache add <tarball file> + npm cache add <folder> + npm cache add <tarball url> + npm cache add <git url> + npm cache add <name>@<version> + npm cache clean + npm cache verify + + ci npm ci + + aliases: clean-install, ic, install-clean, isntall-clean + + completion source <(npm completion) + + config npm config set <key>=<value> [<key>=<value> ...] + npm config get [<key> [<key> ...]] + npm config delete <key> [<key> ...] + npm config list [--json] + npm config edit + npm set <key>=<value> [<key>=<value> ...] + npm get [<key> [<key> ...]] + + alias: c + + dedupe npm dedupe + + alias: ddp + + deprecate npm deprecate <pkg>[@<version>] <message> + + diff npm diff [...<paths>] + npm diff --diff=<pkg-name> [...<paths>] + npm diff --diff=<version-a> [--diff=<version-b>] [...<paths>] + npm diff --diff=<spec-a> [--diff=<spec-b>] [...<paths>] + npm diff [--diff-ignore-all-space] [--diff-name-only] [...<paths>] [...<paths>] + + dist-tag npm dist-tag add <pkg>@<version> [<tag>] + npm dist-tag rm <pkg> <tag> + npm dist-tag ls [<pkg>] + + alias: dist-tags + + docs npm docs [<pkgname> [<pkgname> ...]] + + alias: home + + doctor npm doctor + + edit npm edit <pkg>[/<subpkg>...] + + exec Run a command from a local or remote npm package. + + npm exec -- <pkg>[@<version>] [args...] + npm exec --package=<pkg>[@<version>] -- <cmd> [args...] + npm exec -c '<cmd> [args...]' + npm exec --package=foo -c '<cmd> [args...]' + + npx <pkg>[@<specifier>] [args...] + npx -p <pkg>[@<specifier>] <cmd> [args...] + npx -c '<cmd> [args...]' + npx -p <pkg>[@<specifier>] -c '<cmd> [args...]' + Run without --call or positional args to open interactive subshell + + + alias: x + common options: + --package=<pkg> (may be specified multiple times) + -p is a shorthand for --package only when using npx executable + -c <cmd> --call=<cmd> (may not be mixed with positional arguments) + + explain npm explain <folder | specifier> + + alias: why + + explore npm explore <pkg> [ -- <command>] + + find-dupes npm find-dupes + + fund npm fund + + common options: npm fund [--json] [--browser] [--unicode] [[<@scope>/]<pkg> [--which=<fundingSourceNumber>] + + get npm get [<key> ...] (See \`npm config\`) + + help npm help <term> [<terms..>] + + alias: hlep + + hook npm hook add <pkg> <url> <secret> [--type=<type>] + npm hook ls [pkg] + npm hook rm <id> + npm hook update <id> <url> <secret> + + init + npm init [--force|-f|--yes|-y|--scope] + npm init <@scope> (same as \`npx <@scope>/create\`) + npm init [<@scope>/]<name> (same as \`npx [<@scope>/]create-<name>\`) + + aliases: create, innit + + install npm install (with no args, in package dir) + npm install [<@scope>/]<pkg> + npm install [<@scope>/]<pkg>@<tag> + npm install [<@scope>/]<pkg>@<version> + npm install [<@scope>/]<pkg>@<version range> + npm install <alias>@npm:<name> + npm install <folder> + npm install <tarball file> + npm install <tarball url> + npm install <git:// url> + npm install <github username>/<github project> + + aliases: i, in, ins, inst, insta, instal, isnt, isnta, isntal, add + common options: [--save-prod|--save-dev|--save-optional|--save-peer] [--save-exact] [--no-save] + + install-ci-test npm install-ci-test [args] + Same args as \`npm ci\` + + alias: cit + + install-test npm install-test [args] + Same args as \`npm install\` + + alias: it + + link npm link (in package dir) + npm link [<@scope>/]<pkg>[@<version>] + + alias: ln + + ll npm ls [[<@scope>/]<pkg> ...] + + alias: list + + login npm adduser [--registry=url] [--scope=@orgname] [--always-auth] + + aliases: login, add-user + + logout npm logout [--registry=<url>] [--scope=<@scope>] + + ls npm ls [[<@scope>/]<pkg> ...] + + alias: list + + org npm org set orgname username [developer | admin | owner] + npm org rm orgname username + npm org ls orgname [<username>] + + outdated npm outdated [[<@scope>/]<pkg> ...] + + owner npm owner add <user> [<@scope>/]<pkg> + npm owner rm <user> [<@scope>/]<pkg> + npm owner ls [<@scope>/]<pkg> + + alias: author + + pack npm pack [[<@scope>/]<pkg>...] [--dry-run] + + ping npm ping + ping registry + + prefix npm prefix [-g] + + profile npm profile disable-2fa + + + common options: npm profile get [<key>] + + + prune npm prune [[<@scope>/]<pkg>...] [--production] + + publish npm publish [<folder>] [--tag <tag>] [--access <public|restricted>] [--dry-run] + + Publishes '.' if no argument supplied + Sets tag \`latest\` if no --tag specified + + rebuild npm rebuild [[<@scope>/]<name>[@<version>] ...] + + alias: rb + + repo npm repo [<pkgname> [<pkgname> ...]] + + restart npm restart [-- <args>] + + root npm root [-g] + + run-script npm run-script <command> [-- <args>] + + aliases: run, rum, urn + + search npm search [-l|--long] [--json] [--parseable] [--no-description] [search terms ...] + + aliases: s, se, find + + set npm set <key>=<value> [<key>=<value> ...] (See \`npm config\`) + + set-script npm set-script [<script>] [<command>] + + shrinkwrap npm shrinkwrap + + star npm star [<pkg>...] + npm unstar [<pkg>...] + + stars npm stars [<user>] + + start npm start [-- <args>] + + stop npm stop [-- <args>] + + team npm team create <scope:team> [--otp <otpcode>] + npm team destroy <scope:team> [--otp <otpcode>] + npm team add <scope:team> <user> [--otp <otpcode>] + npm team rm <scope:team> <user> [--otp <otpcode>] + npm team ls <scope>|<scope:team> + + + test npm test [-- <args>] + + aliases: tst, t + + token npm token list + npm token revoke <id|token> + npm token create [--read-only] [--cidr=list] + + uninstall npm uninstall [<@scope>/]<pkg>[@<version>]... [-S|--save|--no-save] + + aliases: un, unlink, remove, rm, r + + unpublish npm unpublish [<@scope>/]<pkg>[@<version>] + + unstar npm star [<pkg>...] + npm unstar [<pkg>...] + + update npm update [-g] [<pkg>...] + + aliases: up, upgrade, udpate + + version npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=<prerelease-id>] | from-git] + (run in package dir) + + 'npm -v' or 'npm --version' to print npm version (7.5.0) + 'npm view <pkg> version' to view a package's published version + 'npm ls' to inspect current package/dependency versions + + alias: verison + + view npm view [<@scope>/]<pkg>[@<version>] [<field>[.subfield]...] + + aliases: v, info, show + + whoami npm whoami [--registry <registry>] + (just prints username according to given registry) + +Specify configs in the ini-formatted file: + /some/config/file/.npmrc +or on the command line via: npm <command> --key=value + +More configuration info: npm help config +Configuration fields: npm help 7 config + +npm@7.99.9999 {BASEDIR} + +` diff --git a/test/lib/utils/npm-usage.js b/test/lib/utils/npm-usage.js new file mode 100644 index 000000000..723750111 --- /dev/null +++ b/test/lib/utils/npm-usage.js @@ -0,0 +1,126 @@ +const t = require('tap') + +const deref = require('../../../lib/utils/deref-command.js') +const npm = { + argv: [], + deref, + config: { + _options: { + viewer: null, + long: false, + userconfig: '/some/config/file/.npmrc', + }, + get: k => { + if (npm.config._options[k] === undefined) + throw new Error('unknown config') + return npm.config._options[k] + }, + set: (k, v) => { + npm.config._options[k] = v + }, + }, + log: {}, + version: '7.99.9999', +} + +const OUTPUT = [] +const output = (...msg) => OUTPUT.push(msg) + +const { dirname } = require('path') +const basedir = dirname(dirname(dirname(__dirname))) +t.cleanSnapshot = str => str.split(basedir).join('{BASEDIR}') + +const requireInject = require('require-inject') +const usage = requireInject('../../../lib/utils/npm-usage.js', { + '../../../lib/npm.js': npm, + '../../../lib/utils/output.js': output, +}) + +t.test('basic usage', t => { + usage() + t.equal(OUTPUT.length, 1) + t.equal(OUTPUT[0].length, 1) + t.matchSnapshot(OUTPUT[0][0]) + OUTPUT.length = 0 + t.end() +}) + +t.test('with browser', t => { + npm.config.set('viewer', 'browser') + usage() + t.equal(OUTPUT.length, 1) + t.equal(OUTPUT[0].length, 1) + t.matchSnapshot(OUTPUT[0][0]) + OUTPUT.length = 0 + npm.config.set('viewer', null) + t.end() +}) + +t.test('with long', t => { + npm.config.set('long', true) + usage() + t.equal(OUTPUT.length, 1) + t.equal(OUTPUT[0].length, 1) + t.matchSnapshot(OUTPUT[0][0]) + OUTPUT.length = 0 + npm.config.set('long', false) + t.end() +}) + +t.test('did you mean?', t => { + npm.argv.push('unistnall') + usage() + t.equal(OUTPUT.length, 2) + t.equal(OUTPUT[0].length, 1) + t.equal(OUTPUT[1].length, 1) + t.matchSnapshot(OUTPUT[0][0]) + t.matchSnapshot(OUTPUT[1][0]) + OUTPUT.length = 0 + npm.argv.length = 0 + t.end() +}) + +t.test('did you mean?', t => { + npm.argv.push('unistnall') + const { exitCode } = process + t.teardown(() => { + if (t.passing()) + process.exitCode = exitCode + }) + // make sure it fails when invalid + usage(false) + t.equal(process.exitCode, 1) + OUTPUT.length = 0 + npm.argv.length = 0 + t.end() +}) + +t.test('set process.stdout.columns', t => { + const { columns } = process.stdout + t.teardown(() => { + Object.defineProperty(process.stdout, 'columns', { + value: columns, + enumerable: true, + configurable: true, + writable: true, + }) + }) + const cases = [0, 90] + for (const cols of cases) { + t.test(`columns=${cols}`, t => { + Object.defineProperty(process.stdout, 'columns', { + value: cols, + enumerable: true, + configurable: true, + writable: true, + }) + usage() + t.equal(OUTPUT.length, 1) + t.equal(OUTPUT[0].length, 1) + t.matchSnapshot(OUTPUT[0][0]) + OUTPUT.length = 0 + t.end() + }) + } + t.end() +}) |