diff --git a/deps/npm/docs/output/commands/npm-ls.html b/deps/npm/docs/output/commands/npm-ls.html index 398d46b6ac5ed7..5969fb08d793a9 100644 --- a/deps/npm/docs/output/commands/npm-ls.html +++ b/deps/npm/docs/output/commands/npm-ls.html @@ -159,7 +159,7 @@

Description

the results to only the paths to the packages named. Note that nested packages will also show the paths to the specified packages. For example, running npm ls promzard in npm’s source tree will show:

-
npm@8.1.2 /path/to/npm
+
npm@8.1.3 /path/to/npm
 └─┬ init-package-json@0.0.4
   └── promzard@0.1.5
 
diff --git a/deps/npm/docs/output/commands/npm.html b/deps/npm/docs/output/commands/npm.html index 3e42f7dfb73bcc..96e98b52773cc8 100644 --- a/deps/npm/docs/output/commands/npm.html +++ b/deps/npm/docs/output/commands/npm.html @@ -148,7 +148,7 @@

Table of contents

npm <command> [args]
 

Version

-

8.1.2

+

8.1.3

Description

npm is the package manager for the Node JavaScript platform. It puts modules in place so that node can find them, and manages dependency diff --git a/deps/npm/index.js b/deps/npm/index.js index 5447643e04b66b..570df352b9d4bb 100644 --- a/deps/npm/index.js +++ b/deps/npm/index.js @@ -1,5 +1,4 @@ -if (require.main === module) { +if (require.main === module) require('./lib/cli.js')(process) -} else { +else throw new Error('The programmatic API was removed in npm v8.0.0') -} diff --git a/deps/npm/lib/workspaces/arborist-cmd.js b/deps/npm/lib/arborist-cmd.js similarity index 70% rename from deps/npm/lib/workspaces/arborist-cmd.js rename to deps/npm/lib/arborist-cmd.js index a75b351be4759b..48ba3b0c942578 100644 --- a/deps/npm/lib/workspaces/arborist-cmd.js +++ b/deps/npm/lib/arborist-cmd.js @@ -2,7 +2,7 @@ // a list of workspace names and passes it on to new Arborist() to // be able to run a filtered Arborist.reify() at some point. -const BaseCommand = require('../base-command.js') +const BaseCommand = require('./base-command.js') class ArboristCmd extends BaseCommand { get isArboristCmd () { return true @@ -17,12 +17,9 @@ class ArboristCmd extends BaseCommand { ] } - execWorkspaces (args, filters, cb) { - this.setWorkspaces(filters, true) - .then(() => { - this.exec(args, cb) - }) - .catch(er => cb(er)) + async execWorkspaces (args, filters) { + await this.setWorkspaces(filters) + return this.exec(args) } } diff --git a/deps/npm/lib/base-command.js b/deps/npm/lib/base-command.js index c5bd3fd94f960c..c5fce6fd8d0bd5 100644 --- a/deps/npm/lib/base-command.js +++ b/deps/npm/lib/base-command.js @@ -1,4 +1,4 @@ -// Base class for npm.commands[cmd] +// Base class for npm commands const usageUtil = require('./utils/usage.js') const ConfigDefinitions = require('./utils/config/definitions.js') const getWorkspaces = require('./workspaces/get-workspaces.js') @@ -53,19 +53,15 @@ class BaseCommand { return results } - usageError (msg) { - if (!msg) { - return Object.assign(new Error(`\nUsage: ${this.usage}`), { - code: 'EUSAGE', - }) - } - - return Object.assign(new Error(`\nUsage: ${msg}\n\n${this.usage}`), { + usageError (prefix = '') { + if (prefix) + prefix += '\n\n' + return Object.assign(new Error(`\nUsage: ${prefix}${this.usage}`), { code: 'EUSAGE', }) } - execWorkspaces (args, filters, cb) { + async execWorkspaces (args, filters) { throw Object.assign( new Error('This command does not support workspaces.'), { code: 'ENOWORKSPACES' } diff --git a/deps/npm/lib/cli.js b/deps/npm/lib/cli.js index e33ac91fa5ade0..0e6301517f4459 100644 --- a/deps/npm/lib/cli.js +++ b/deps/npm/lib/cli.js @@ -18,7 +18,8 @@ module.exports = async (process) => { checkForUnsupportedNode() - const npm = require('../lib/npm.js') + const Npm = require('../lib/npm.js') + const npm = new Npm() const exitHandler = require('../lib/utils/exit-handler.js') exitHandler.setNpm(npm) @@ -38,6 +39,7 @@ module.exports = async (process) => { const updateNotifier = require('../lib/utils/update-notifier.js') + let cmd // now actually fire up npm and run the command. // this is how to use npm programmatically: try { @@ -55,24 +57,23 @@ module.exports = async (process) => { updateNotifier(npm) - const cmd = npm.argv.shift() + cmd = npm.argv.shift() if (!cmd) { - npm.output(npm.usage) + npm.output(await npm.usage) process.exitCode = 1 return exitHandler() } - const impl = npm.commands[cmd] - if (!impl) { + await npm.exec(cmd, npm.argv) + exitHandler() + } catch (err) { + if (err.code === 'EUNKNOWNCOMMAND') { const didYouMean = require('./utils/did-you-mean.js') const suggestions = await didYouMean(npm, npm.localPrefix, cmd) npm.output(`Unknown command: "${cmd}"${suggestions}\n\nTo see a list of supported npm commands, run:\n npm help`) process.exitCode = 1 return exitHandler() } - - impl(npm.argv, exitHandler) - } catch (err) { return exitHandler(err) } } diff --git a/deps/npm/lib/access.js b/deps/npm/lib/commands/access.js similarity index 95% rename from deps/npm/lib/access.js rename to deps/npm/lib/commands/access.js index 2f0a979ff384e4..15e51a450aa2a0 100644 --- a/deps/npm/lib/access.js +++ b/deps/npm/lib/commands/access.js @@ -3,9 +3,9 @@ const path = require('path') const libaccess = require('libnpmaccess') const readPackageJson = require('read-package-json-fast') -const otplease = require('./utils/otplease.js') -const getIdentity = require('./utils/get-identity.js') -const BaseCommand = require('./base-command.js') +const otplease = require('../utils/otplease.js') +const getIdentity = require('../utils/get-identity.js') +const BaseCommand = require('../base-command.js') const subcommands = [ 'public', @@ -76,11 +76,7 @@ class Access extends BaseCommand { } } - exec (args, cb) { - this.access(args).then(() => cb()).catch(cb) - } - - async access ([cmd, ...args]) { + async exec ([cmd, ...args]) { if (!cmd) throw this.usageError('Subcommand is required.') diff --git a/deps/npm/lib/adduser.js b/deps/npm/lib/commands/adduser.js similarity index 82% rename from deps/npm/lib/adduser.js rename to deps/npm/lib/commands/adduser.js index e502276a1743c6..6136eb726fa7e0 100644 --- a/deps/npm/lib/adduser.js +++ b/deps/npm/lib/commands/adduser.js @@ -1,11 +1,11 @@ const log = require('npmlog') -const replaceInfo = require('./utils/replace-info.js') -const BaseCommand = require('./base-command.js') +const replaceInfo = require('../utils/replace-info.js') +const BaseCommand = require('../base-command.js') const authTypes = { - legacy: require('./auth/legacy.js'), - oauth: require('./auth/oauth.js'), - saml: require('./auth/saml.js'), - sso: require('./auth/sso.js'), + legacy: require('../auth/legacy.js'), + oauth: require('../auth/oauth.js'), + saml: require('../auth/saml.js'), + sso: require('../auth/sso.js'), } class AddUser extends BaseCommand { @@ -24,11 +24,7 @@ class AddUser extends BaseCommand { ] } - exec (args, cb) { - this.adduser(args).then(() => cb()).catch(cb) - } - - async adduser (args) { + async exec (args) { const { scope } = this.npm.flatOptions const registry = this.getRegistry(this.npm.flatOptions) const auth = this.getAuthType(this.npm.flatOptions) diff --git a/deps/npm/lib/audit.js b/deps/npm/lib/commands/audit.js similarity index 86% rename from deps/npm/lib/audit.js rename to deps/npm/lib/commands/audit.js index 54480d1f0cbf95..d05633ab0fe093 100644 --- a/deps/npm/lib/audit.js +++ b/deps/npm/lib/commands/audit.js @@ -1,8 +1,8 @@ const Arborist = require('@npmcli/arborist') const auditReport = require('npm-audit-report') -const reifyFinish = require('./utils/reify-finish.js') -const auditError = require('./utils/audit-error.js') -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const reifyFinish = require('../utils/reify-finish.js') +const auditError = require('../utils/audit-error.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') class Audit extends ArboristWorkspaceCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -47,11 +47,7 @@ class Audit extends ArboristWorkspaceCmd { } } - exec (args, cb) { - this.audit(args).then(() => cb()).catch(cb) - } - - async audit (args) { + async exec (args) { const reporter = this.npm.config.get('json') ? 'json' : 'detail' const opts = { ...this.npm.flatOptions, diff --git a/deps/npm/lib/bin.js b/deps/npm/lib/commands/bin.js similarity index 68% rename from deps/npm/lib/bin.js rename to deps/npm/lib/commands/bin.js index 20e13f160f2761..9a894f3bb58f3b 100644 --- a/deps/npm/lib/bin.js +++ b/deps/npm/lib/commands/bin.js @@ -1,5 +1,5 @@ -const envPath = require('./utils/path.js') -const BaseCommand = require('./base-command.js') +const envPath = require('../utils/path.js') +const BaseCommand = require('../base-command.js') class Bin extends BaseCommand { static get description () { @@ -14,11 +14,7 @@ class Bin extends BaseCommand { return ['global'] } - exec (args, cb) { - this.bin(args).then(() => cb()).catch(cb) - } - - async bin (args) { + async exec (args) { const b = this.npm.bin this.npm.output(b) if (this.npm.config.get('global') && !envPath.includes(b)) diff --git a/deps/npm/lib/birthday.js b/deps/npm/lib/commands/birthday.js similarity index 52% rename from deps/npm/lib/birthday.js rename to deps/npm/lib/commands/birthday.js index 92b1dd1c2e5fe8..4fa0268f8bcfa4 100644 --- a/deps/npm/lib/birthday.js +++ b/deps/npm/lib/commands/birthday.js @@ -1,10 +1,11 @@ -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Birthday extends BaseCommand { - exec (args, cb) { + async exec () { this.npm.config.set('package', ['@npmcli/npm-birthday']) this.npm.config.set('yes', true) - return this.npm.commands.exec(['npm-birthday'], cb) + const exec = await this.npm.cmd('exec') + return exec.exec(['npm-birthday']) } } diff --git a/deps/npm/lib/bugs.js b/deps/npm/lib/commands/bugs.js similarity index 84% rename from deps/npm/lib/bugs.js rename to deps/npm/lib/commands/bugs.js index 05897176104b5e..863a7ffeca56bf 100644 --- a/deps/npm/lib/bugs.js +++ b/deps/npm/lib/commands/bugs.js @@ -1,8 +1,8 @@ const log = require('npmlog') const pacote = require('pacote') -const openUrl = require('./utils/open-url.js') -const hostedFromMani = require('./utils/hosted-git-info-from-manifest.js') -const BaseCommand = require('./base-command.js') +const openUrl = require('../utils/open-url.js') +const hostedFromMani = require('../utils/hosted-git-info-from-manifest.js') +const BaseCommand = require('../base-command.js') class Bugs extends BaseCommand { static get description () { @@ -22,11 +22,7 @@ class Bugs extends BaseCommand { return ['browser', 'registry'] } - exec (args, cb) { - this.bugs(args).then(() => cb()).catch(cb) - } - - async bugs (args) { + async exec (args) { if (!args || !args.length) args = ['.'] diff --git a/deps/npm/lib/cache.js b/deps/npm/lib/commands/cache.js similarity index 93% rename from deps/npm/lib/cache.js rename to deps/npm/lib/commands/cache.js index 4a5665111949fd..b4a932d1bec031 100644 --- a/deps/npm/lib/cache.js +++ b/deps/npm/lib/commands/cache.js @@ -5,7 +5,7 @@ const pacote = require('pacote') const path = require('path') const rimraf = promisify(require('rimraf')) const semver = require('semver') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') const npa = require('npm-package-arg') const jsonParse = require('json-parse-even-better-errors') const localeCompare = require('@isaacs/string-locale-compare')('en') @@ -104,11 +104,7 @@ class Cache extends BaseCommand { } } - exec (args, cb) { - this.cache(args).then(() => cb()).catch(cb) - } - - async cache (args) { + async exec (args) { const cmd = args.shift() switch (cmd) { case 'rm': case 'clear': case 'clean': @@ -120,7 +116,7 @@ class Cache extends BaseCommand { case 'ls': return await this.ls(args) default: - throw Object.assign(new Error(this.usage), { code: 'EUSAGE' }) + throw this.usageError() } } @@ -165,14 +161,9 @@ class Cache extends BaseCommand { // npm cache add ... // npm cache add ... async add (args) { - const usage = 'Usage:\n' + - ' npm cache add ...\n' + - ' npm cache add @...\n' + - ' npm cache add ...\n' + - ' npm cache add ...\n' log.silly('cache add', 'args', args) if (args.length === 0) - throw Object.assign(new Error(usage), { code: 'EUSAGE' }) + throw this.usageError('First argument to `add` is required') return Promise.all(args.map(spec => { log.silly('cache add', 'spec', spec) diff --git a/deps/npm/lib/ci.js b/deps/npm/lib/commands/ci.js similarity index 93% rename from deps/npm/lib/ci.js rename to deps/npm/lib/commands/ci.js index 6634ffcdc19bcb..a53c580670581a 100644 --- a/deps/npm/lib/ci.js +++ b/deps/npm/lib/commands/ci.js @@ -1,7 +1,7 @@ const util = require('util') const Arborist = require('@npmcli/arborist') const rimraf = util.promisify(require('rimraf')) -const reifyFinish = require('./utils/reify-finish.js') +const reifyFinish = require('../utils/reify-finish.js') const runScript = require('@npmcli/run-script') const fs = require('fs') const readdir = util.promisify(fs.readdir) @@ -17,7 +17,7 @@ const removeNodeModules = async where => { await Promise.all(entries.map(f => rimraf(`${path}/${f}`, rimrafOpts))) process.emit('timeEnd', 'npm-ci:rm') } -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') class CI extends ArboristWorkspaceCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -39,11 +39,7 @@ class CI extends ArboristWorkspaceCmd { ] } - exec (args, cb) { - this.ci().then(() => cb()).catch(cb) - } - - async ci () { + async exec () { if (this.npm.config.get('global')) { const err = new Error('`npm ci` does not work for global packages') err.code = 'ECIGLOBAL' diff --git a/deps/npm/lib/completion.js b/deps/npm/lib/commands/completion.js similarity index 93% rename from deps/npm/lib/completion.js rename to deps/npm/lib/commands/completion.js index fa3b5f2dd36ccc..fbbde0df70ea7b 100644 --- a/deps/npm/lib/completion.js +++ b/deps/npm/lib/commands/completion.js @@ -29,20 +29,20 @@ // as an array. // -const { definitions, shorthands } = require('./utils/config/index.js') -const deref = require('./utils/deref-command.js') -const { aliases, cmdList, plumbing } = require('./utils/cmd-list.js') +const { definitions, shorthands } = require('../utils/config/index.js') +const deref = require('../utils/deref-command.js') +const { aliases, cmdList, plumbing } = require('../utils/cmd-list.js') const aliasNames = Object.keys(aliases) const fullList = cmdList.concat(aliasNames).filter(c => !plumbing.includes(c)) const nopt = require('nopt') const configNames = Object.keys(definitions) const shorthandNames = Object.keys(shorthands) const allConfs = configNames.concat(shorthandNames) -const isWindowsShell = require('./utils/is-windows-shell.js') -const fileExists = require('./utils/file-exists.js') +const isWindowsShell = require('../utils/is-windows-shell.js') +const fileExists = require('../utils/file-exists.js') const { promisify } = require('util') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Completion extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -75,11 +75,7 @@ class Completion extends BaseCommand { return out } - exec (args, cb) { - this.compl(args).then(() => cb()).catch(cb) - } - - async compl (args) { + async exec (args) { if (isWindowsShell) { const msg = 'npm completion supported only in MINGW / Git bash on Windows' throw Object.assign(new Error(msg), { @@ -163,8 +159,8 @@ class Completion extends BaseCommand { // at this point, if words[1] is some kind of npm command, // then complete on it. // otherwise, do nothing - const impl = this.npm.commands[cmd] - if (impl && impl.completion) { + const impl = this.npm.cmd(cmd) + if (impl.completion) { const comps = await impl.completion(opts) return this.wrap(opts, comps) } @@ -195,19 +191,11 @@ const dumpScript = async () => { const fs = require('fs') const readFile = promisify(fs.readFile) const { resolve } = require('path') - const p = resolve(__dirname, 'utils/completion.sh') + const p = resolve(__dirname, '..', 'utils', 'completion.sh') const d = (await readFile(p, 'utf8')).replace(/^#!.*?\n/, '') await new Promise((res, rej) => { let done = false - process.stdout.write(d, () => { - if (done) - return - - done = true - res() - }) - process.stdout.on('error', er => { if (done) return @@ -224,11 +212,21 @@ const dumpScript = async () => { // Really, one should not be tossing away EPIPE errors, or any // errors, so casually. But, without this, `. <(npm completion)` // can never ever work on OS X. + // TODO Ignoring coverage, see 'non EPIPE errors cause failures' test. + /* istanbul ignore next */ if (er.errno === 'EPIPE') res() else rej(er) }) + + process.stdout.write(d, () => { + if (done) + return + + done = true + res() + }) }) } diff --git a/deps/npm/lib/config.js b/deps/npm/lib/commands/config.js similarity index 96% rename from deps/npm/lib/config.js rename to deps/npm/lib/commands/config.js index a1f706d930e6af..fc482edb6a6888 100644 --- a/deps/npm/lib/config.js +++ b/deps/npm/lib/commands/config.js @@ -1,5 +1,5 @@ // don't expand so that we only assemble the set of defaults when needed -const configDefs = require('./utils/config/index.js') +const configDefs = require('../utils/config/index.js') const mkdirp = require('mkdirp-infer-owner') const { dirname } = require('path') @@ -29,7 +29,7 @@ const keyValues = args => { const publicVar = k => !/^(\/\/[^:]+:)?_/.test(k) -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Config extends BaseCommand { static get description () { return 'Manage the npm configuration files' @@ -96,16 +96,12 @@ class Config extends BaseCommand { } } - exec (args, cb) { - this.config(args).then(() => cb()).catch(cb) - } - - execWorkspaces (args, filters, cb) { + async execWorkspaces (args, filters) { this.npm.log.warn('config', 'This command does not support workspaces.') - this.exec(args, cb) + return this.exec(args) } - async config ([action, ...args]) { + async exec ([action, ...args]) { this.npm.log.disableProgress() try { switch (action) { diff --git a/deps/npm/lib/dedupe.js b/deps/npm/lib/commands/dedupe.js similarity index 85% rename from deps/npm/lib/dedupe.js rename to deps/npm/lib/commands/dedupe.js index aaa7a30d104167..f9314cfc5155a9 100644 --- a/deps/npm/lib/dedupe.js +++ b/deps/npm/lib/commands/dedupe.js @@ -1,8 +1,8 @@ // dedupe duplicated packages, or find them in the tree const Arborist = require('@npmcli/arborist') -const reifyFinish = require('./utils/reify-finish.js') +const reifyFinish = require('../utils/reify-finish.js') -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') class Dedupe extends ArboristWorkspaceCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -32,11 +32,7 @@ class Dedupe extends ArboristWorkspaceCmd { ] } - exec (args, cb) { - this.dedupe(args).then(() => cb()).catch(cb) - } - - async dedupe (args) { + async exec (args) { if (this.npm.config.get('global')) { const er = new Error('`npm dedupe` does not work in global mode.') er.code = 'EDEDUPEGLOBAL' diff --git a/deps/npm/lib/deprecate.js b/deps/npm/lib/commands/deprecate.js similarity index 86% rename from deps/npm/lib/deprecate.js rename to deps/npm/lib/commands/deprecate.js index c1f7ee629bff25..37b9d2dc27b66d 100644 --- a/deps/npm/lib/deprecate.js +++ b/deps/npm/lib/commands/deprecate.js @@ -1,10 +1,10 @@ const fetch = require('npm-registry-fetch') -const otplease = require('./utils/otplease.js') +const otplease = require('../utils/otplease.js') const npa = require('npm-package-arg') const semver = require('semver') -const getIdentity = require('./utils/get-identity.js') +const getIdentity = require('../utils/get-identity.js') const libaccess = require('libnpmaccess') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Deprecate extends BaseCommand { static get description () { @@ -42,13 +42,7 @@ class Deprecate extends BaseCommand { name.startsWith(opts.conf.argv.remain[0]))) } - exec (args, cb) { - this.deprecate(args) - .then(() => cb()) - .catch(err => cb(err.code === 'EUSAGE' ? err.message : err)) - } - - async deprecate ([pkg, msg]) { + async exec ([pkg, msg]) { // msg == null because '' is a valid value, it indicates undeprecate if (!pkg || msg == null) throw this.usageError() diff --git a/deps/npm/lib/diff.js b/deps/npm/lib/commands/diff.js similarity index 91% rename from deps/npm/lib/diff.js rename to deps/npm/lib/commands/diff.js index b1a32705c0644a..67d0d15058534d 100644 --- a/deps/npm/lib/diff.js +++ b/deps/npm/lib/commands/diff.js @@ -8,8 +8,8 @@ const npmlog = require('npmlog') const pacote = require('pacote') const pickManifest = require('npm-pick-manifest') -const readPackageName = require('./utils/read-package-name.js') -const BaseCommand = require('./base-command.js') +const readPackageName = require('../utils/read-package-name.js') +const BaseCommand = require('../base-command.js') class Diff extends BaseCommand { static get description () { @@ -47,24 +47,12 @@ class Diff extends BaseCommand { ] } - exec (args, cb) { - this.diff(args).then(() => cb()).catch(cb) - } - - execWorkspaces (args, filters, cb) { - this.diffWorkspaces(args, filters).then(() => cb()).catch(cb) - } - - async diff (args) { + async exec (args) { const specs = this.npm.config.get('diff').filter(d => d) - if (specs.length > 2) { - throw new TypeError( - 'Can\'t use more than two --diff arguments.\n\n' + - `Usage:\n${this.usage}` - ) - } + if (specs.length > 2) + throw this.usageError(`Can't use more than two --diff arguments.`) - // diffWorkspaces may have set this already + // execWorkspaces may have set this already if (!this.prefix) this.prefix = this.npm.prefix @@ -89,12 +77,12 @@ class Diff extends BaseCommand { return this.npm.output(res) } - async diffWorkspaces (args, filters) { + async execWorkspaces (args, filters) { await this.setWorkspaces(filters) for (const workspacePath of this.workspacePaths) { this.top = workspacePath this.prefix = workspacePath - await this.diff(args) + await this.exec(args) } } @@ -109,7 +97,7 @@ class Diff extends BaseCommand { } if (!name) - throw this.usageError('Needs multiple arguments to compare or run from a project dir.\n') + throw this.usageError('Needs multiple arguments to compare or run from a project dir.') return name } @@ -141,7 +129,7 @@ class Diff extends BaseCommand { noPackageJson = true } - const missingPackageJson = this.usageError('Needs multiple arguments to compare or run from a project dir.\n') + const missingPackageJson = this.usageError('Needs multiple arguments to compare or run from a project dir.') // using a valid semver range, that means it should just diff // the cwd against a published version to the registry using the @@ -230,7 +218,7 @@ class Diff extends BaseCommand { `file:${this.prefix}`, ] } else - throw this.usageError(`Spec type ${spec.type} not supported.\n`) + throw this.usageError(`Spec type ${spec.type} not supported.`) } async convertVersionsToSpecs ([a, b]) { @@ -247,7 +235,7 @@ class Diff extends BaseCommand { } if (!pkgName) - throw this.usageError('Needs to be run from a project dir in order to diff two versions.\n') + throw this.usageError('Needs to be run from a project dir in order to diff two versions.') return [`${pkgName}@${a}`, `${pkgName}@${b}`] } diff --git a/deps/npm/lib/dist-tag.js b/deps/npm/lib/commands/dist-tag.js similarity index 91% rename from deps/npm/lib/dist-tag.js rename to deps/npm/lib/commands/dist-tag.js index be44f39ff25333..b7baa3d463e5d5 100644 --- a/deps/npm/lib/dist-tag.js +++ b/deps/npm/lib/commands/dist-tag.js @@ -3,9 +3,9 @@ const npa = require('npm-package-arg') const regFetch = require('npm-registry-fetch') const semver = require('semver') -const otplease = require('./utils/otplease.js') -const readPackageName = require('./utils/read-package-name.js') -const BaseCommand = require('./base-command.js') +const otplease = require('../utils/otplease.js') +const readPackageName = require('../utils/read-package-name.js') +const BaseCommand = require('../base-command.js') class DistTag extends BaseCommand { static get description () { @@ -42,11 +42,7 @@ class DistTag extends BaseCommand { } } - exec (args, cb) { - this.distTag(args).then(() => cb()).catch(cb) - } - - async distTag ([cmdName, pkg, tag]) { + async exec ([cmdName, pkg, tag]) { const opts = this.npm.flatOptions if (['add', 'a', 'set', 's'].includes(cmdName)) @@ -66,11 +62,7 @@ class DistTag extends BaseCommand { throw this.usageError() } - execWorkspaces (args, filters, cb) { - this.distTagWorkspaces(args, filters).then(() => cb()).catch(cb) - } - - async distTagWorkspaces ([cmdName, pkg, tag], filters) { + async execWorkspaces ([cmdName, pkg, tag], filters) { // cmdName is some form of list // pkg is one of: // - unset @@ -90,7 +82,7 @@ class DistTag extends BaseCommand { // anything else is just a regular dist-tag command // so we fallback to the non-workspaces implementation log.warn('Ignoring workspaces for specified package') - return this.distTag([cmdName, pkg, tag]) + return this.exec([cmdName, pkg, tag]) } async add (spec, tag, opts) { diff --git a/deps/npm/lib/docs.js b/deps/npm/lib/commands/docs.js similarity index 75% rename from deps/npm/lib/docs.js rename to deps/npm/lib/commands/docs.js index 51f8be38821792..4482678ea7f0c4 100644 --- a/deps/npm/lib/docs.js +++ b/deps/npm/lib/commands/docs.js @@ -1,9 +1,9 @@ const log = require('npmlog') const pacote = require('pacote') -const openUrl = require('./utils/open-url.js') -const hostedFromMani = require('./utils/hosted-git-info-from-manifest.js') +const openUrl = require('../utils/open-url.js') +const hostedFromMani = require('../utils/hosted-git-info-from-manifest.js') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Docs extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -31,24 +31,16 @@ class Docs extends BaseCommand { return ['[ [ ...]]'] } - exec (args, cb) { - this.docs(args).then(() => cb()).catch(cb) - } - - execWorkspaces (args, filters, cb) { - this.docsWorkspaces(args, filters).then(() => cb()).catch(cb) - } - - async docs (args) { + async exec (args) { if (!args || !args.length) args = ['.'] await Promise.all(args.map(pkg => this.getDocs(pkg))) } - async docsWorkspaces (args, filters) { + async execWorkspaces (args, filters) { await this.setWorkspaces(filters) - return this.docs(this.workspacePaths) + return this.exec(this.workspacePaths) } async getDocs (pkg) { diff --git a/deps/npm/lib/doctor.js b/deps/npm/lib/commands/doctor.js similarity index 95% rename from deps/npm/lib/doctor.js rename to deps/npm/lib/commands/doctor.js index 57488fd698856a..b6363467c6487e 100644 --- a/deps/npm/lib/doctor.js +++ b/deps/npm/lib/commands/doctor.js @@ -8,10 +8,10 @@ const pacote = require('pacote') const { resolve } = require('path') const semver = require('semver') const { promisify } = require('util') -const ansiTrim = require('./utils/ansi-trim.js') -const isWindows = require('./utils/is-windows.js') -const ping = require('./utils/ping.js') -const { registry: { default: defaultRegistry } } = require('./utils/config/definitions.js') +const ansiTrim = require('../utils/ansi-trim.js') +const isWindows = require('../utils/is-windows.js') +const ping = require('../utils/ping.js') +const { registry: { default: defaultRegistry } } = require('../utils/config/definitions.js') const lstat = promisify(fs.lstat) const readdir = promisify(fs.readdir) const access = promisify(fs.access) @@ -30,7 +30,7 @@ const maskLabel = mask => { return label.join(', ') } -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Doctor extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -47,11 +47,7 @@ class Doctor extends BaseCommand { return ['registry'] } - exec (args, cb) { - this.doctor(args).then(() => cb()).catch(cb) - } - - async doctor (args) { + async exec (args) { this.npm.log.info('Running checkup') // each message is [title, ok, message] @@ -121,7 +117,7 @@ class Doctor extends BaseCommand { console.error('') } if (!allOk) - throw 'Some problems found. See above for recommendations.' + throw new Error('Some problems found. See above for recommendations.') } async checkPing () { diff --git a/deps/npm/lib/edit.js b/deps/npm/lib/commands/edit.js similarity index 75% rename from deps/npm/lib/edit.js rename to deps/npm/lib/commands/edit.js index 1cf7ca5c223812..4f0af6e8333e66 100644 --- a/deps/npm/lib/edit.js +++ b/deps/npm/lib/commands/edit.js @@ -4,9 +4,9 @@ const { resolve } = require('path') const fs = require('graceful-fs') const { spawn } = require('child_process') -const splitPackageNames = require('./utils/split-package-names.js') -const completion = require('./utils/completion/installed-shallow.js') -const BaseCommand = require('./base-command.js') +const splitPackageNames = require('../utils/split-package-names.js') +const completion = require('../utils/completion/installed-shallow.js') +const BaseCommand = require('../base-command.js') class Edit extends BaseCommand { static get description () { @@ -33,13 +33,9 @@ class Edit extends BaseCommand { return completion(this.npm, opts) } - exec (args, cb) { - this.edit(args).then(() => cb()).catch(cb) - } - - async edit (args) { + async exec (args) { if (args.length !== 1) - throw new Error(this.usage) + throw this.usageError() const path = splitPackageNames(args[0]) const dir = resolve(this.npm.dir, path) @@ -54,12 +50,7 @@ class Edit extends BaseCommand { editor.on('exit', (code) => { if (code) return reject(new Error(`editor process exited with code: ${code}`)) - this.npm.commands.rebuild([dir], (err) => { - if (err) - return reject(err) - - resolve() - }) + this.npm.exec('rebuild', [dir]).catch(reject).then(resolve) }) }) }) diff --git a/deps/npm/lib/exec.js b/deps/npm/lib/commands/exec.js similarity index 77% rename from deps/npm/lib/exec.js rename to deps/npm/lib/commands/exec.js index d11947483e26ef..ffe72ccb4c862e 100644 --- a/deps/npm/lib/exec.js +++ b/deps/npm/lib/commands/exec.js @@ -1,6 +1,6 @@ const libexec = require('libnpmexec') -const BaseCommand = require('./base-command.js') -const getLocationMsg = require('./exec/get-workspace-location-msg.js') +const BaseCommand = require('../base-command.js') +const getLocationMsg = require('../exec/get-workspace-location-msg.js') // it's like this: // @@ -59,19 +59,13 @@ class Exec extends BaseCommand { ] } - exec (args, cb) { - const path = this.npm.localPrefix - const runPath = process.cwd() - this._exec(args, { path, runPath }).then(() => cb()).catch(cb) - } + async exec (_args, { locationMsg, path, runPath } = {}) { + if (!path) + path = this.npm.localPrefix - execWorkspaces (args, filters, cb) { - this._execWorkspaces(args, filters).then(() => cb()).catch(cb) - } + if (!runPath) + runPath = process.cwd() - // When commands go async and we can dump the boilerplate exec methods this - // can be named correctly - async _exec (_args, { locationMsg, path, runPath }) { const args = [..._args] const call = this.npm.config.get('call') const { @@ -86,7 +80,7 @@ class Exec extends BaseCommand { const yes = this.npm.config.get('yes') if (call && _args.length) - throw this.usage + throw this.usageError() return libexec({ ...flatOptions, @@ -105,17 +99,13 @@ class Exec extends BaseCommand { }) } - async _execWorkspaces (args, filters) { + async execWorkspaces (args, filters) { await this.setWorkspaces(filters) const color = this.npm.color for (const path of this.workspacePaths) { const locationMsg = await getLocationMsg({ color, path }) - await this._exec(args, { - locationMsg, - path, - runPath: path, - }) + await this.exec(args, { locationMsg, path, runPath: path }) } } } diff --git a/deps/npm/lib/explain.js b/deps/npm/lib/commands/explain.js similarity index 90% rename from deps/npm/lib/explain.js rename to deps/npm/lib/commands/explain.js index fc7f57891b986f..0ef41559f7a9e9 100644 --- a/deps/npm/lib/explain.js +++ b/deps/npm/lib/commands/explain.js @@ -1,11 +1,11 @@ -const { explainNode } = require('./utils/explain-dep.js') -const completion = require('./utils/completion/installed-deep.js') +const { explainNode } = require('../utils/explain-dep.js') +const completion = require('../utils/completion/installed-deep.js') const Arborist = require('@npmcli/arborist') const npa = require('npm-package-arg') const semver = require('semver') const { relative, resolve } = require('path') const validName = require('validate-npm-package-name') -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') class Explain extends ArboristWorkspaceCmd { static get description () { @@ -35,13 +35,9 @@ class Explain extends ArboristWorkspaceCmd { return completion(this.npm, opts) } - exec (args, cb) { - this.explain(args).then(() => cb()).catch(cb) - } - - async explain (args) { + async exec (args) { if (!args.length) - throw this.usage + throw this.usageError() const arb = new Arborist({ path: this.npm.prefix, ...this.npm.flatOptions }) const tree = await arb.loadActual() @@ -67,7 +63,7 @@ class Explain extends ArboristWorkspaceCmd { } } if (nodes.size === 0) - throw `No dependencies found matching ${args.join(', ')}` + throw new Error(`No dependencies found matching ${args.join(', ')}`) const expls = [] for (const node of nodes) { diff --git a/deps/npm/lib/explore.js b/deps/npm/lib/commands/explore.js similarity index 90% rename from deps/npm/lib/explore.js rename to deps/npm/lib/commands/explore.js index 4417fba7d1fc74..81a71f86abacec 100644 --- a/deps/npm/lib/explore.js +++ b/deps/npm/lib/commands/explore.js @@ -4,8 +4,8 @@ const rpj = require('read-package-json-fast') const runScript = require('@npmcli/run-script') const { join, resolve, relative } = require('path') -const completion = require('./utils/completion/installed-shallow.js') -const BaseCommand = require('./base-command.js') +const completion = require('../utils/completion/installed-shallow.js') +const BaseCommand = require('../base-command.js') class Explore extends BaseCommand { static get description () { @@ -32,20 +32,16 @@ class Explore extends BaseCommand { return completion(this.npm, opts) } - exec (args, cb) { - this.explore(args).then(() => cb()).catch(cb) - } - - async explore (args) { + async exec (args) { if (args.length < 1 || !args[0]) - throw this.usage + throw this.usageError() const pkgname = args.shift() // detect and prevent any .. shenanigans const path = join(this.npm.dir, join('/', pkgname)) if (relative(path, this.npm.dir) === '') - throw this.usage + throw this.usageError() // run as if running a script named '_explore', which we set to either // the set of arguments, or the shell config, and let @npmcli/run-script diff --git a/deps/npm/lib/find-dupes.js b/deps/npm/lib/commands/find-dupes.js similarity index 85% rename from deps/npm/lib/find-dupes.js rename to deps/npm/lib/commands/find-dupes.js index 69b30e8aa3dbba..5467a94dd9fcf4 100644 --- a/deps/npm/lib/find-dupes.js +++ b/deps/npm/lib/commands/find-dupes.js @@ -1,5 +1,5 @@ // dedupe duplicated packages, or find them in the tree -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') class FindDupes extends ArboristWorkspaceCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -28,9 +28,9 @@ class FindDupes extends ArboristWorkspaceCmd { ] } - exec (args, cb) { + async exec (args, cb) { this.npm.config.set('dry-run', true) - this.npm.commands.dedupe([], cb) + return this.npm.exec('dedupe', []) } } module.exports = FindDupes diff --git a/deps/npm/lib/fund.js b/deps/npm/lib/commands/fund.js similarity index 96% rename from deps/npm/lib/fund.js rename to deps/npm/lib/commands/fund.js index 97139f5bba09c9..fbf78051d97a93 100644 --- a/deps/npm/lib/fund.js +++ b/deps/npm/lib/commands/fund.js @@ -11,9 +11,9 @@ const { isValidFunding, } = require('libnpmfund') -const completion = require('./utils/completion/installed-deep.js') -const openUrl = require('./utils/open-url.js') -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const completion = require('../utils/completion/installed-deep.js') +const openUrl = require('../utils/open-url.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') const getPrintableName = ({ name, version }) => { const printableVersion = version ? `@${version}` : '' @@ -52,11 +52,7 @@ class Fund extends ArboristWorkspaceCmd { return completion(this.npm, opts) } - exec (args, cb) { - this.fund(args).then(() => cb()).catch(cb) - } - - async fund (args) { + async exec (args) { const spec = args[0] const numberArg = this.npm.config.get('which') diff --git a/deps/npm/lib/get.js b/deps/npm/lib/commands/get.js similarity index 72% rename from deps/npm/lib/get.js rename to deps/npm/lib/commands/get.js index 8cfb259a81323b..0e314efe7144c8 100644 --- a/deps/npm/lib/get.js +++ b/deps/npm/lib/commands/get.js @@ -1,4 +1,4 @@ -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Get extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -18,11 +18,12 @@ class Get extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ async completion (opts) { - return this.npm.commands.config.completion(opts) + const config = await this.npm.cmd('config') + return config.completion(opts) } - exec (args, cb) { - this.npm.commands.config(['get'].concat(args), cb) + async exec (args) { + return this.npm.exec('config', ['get'].concat(args)) } } module.exports = Get diff --git a/deps/npm/lib/help-search.js b/deps/npm/lib/commands/help-search.js similarity index 95% rename from deps/npm/lib/help-search.js rename to deps/npm/lib/commands/help-search.js index 877989fd0148e2..a179939abf673d 100644 --- a/deps/npm/lib/help-search.js +++ b/deps/npm/lib/commands/help-search.js @@ -4,7 +4,7 @@ const color = require('ansicolors') const { promisify } = require('util') const glob = promisify(require('glob')) const readFile = promisify(fs.readFile) -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class HelpSearch extends BaseCommand { static get description () { @@ -26,15 +26,11 @@ class HelpSearch extends BaseCommand { return ['long'] } - exec (args, cb) { - this.helpSearch(args).then(() => cb()).catch(cb) - } - - async helpSearch (args) { + async exec (args) { if (!args.length) - return this.npm.output(this.usage) + throw this.usageError() - const docPath = path.resolve(__dirname, '..', 'docs/content') + const docPath = path.resolve(__dirname, '..', '..', 'docs/content') const files = await glob(`${docPath}/*/*.md`) const data = await this.readFiles(files) const results = await this.searchFiles(args, data, files) diff --git a/deps/npm/lib/help.js b/deps/npm/lib/commands/help.js similarity index 83% rename from deps/npm/lib/help.js rename to deps/npm/lib/commands/help.js index 9a6f950e059535..bfc7f8b60e5b35 100644 --- a/deps/npm/lib/help.js +++ b/deps/npm/lib/commands/help.js @@ -1,11 +1,11 @@ const { spawn } = require('child_process') const path = require('path') -const openUrl = require('./utils/open-url.js') +const openUrl = require('../utils/open-url.js') const { promisify } = require('util') const glob = promisify(require('glob')) const localeCompare = require('@isaacs/string-locale-compare')('en') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') // Strips out the number from foo.7 or foo.7. or foo.7.tgz // We don't currently compress our man pages but if we ever did this would @@ -36,7 +36,7 @@ class Help extends BaseCommand { async completion (opts) { if (opts.conf.argv.remain.length > 2) return [] - const g = path.resolve(__dirname, '../man/man[0-9]/*.[0-9]') + const g = path.resolve(__dirname, '../../man/man[0-9]/*.[0-9]') const files = await glob(g) return Object.keys(files.reduce(function (acc, file) { @@ -47,11 +47,7 @@ class Help extends BaseCommand { }, { help: true })) } - exec (args, cb) { - this.help(args).then(() => cb()).catch(cb) - } - - async help (args) { + async exec (args) { // By default we search all of our man subdirectories, but if the user has // asked for a specific one we limit the search to just there let manSearch = 'man*' @@ -59,7 +55,7 @@ class Help extends BaseCommand { manSearch = `man${args.shift()}` if (!args.length) - return this.npm.output(this.npm.usage) + return this.npm.output(await this.npm.usage) // npm help foo bar baz: search topics if (args.length > 1) @@ -70,7 +66,7 @@ class Help extends BaseCommand { // support `npm help package.json` section = section.replace('.json', '-json') - const manroot = path.resolve(__dirname, '..', 'man') + const manroot = path.resolve(__dirname, '..', '..', 'man') // find either section.n or npm-section.n const f = `${manroot}/${manSearch}/?(npm-)${section}.[0-9]*` let mans = await glob(f) @@ -94,16 +90,7 @@ class Help extends BaseCommand { } helpSearch (args) { - return new Promise((resolve, reject) => { - this.npm.commands['help-search'](args, (err) => { - // This would only error if args was empty, which it never is - /* istanbul ignore next */ - if (err) - return reject(err) - - resolve() - }) - }) + return this.npm.exec('help-search', args) } async viewMan (man) { @@ -161,7 +148,7 @@ class Help extends BaseCommand { sect = 'using-npm' break } - return 'file://' + path.resolve(__dirname, '..', 'docs', 'output', sect, f + '.html') + return 'file:///' + path.resolve(__dirname, '..', '..', 'docs', 'output', sect, f + '.html') } } module.exports = Help diff --git a/deps/npm/lib/hook.js b/deps/npm/lib/commands/hook.js similarity index 94% rename from deps/npm/lib/hook.js rename to deps/npm/lib/commands/hook.js index 2ee81bea648b46..7b2deff22940bc 100644 --- a/deps/npm/lib/hook.js +++ b/deps/npm/lib/commands/hook.js @@ -1,9 +1,9 @@ const hookApi = require('libnpmhook') -const otplease = require('./utils/otplease.js') +const otplease = require('../utils/otplease.js') const relativeDate = require('tiny-relative-date') const Table = require('cli-table3') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Hook extends BaseCommand { static get description () { return 'Manage registry hooks' @@ -30,11 +30,7 @@ class Hook extends BaseCommand { ] } - exec (args, cb) { - this.hook(args).then(() => cb()).catch(cb) - } - - async hook (args) { + async exec (args) { return otplease(this.npm.flatOptions, (opts) => { switch (args[0]) { case 'add': @@ -47,7 +43,7 @@ class Hook extends BaseCommand { case 'up': return this.update(args[1], args[2], args[3], opts) default: - throw this.usage + throw this.usageError() } }) } diff --git a/deps/npm/lib/init.js b/deps/npm/lib/commands/init.js similarity index 94% rename from deps/npm/lib/init.js rename to deps/npm/lib/commands/init.js index e654793ecca0ec..b88b38436e9104 100644 --- a/deps/npm/lib/init.js +++ b/deps/npm/lib/commands/init.js @@ -8,8 +8,8 @@ const libexec = require('libnpmexec') const mapWorkspaces = require('@npmcli/map-workspaces') const PackageJson = require('@npmcli/package-json') -const getLocationMsg = require('./exec/get-workspace-location-msg.js') -const BaseCommand = require('./base-command.js') +const getLocationMsg = require('../exec/get-workspace-location-msg.js') +const BaseCommand = require('../base-command.js') class Init extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -36,15 +36,7 @@ class Init extends BaseCommand { ] } - exec (args, cb) { - this.init(args).then(() => cb()).catch(cb) - } - - execWorkspaces (args, filters, cb) { - this.initWorkspaces(args, filters).then(() => cb()).catch(cb) - } - - async init (args) { + async exec (args) { // npm exec style if (args.length) return (await this.execCreate({ args, path: process.cwd() })) @@ -53,10 +45,10 @@ class Init extends BaseCommand { await this.template() } - async initWorkspaces (args, filters) { + async execWorkspaces (args, filters) { // if the root package is uninitiated, take care of it first if (this.npm.flatOptions.includeWorkspaceRoot) - await this.init(args) + await this.exec(args) // reads package.json for the top-level folder first, by doing this we // ensure the command throw if no package.json is found before trying diff --git a/deps/npm/lib/install-ci-test.js b/deps/npm/lib/commands/install-ci-test.js similarity index 73% rename from deps/npm/lib/install-ci-test.js rename to deps/npm/lib/commands/install-ci-test.js index 871f24b2f32d6a..7b121f776666af 100644 --- a/deps/npm/lib/install-ci-test.js +++ b/deps/npm/lib/commands/install-ci-test.js @@ -13,12 +13,9 @@ class InstallCITest extends CI { return 'install-ci-test' } - exec (args, cb) { - this.npm.commands.ci(args, (er) => { - if (er) - return cb(er) - this.npm.commands.test([], cb) - }) + async exec (args, cb) { + await this.npm.exec('ci', args) + return this.npm.exec('test', []) } } module.exports = InstallCITest diff --git a/deps/npm/lib/install-test.js b/deps/npm/lib/commands/install-test.js similarity index 72% rename from deps/npm/lib/install-test.js rename to deps/npm/lib/commands/install-test.js index d5664119df5ce2..74e7ebcf86c90b 100644 --- a/deps/npm/lib/install-test.js +++ b/deps/npm/lib/commands/install-test.js @@ -13,12 +13,9 @@ class InstallTest extends Install { return 'install-test' } - exec (args, cb) { - this.npm.commands.install(args, (er) => { - if (er) - return cb(er) - this.npm.commands.test([], cb) - }) + async exec (args, cb) { + await this.npm.exec('install', args) + return this.npm.exec('test', []) } } module.exports = InstallTest diff --git a/deps/npm/lib/install.js b/deps/npm/lib/commands/install.js similarity index 96% rename from deps/npm/lib/install.js rename to deps/npm/lib/commands/install.js index 99f75b71384fa6..ea3bbcee3fca05 100644 --- a/deps/npm/lib/install.js +++ b/deps/npm/lib/commands/install.js @@ -3,7 +3,7 @@ const fs = require('fs') const util = require('util') const readdir = util.promisify(fs.readdir) -const reifyFinish = require('./utils/reify-finish.js') +const reifyFinish = require('../utils/reify-finish.js') const log = require('npmlog') const { resolve, join } = require('path') const Arborist = require('@npmcli/arborist') @@ -11,7 +11,7 @@ const runScript = require('@npmcli/run-script') const pacote = require('pacote') const checks = require('npm-install-checks') -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') class Install extends ArboristWorkspaceCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -118,11 +118,7 @@ class Install extends ArboristWorkspaceCmd { // 50,000 packages on the registry } - exec (args, cb) { - this.install(args).then(() => cb()).catch(cb) - } - - async install (args) { + async exec (args) { // the /path/to/node_modules/.. const globalTop = resolve(this.npm.globalDir, '..') const ignoreScripts = this.npm.config.get('ignore-scripts') diff --git a/deps/npm/lib/link.js b/deps/npm/lib/commands/link.js similarity index 96% rename from deps/npm/lib/link.js rename to deps/npm/lib/commands/link.js index 2437eb12ed7d6e..4a800d7c60242c 100644 --- a/deps/npm/lib/link.js +++ b/deps/npm/lib/commands/link.js @@ -8,9 +8,9 @@ const npa = require('npm-package-arg') const rpj = require('read-package-json-fast') const semver = require('semver') -const reifyFinish = require('./utils/reify-finish.js') +const reifyFinish = require('../utils/reify-finish.js') -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') class Link extends ArboristWorkspaceCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -56,11 +56,7 @@ class Link extends ArboristWorkspaceCmd { return files.filter(f => !/^[._-]/.test(f)) } - exec (args, cb) { - this.link(args).then(() => cb()).catch(cb) - } - - async link (args) { + async exec (args) { if (this.npm.config.get('global')) { throw Object.assign( new Error( diff --git a/deps/npm/lib/ll.js b/deps/npm/lib/commands/ll.js similarity index 87% rename from deps/npm/lib/ll.js rename to deps/npm/lib/commands/ll.js index 3e3428a7ff5ebc..d438de61e2fe7d 100644 --- a/deps/npm/lib/ll.js +++ b/deps/npm/lib/commands/ll.js @@ -11,9 +11,9 @@ class LL extends LS { return ['[[<@scope>/] ...]'] } - exec (args, cb) { + async exec (args) { this.npm.config.set('long', true) - super.exec(args, cb) + return super.exec(args) } } diff --git a/deps/npm/lib/logout.js b/deps/npm/lib/commands/logout.js similarity index 91% rename from deps/npm/lib/logout.js rename to deps/npm/lib/commands/logout.js index 0887ec397bf1ae..3c0bdc756508c8 100644 --- a/deps/npm/lib/logout.js +++ b/deps/npm/lib/commands/logout.js @@ -1,7 +1,7 @@ const log = require('npmlog') const getAuth = require('npm-registry-fetch/auth.js') const npmFetch = require('npm-registry-fetch') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Logout extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -22,11 +22,7 @@ class Logout extends BaseCommand { ] } - exec (args, cb) { - this.logout(args).then(() => cb()).catch(cb) - } - - async logout (args) { + async exec (args) { const registry = this.npm.config.get('registry') const scope = this.npm.config.get('scope') const regRef = scope ? `${scope}:registry` : 'registry' diff --git a/deps/npm/lib/ls.js b/deps/npm/lib/commands/ls.js similarity index 98% rename from deps/npm/lib/ls.js rename to deps/npm/lib/commands/ls.js index 46cfb2462d327a..af7d44ab41800e 100644 --- a/deps/npm/lib/ls.js +++ b/deps/npm/lib/commands/ls.js @@ -8,7 +8,7 @@ const Arborist = require('@npmcli/arborist') const { breadth } = require('treeverse') const npa = require('npm-package-arg') -const completion = require('./utils/completion/installed-deep.js') +const completion = require('../utils/completion/installed-deep.js') const _depth = Symbol('depth') const _dedupe = Symbol('dedupe') @@ -21,7 +21,7 @@ const _parent = Symbol('parent') const _problems = Symbol('problems') const _required = Symbol('required') const _type = Symbol('type') -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') const localeCompare = require('@isaacs/string-locale-compare')('en') class LS extends ArboristWorkspaceCmd { @@ -62,11 +62,7 @@ class LS extends ArboristWorkspaceCmd { return completion(this.npm, opts) } - exec (args, cb) { - this.ls(args).then(() => cb()).catch(cb) - } - - async ls (args) { + async exec (args) { const all = this.npm.config.get('all') const color = this.npm.color const depth = this.npm.config.get('depth') diff --git a/deps/npm/lib/org.js b/deps/npm/lib/commands/org.js similarity index 91% rename from deps/npm/lib/org.js rename to deps/npm/lib/commands/org.js index a494e1eaf9486c..6d0b8cd5057583 100644 --- a/deps/npm/lib/org.js +++ b/deps/npm/lib/commands/org.js @@ -1,7 +1,7 @@ const liborg = require('libnpmorg') -const otplease = require('./utils/otplease.js') +const otplease = require('../utils/otplease.js') const Table = require('cli-table3') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Org extends BaseCommand { static get description () { @@ -48,16 +48,7 @@ class Org extends BaseCommand { } } - exec (args, cb) { - this.org(args) - .then(x => cb(null, x)) - .catch(err => err.code === 'EUSAGE' - ? cb(err.message) - : cb(err) - ) - } - - async org ([cmd, orgname, username, role], cb) { + async exec ([cmd, orgname, username, role], cb) { return otplease(this.npm.flatOptions, opts => { switch (cmd) { case 'add': @@ -68,7 +59,7 @@ class Org extends BaseCommand { case 'ls': return this.ls(orgname, username, opts) default: - throw Object.assign(new Error(this.usage), { code: 'EUSAGE' }) + throw this.usageError() } }) } diff --git a/deps/npm/lib/outdated.js b/deps/npm/lib/commands/outdated.js similarity index 97% rename from deps/npm/lib/outdated.js rename to deps/npm/lib/commands/outdated.js index ab46b453608014..119316d3b4890c 100644 --- a/deps/npm/lib/outdated.js +++ b/deps/npm/lib/commands/outdated.js @@ -10,8 +10,8 @@ const localeCompare = require('@isaacs/string-locale-compare')('en') const Arborist = require('@npmcli/arborist') -const ansiTrim = require('./utils/ansi-trim.js') -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const ansiTrim = require('../utils/ansi-trim.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') class Outdated extends ArboristWorkspaceCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -41,11 +41,7 @@ class Outdated extends ArboristWorkspaceCmd { ] } - exec (args, cb) { - this.outdated(args).then(() => cb()).catch(cb) - } - - async outdated (args) { + async exec (args) { const global = path.resolve(this.npm.globalDir, '..') const where = this.npm.config.get('global') ? global diff --git a/deps/npm/lib/owner.js b/deps/npm/lib/commands/owner.js similarity index 95% rename from deps/npm/lib/owner.js rename to deps/npm/lib/commands/owner.js index 311b25064e6383..5d28e2b750cf5a 100644 --- a/deps/npm/lib/owner.js +++ b/deps/npm/lib/commands/owner.js @@ -3,9 +3,9 @@ const npa = require('npm-package-arg') const npmFetch = require('npm-registry-fetch') const pacote = require('pacote') -const otplease = require('./utils/otplease.js') -const readLocalPkgName = require('./utils/read-package-name.js') -const BaseCommand = require('./base-command.js') +const otplease = require('../utils/otplease.js') +const readLocalPkgName = require('../utils/read-package-name.js') +const BaseCommand = require('../base-command.js') class Owner extends BaseCommand { static get description () { @@ -64,11 +64,7 @@ class Owner extends BaseCommand { return [] } - exec (args, cb) { - this.owner(args).then(() => cb()).catch(cb) - } - - async owner ([action, ...args]) { + async exec ([action, ...args]) { const opts = this.npm.flatOptions switch (action) { case 'ls': diff --git a/deps/npm/lib/pack.js b/deps/npm/lib/commands/pack.js similarity index 86% rename from deps/npm/lib/pack.js rename to deps/npm/lib/commands/pack.js index 848f8afd5ea872..013e88b44a25db 100644 --- a/deps/npm/lib/pack.js +++ b/deps/npm/lib/commands/pack.js @@ -5,11 +5,11 @@ const libpack = require('libnpmpack') const npa = require('npm-package-arg') const path = require('path') -const { getContents, logTar } = require('./utils/tar.js') +const { getContents, logTar } = require('../utils/tar.js') const writeFile = util.promisify(require('fs').writeFile) -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Pack extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -39,15 +39,7 @@ class Pack extends BaseCommand { return ['[[<@scope>/]...]'] } - exec (args, cb) { - this.pack(args).then(() => cb()).catch(cb) - } - - execWorkspaces (args, filters, cb) { - this.packWorkspaces(args, filters).then(() => cb()).catch(cb) - } - - async pack (args) { + async exec (args) { if (args.length === 0) args = ['.'] @@ -94,7 +86,7 @@ class Pack extends BaseCommand { } } - async packWorkspaces (args, filters) { + async execWorkspaces (args, filters) { // If they either ask for nothing, or explicitly include '.' in the args, // we effectively translate that into each workspace requested @@ -102,11 +94,11 @@ class Pack extends BaseCommand { if (!useWorkspaces) { this.npm.log.warn('Ignoring workspaces for specified package(s)') - return this.pack(args) + return this.exec(args) } await this.setWorkspaces(filters) - return this.pack([...this.workspacePaths, ...args.filter(a => a !== '.')]) + return this.exec([...this.workspacePaths, ...args.filter(a => a !== '.')]) } } module.exports = Pack diff --git a/deps/npm/lib/ping.js b/deps/npm/lib/commands/ping.js similarity index 83% rename from deps/npm/lib/ping.js rename to deps/npm/lib/commands/ping.js index fbfb177ff87fcc..d8ad1dc2a281d9 100644 --- a/deps/npm/lib/ping.js +++ b/deps/npm/lib/commands/ping.js @@ -1,6 +1,6 @@ const log = require('npmlog') -const pingUtil = require('./utils/ping.js') -const BaseCommand = require('./base-command.js') +const pingUtil = require('../utils/ping.js') +const BaseCommand = require('../base-command.js') class Ping extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -18,11 +18,7 @@ class Ping extends BaseCommand { return 'ping' } - exec (args, cb) { - this.ping(args).then(() => cb()).catch(cb) - } - - async ping (args) { + async exec (args) { log.notice('PING', this.npm.config.get('registry')) const start = Date.now() const details = await pingUtil(this.npm.flatOptions) diff --git a/deps/npm/lib/pkg.js b/deps/npm/lib/commands/pkg.js similarity index 82% rename from deps/npm/lib/pkg.js rename to deps/npm/lib/commands/pkg.js index 9ba92c930e1f0e..1fa2c3bc5777b6 100644 --- a/deps/npm/lib/pkg.js +++ b/deps/npm/lib/commands/pkg.js @@ -1,6 +1,6 @@ const PackageJson = require('@npmcli/package-json') -const BaseCommand = require('./base-command.js') -const Queryable = require('./utils/queryable.js') +const BaseCommand = require('../base-command.js') +const Queryable = require('../utils/queryable.js') class Pkg extends BaseCommand { static get description () { @@ -31,16 +31,12 @@ class Pkg extends BaseCommand { ] } - exec (args, cb) { - this.prefix = this.npm.localPrefix - this.pkg(args).then(() => cb()).catch(cb) - } - - execWorkspaces (args, filters, cb) { - this.pkgWorkspaces(args, filters).then(() => cb()).catch(cb) - } + async exec (args, { prefix } = {}) { + if (!prefix) + this.prefix = this.npm.localPrefix + else + this.prefix = prefix - async pkg (args) { if (this.npm.config.get('global')) { throw Object.assign( new Error(`There's no package.json file to manage on global mode`), @@ -61,12 +57,12 @@ class Pkg extends BaseCommand { } } - async pkgWorkspaces (args, filters) { + async execWorkspaces (args, filters) { await this.setWorkspaces(filters) const result = {} for (const [workspaceName, workspacePath] of this.workspaces.entries()) { this.prefix = workspacePath - result[workspaceName] = await this.pkg(args) + result[workspaceName] = await this.exec(args, { prefix: workspacePath }) } // when running in workspaces names, make sure to key by workspace // name the results of each value retrieved in each ws @@ -100,10 +96,7 @@ class Pkg extends BaseCommand { async set (args) { const setError = () => - Object.assign( - new TypeError('npm pkg set expects a key=value pair of args.'), - { code: 'EPKGSET' } - ) + this.usageError('npm pkg set expects a key=value pair of args.') if (!args.length) throw setError() @@ -127,10 +120,7 @@ class Pkg extends BaseCommand { async delete (args) { const setError = () => - Object.assign( - new TypeError('npm pkg delete expects key args.'), - { code: 'EPKGDELETE' } - ) + this.usageError('npm pkg delete expects key args.') if (!args.length) throw setError() diff --git a/deps/npm/lib/prefix.js b/deps/npm/lib/commands/prefix.js similarity index 79% rename from deps/npm/lib/prefix.js rename to deps/npm/lib/commands/prefix.js index 172f8d8fadfc8b..1f2a78c312a4f4 100644 --- a/deps/npm/lib/prefix.js +++ b/deps/npm/lib/commands/prefix.js @@ -1,4 +1,4 @@ -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Prefix extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ @@ -21,11 +21,7 @@ class Prefix extends BaseCommand { return ['[-g]'] } - exec (args, cb) { - this.prefix(args).then(() => cb()).catch(cb) - } - - async prefix (args) { + async exec (args) { return this.npm.output(this.npm.prefix) } } diff --git a/deps/npm/lib/profile.js b/deps/npm/lib/commands/profile.js similarity index 97% rename from deps/npm/lib/profile.js rename to deps/npm/lib/commands/profile.js index 36e9b03dcee596..abfe5edd7a9d74 100644 --- a/deps/npm/lib/profile.js +++ b/deps/npm/lib/commands/profile.js @@ -6,9 +6,9 @@ const npmProfile = require('npm-profile') const qrcodeTerminal = require('qrcode-terminal') const Table = require('cli-table3') -const otplease = require('./utils/otplease.js') -const pulseTillDone = require('./utils/pulse-till-done.js') -const readUserInfo = require('./utils/read-user-info.js') +const otplease = require('../utils/otplease.js') +const pulseTillDone = require('../utils/pulse-till-done.js') +const readUserInfo = require('../utils/read-user-info.js') const qrcode = url => new Promise((resolve) => qrcodeTerminal.generate(url, resolve)) @@ -36,7 +36,7 @@ const writableProfileKeys = [ 'github', ] -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Profile extends BaseCommand { static get description () { return 'Change settings on your registry profile' @@ -88,13 +88,9 @@ class Profile extends BaseCommand { } } - exec (args, cb) { - this.profile(args).then(() => cb()).catch(cb) - } - - async profile (args) { + async exec (args) { if (args.length === 0) - throw new Error(this.usage) + throw this.usageError() log.gauge.show('profile') diff --git a/deps/npm/lib/prune.js b/deps/npm/lib/commands/prune.js similarity index 81% rename from deps/npm/lib/prune.js rename to deps/npm/lib/commands/prune.js index a91276fc4fa277..334ee4dd4a9ba6 100644 --- a/deps/npm/lib/prune.js +++ b/deps/npm/lib/commands/prune.js @@ -1,8 +1,8 @@ // prune extraneous packages const Arborist = require('@npmcli/arborist') -const reifyFinish = require('./utils/reify-finish.js') +const reifyFinish = require('../utils/reify-finish.js') -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') class Prune extends ArboristWorkspaceCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -24,11 +24,7 @@ class Prune extends ArboristWorkspaceCmd { return ['[[<@scope>/]...]'] } - exec (args, cb) { - this.prune().then(() => cb()).catch(cb) - } - - async prune () { + async exec () { const where = this.npm.prefix const opts = { ...this.npm.flatOptions, diff --git a/deps/npm/lib/publish.js b/deps/npm/lib/commands/publish.js similarity index 91% rename from deps/npm/lib/publish.js rename to deps/npm/lib/commands/publish.js index 5e064a34bc041f..3bc309c12a15b2 100644 --- a/deps/npm/lib/publish.js +++ b/deps/npm/lib/commands/publish.js @@ -8,23 +8,23 @@ const pacote = require('pacote') const npa = require('npm-package-arg') const npmFetch = require('npm-registry-fetch') const chalk = require('chalk') -const replaceInfo = require('./utils/replace-info.js') +const replaceInfo = require('../utils/replace-info.js') -const otplease = require('./utils/otplease.js') -const { getContents, logTar } = require('./utils/tar.js') +const otplease = require('../utils/otplease.js') +const { getContents, logTar } = require('../utils/tar.js') // for historical reasons, publishConfig in package.json can contain ANY config // keys that npm supports in .npmrc files and elsewhere. We *may* want to // revisit this at some point, and have a minimal set that's a SemVer-major // change that ought to get a RFC written on it. -const flatten = require('./utils/config/flatten.js') +const flatten = require('../utils/config/flatten.js') // this is the only case in the CLI where we want to use the old full slow // 'read-package-json' module, because we want to pull in all the defaults and // metadata, like git sha's and default scripts and all that. const readJson = util.promisify(require('read-package-json')) -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Publish extends BaseCommand { static get description () { return 'Publish a package' @@ -55,15 +55,7 @@ class Publish extends BaseCommand { ] } - exec (args, cb) { - this.publish(args).then(() => cb()).catch(cb) - } - - execWorkspaces (args, filters, cb) { - this.publishWorkspaces(args, filters).then(() => cb()).catch(cb) - } - - async publish (args) { + async exec (args) { if (args.length === 0) args = ['.'] if (args.length !== 1) @@ -157,7 +149,7 @@ class Publish extends BaseCommand { return pkgContents } - async publishWorkspaces (args, filters) { + async execWorkspaces (args, filters) { // Suppresses JSON output in publish() so we can handle it here this.suppressOutput = true @@ -171,7 +163,7 @@ class Publish extends BaseCommand { for (const [name, workspace] of this.workspaces.entries()) { let pkgContents try { - pkgContents = await this.publish([workspace]) + pkgContents = await this.exec([workspace]) } catch (err) { if (err.code === 'EPRIVATE') { log.warn( diff --git a/deps/npm/lib/rebuild.js b/deps/npm/lib/commands/rebuild.js similarity index 91% rename from deps/npm/lib/rebuild.js rename to deps/npm/lib/commands/rebuild.js index 9aa0e27f87eb40..3b9211e2e43bf4 100644 --- a/deps/npm/lib/rebuild.js +++ b/deps/npm/lib/commands/rebuild.js @@ -2,9 +2,9 @@ const { resolve } = require('path') const Arborist = require('@npmcli/arborist') const npa = require('npm-package-arg') const semver = require('semver') -const completion = require('./utils/completion/installed-deep.js') +const completion = require('../utils/completion/installed-deep.js') -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') class Rebuild extends ArboristWorkspaceCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -36,11 +36,7 @@ class Rebuild extends ArboristWorkspaceCmd { return completion(this.npm, opts) } - exec (args, cb) { - this.rebuild(args).then(() => cb()).catch(cb) - } - - async rebuild (args) { + async exec (args) { const globalTop = resolve(this.npm.globalDir, '..') const where = this.npm.config.get('global') ? globalTop : this.npm.prefix const arb = new Arborist({ diff --git a/deps/npm/lib/repo.js b/deps/npm/lib/commands/repo.js similarity index 83% rename from deps/npm/lib/repo.js rename to deps/npm/lib/commands/repo.js index bf1d1e7ff886d1..372940512c6c90 100644 --- a/deps/npm/lib/repo.js +++ b/deps/npm/lib/commands/repo.js @@ -2,10 +2,10 @@ const log = require('npmlog') const pacote = require('pacote') const { URL } = require('url') -const hostedFromMani = require('./utils/hosted-git-info-from-manifest.js') -const openUrl = require('./utils/open-url.js') +const hostedFromMani = require('../utils/hosted-git-info-from-manifest.js') +const openUrl = require('../utils/open-url.js') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Repo extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -27,24 +27,16 @@ class Repo extends BaseCommand { return ['[ [ ...]]'] } - exec (args, cb) { - this.repo(args).then(() => cb()).catch(cb) - } - - execWorkspaces (args, filters, cb) { - this.repoWorkspaces(args, filters).then(() => cb()).catch(cb) - } - - async repo (args) { + async exec (args) { if (!args || !args.length) args = ['.'] await Promise.all(args.map(pkg => this.get(pkg))) } - async repoWorkspaces (args, filters) { + async execWorkspaces (args, filters) { await this.setWorkspaces(filters) - return this.repo(this.workspacePaths) + return this.exec(this.workspacePaths) } async get (pkg) { diff --git a/deps/npm/lib/restart.js b/deps/npm/lib/commands/restart.js similarity index 90% rename from deps/npm/lib/restart.js rename to deps/npm/lib/commands/restart.js index 716ddc909b2be1..f832d6a1e34584 100644 --- a/deps/npm/lib/restart.js +++ b/deps/npm/lib/commands/restart.js @@ -1,4 +1,4 @@ -const LifecycleCmd = require('./utils/lifecycle-cmd.js') +const LifecycleCmd = require('../lifecycle-cmd.js') // This ends up calling run-script(['restart', ...args]) class Restart extends LifecycleCmd { diff --git a/deps/npm/lib/root.js b/deps/npm/lib/commands/root.js similarity index 76% rename from deps/npm/lib/root.js rename to deps/npm/lib/commands/root.js index 635a68e2563184..acfc5c70ef1b75 100644 --- a/deps/npm/lib/root.js +++ b/deps/npm/lib/commands/root.js @@ -1,4 +1,4 @@ -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Root extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -15,11 +15,7 @@ class Root extends BaseCommand { return ['global'] } - exec (args, cb) { - this.root(args).then(() => cb()).catch(cb) - } - - async root () { + async exec () { this.npm.output(this.npm.dir) } } diff --git a/deps/npm/lib/run-script.js b/deps/npm/lib/commands/run-script.js similarity index 93% rename from deps/npm/lib/run-script.js rename to deps/npm/lib/commands/run-script.js index de847ff28b3b5e..34e96257c365af 100644 --- a/deps/npm/lib/run-script.js +++ b/deps/npm/lib/commands/run-script.js @@ -4,8 +4,8 @@ const runScript = require('@npmcli/run-script') const { isServerPackage } = runScript const rpj = require('read-package-json-fast') const log = require('npmlog') -const didYouMean = require('./utils/did-you-mean.js') -const isWindowsShell = require('./utils/is-windows-shell.js') +const didYouMean = require('../utils/did-you-mean.js') +const isWindowsShell = require('../utils/is-windows-shell.js') const cmdList = [ 'publish', @@ -26,7 +26,7 @@ const nocolor = { green: s => s, } -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class RunScript extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -65,18 +65,18 @@ class RunScript extends BaseCommand { } } - exec (args, cb) { + async exec (args) { if (args.length) - this.run(args).then(() => cb()).catch(cb) + return this.run(args) else - this.list(args).then(() => cb()).catch(cb) + return this.list(args) } - execWorkspaces (args, filters, cb) { + async execWorkspaces (args, filters) { if (args.length) - this.runWorkspaces(args, filters).then(() => cb()).catch(cb) + return this.runWorkspaces(args, filters) else - this.listWorkspaces(args, filters).then(() => cb()).catch(cb) + return this.listWorkspaces(args, filters) } async run ([event, ...args], { path = this.npm.localPrefix, pkg } = {}) { diff --git a/deps/npm/lib/search.js b/deps/npm/lib/commands/search.js similarity index 90% rename from deps/npm/lib/search.js rename to deps/npm/lib/commands/search.js index dfb987cc07bfda..e60f41afb03fca 100644 --- a/deps/npm/lib/search.js +++ b/deps/npm/lib/commands/search.js @@ -3,8 +3,8 @@ const Pipeline = require('minipass-pipeline') const libSearch = require('libnpmsearch') const log = require('npmlog') -const formatPackageStream = require('./search/format-package-stream.js') -const packageFilter = require('./search/package-filter.js') +const formatPackageStream = require('../search/format-package-stream.js') +const packageFilter = require('../search/package-filter.js') function prepareIncludes (args) { return args @@ -24,7 +24,7 @@ function prepareExcludes (searchexclude) { .filter(s => s) } -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Search extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -58,11 +58,7 @@ class Search extends BaseCommand { return ['[search terms ...]'] } - exec (args, cb) { - this.search(args).then(() => cb()).catch(cb) - } - - async search (args) { + async exec (args) { const opts = { ...this.npm.flatOptions, ...this.npm.flatOptions.search, diff --git a/deps/npm/lib/set-script.js b/deps/npm/lib/commands/set-script.js similarity index 89% rename from deps/npm/lib/set-script.js rename to deps/npm/lib/commands/set-script.js index 185c4cc901d2eb..00f9b5d5b1745b 100644 --- a/deps/npm/lib/set-script.js +++ b/deps/npm/lib/commands/set-script.js @@ -3,7 +3,7 @@ const log = require('npmlog') const rpj = require('read-package-json-fast') const PackageJson = require('@npmcli/package-json') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class SetScript extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -44,22 +44,14 @@ class SetScript extends BaseCommand { throw new Error(`Expected 2 arguments: got ${args.length}`) } - exec (args, cb) { - this.setScript(args).then(() => cb()).catch(cb) - } - - async setScript (args) { + async exec (args) { this.validate(args) const warn = await this.doSetScript(this.npm.localPrefix, args[0], args[1]) if (warn) log.warn('set-script', `Script "${args[0]}" was overwritten`) } - execWorkspaces (args, filters, cb) { - this.setScriptWorkspaces(args, filters).then(() => cb()).catch(cb) - } - - async setScriptWorkspaces (args, filters) { + async execWorkspaces (args, filters) { this.validate(args) await this.setWorkspaces(filters) diff --git a/deps/npm/lib/set.js b/deps/npm/lib/commands/set.js similarity index 71% rename from deps/npm/lib/set.js rename to deps/npm/lib/commands/set.js index a9f16f3b345121..cdaabc04ac9cea 100644 --- a/deps/npm/lib/set.js +++ b/deps/npm/lib/commands/set.js @@ -1,4 +1,4 @@ -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Set extends BaseCommand { static get description () { @@ -17,13 +17,13 @@ class Set extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ async completion (opts) { - return this.npm.commands.config.completion(opts) + return this.npm.cmd('config').completion(opts) } - exec (args, cb) { + async exec (args) { if (!args.length) - return cb(this.usageError()) - this.npm.commands.config(['set'].concat(args), cb) + throw this.usageError() + return this.npm.exec('config', ['set'].concat(args)) } } module.exports = Set diff --git a/deps/npm/lib/shrinkwrap.js b/deps/npm/lib/commands/shrinkwrap.js similarity index 55% rename from deps/npm/lib/shrinkwrap.js rename to deps/npm/lib/commands/shrinkwrap.js index 5d4a1ada982a49..42489a27f5bfb9 100644 --- a/deps/npm/lib/shrinkwrap.js +++ b/deps/npm/lib/commands/shrinkwrap.js @@ -1,11 +1,9 @@ const { resolve, basename } = require('path') -const util = require('util') -const fs = require('fs') -const { unlink } = fs.promises || { unlink: util.promisify(fs.unlink) } +const { unlink } = require('fs').promises const Arborist = require('@npmcli/arborist') const log = require('npmlog') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Shrinkwrap extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -17,15 +15,10 @@ class Shrinkwrap extends BaseCommand { return 'shrinkwrap' } - exec (args, cb) { - this.shrinkwrap().then(() => cb()).catch(cb) - } - - async shrinkwrap () { + async exec () { // if has a npm-shrinkwrap.json, nothing to do // if has a package-lock.json, rename to npm-shrinkwrap.json // if has neither, load the actual tree and save that as npm-shrinkwrap.json - // in all cases, re-cast to current lockfile version // // loadVirtual, fall back to loadActual // rename shrinkwrap file type, and tree.meta.save() @@ -44,17 +37,37 @@ class Shrinkwrap extends BaseCommand { const oldFilename = meta.filename const notSW = !newFile && basename(oldFilename) !== 'npm-shrinkwrap.json' + // The computed lockfile version of a hidden lockfile is always 3 + // even if the actual value of the property is a different. + // When shrinkwrap is run with only a hidden lockfile we want to + // set the shrinkwrap lockfile version as whatever was explicitly + // requested with a fallback to the actual value from the hidden + // lockfile. + if (meta.hiddenLockfile) { + meta.lockfileVersion = arb.options.lockfileVersion || + meta.originalLockfileVersion + } meta.hiddenLockfile = false meta.filename = sw await meta.save() - if (newFile) - log.notice('', 'created a lockfile as npm-shrinkwrap.json') - else if (notSW) { + const updatedVersion = meta.originalLockfileVersion !== meta.lockfileVersion + ? meta.lockfileVersion + : null + + if (newFile) { + let message = 'created a lockfile as npm-shrinkwrap.json' + if (updatedVersion) + message += ` with version ${updatedVersion}` + log.notice('', message) + } else if (notSW) { await unlink(oldFilename) - log.notice('', 'package-lock.json has been renamed to npm-shrinkwrap.json') - } else if (meta.originalLockfileVersion !== this.npm.lockfileVersion) - log.notice('', `npm-shrinkwrap.json updated to version ${this.npm.lockfileVersion}`) + let message = 'package-lock.json has been renamed to npm-shrinkwrap.json' + if (updatedVersion) + message += ` and updated to version ${updatedVersion}` + log.notice('', message) + } else if (updatedVersion) + log.notice('', `npm-shrinkwrap.json updated to version ${updatedVersion}`) else log.notice('', 'npm-shrinkwrap.json up to date') } diff --git a/deps/npm/lib/star.js b/deps/npm/lib/commands/star.js similarity index 90% rename from deps/npm/lib/star.js rename to deps/npm/lib/commands/star.js index bed9c5c434c92e..36003a02004be4 100644 --- a/deps/npm/lib/star.js +++ b/deps/npm/lib/commands/star.js @@ -2,9 +2,9 @@ const fetch = require('npm-registry-fetch') const log = require('npmlog') const npa = require('npm-package-arg') -const getIdentity = require('./utils/get-identity') +const getIdentity = require('../utils/get-identity') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Star extends BaseCommand { static get description () { return 'Mark your favorite packages' @@ -28,13 +28,9 @@ class Star extends BaseCommand { ] } - exec (args, cb) { - this.star(args).then(() => cb()).catch(cb) - } - - async star (args) { + async exec (args) { if (!args.length) - throw new Error(this.usage) + throw this.usageError() // if we're unstarring, then show an empty star image // otherwise, show the full star image diff --git a/deps/npm/lib/stars.js b/deps/npm/lib/commands/stars.js similarity index 53% rename from deps/npm/lib/stars.js rename to deps/npm/lib/commands/stars.js index f443445153fe27..d430be2ced4efe 100644 --- a/deps/npm/lib/stars.js +++ b/deps/npm/lib/commands/stars.js @@ -1,9 +1,9 @@ const log = require('npmlog') const fetch = require('npm-registry-fetch') -const getIdentity = require('./utils/get-identity.js') +const getIdentity = require('../utils/get-identity.js') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Stars extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -27,28 +27,25 @@ class Stars extends BaseCommand { ] } - exec (args, cb) { - this.stars(args).then(() => cb()).catch(er => { - if (er.code === 'ENEEDAUTH') + async exec ([user]) { + try { + if (!user) + user = await getIdentity(this.npm, this.npm.flatOptions) + + const { rows } = await fetch.json('/-/_view/starredByUser', { + ...this.npm.flatOptions, + query: { key: `"${user}"` }, + }) + if (rows.length === 0) + log.warn('stars', 'user has not starred any packages') + + for (const row of rows) + this.npm.output(row.value) + } catch (err) { + if (err.code === 'ENEEDAUTH') log.warn('stars', 'auth is required to look up your username') - cb(er) - }) - } - - async stars ([user]) { - if (!user) - user = await getIdentity(this.npm, this.npm.flatOptions) - - const { rows } = await fetch.json('/-/_view/starredByUser', { - ...this.npm.flatOptions, - query: { key: `"${user}"` }, - }) - - if (rows.length === 0) - log.warn('stars', 'user has not starred any packages') - - for (const row of rows) - this.npm.output(row.value) + throw err + } } } module.exports = Stars diff --git a/deps/npm/lib/start.js b/deps/npm/lib/commands/start.js similarity index 90% rename from deps/npm/lib/start.js rename to deps/npm/lib/commands/start.js index 0251bff677c6ce..e075c22dfff1fa 100644 --- a/deps/npm/lib/start.js +++ b/deps/npm/lib/commands/start.js @@ -1,4 +1,4 @@ -const LifecycleCmd = require('./utils/lifecycle-cmd.js') +const LifecycleCmd = require('../lifecycle-cmd.js') // This ends up calling run-script(['start', ...args]) class Start extends LifecycleCmd { diff --git a/deps/npm/lib/stop.js b/deps/npm/lib/commands/stop.js similarity index 89% rename from deps/npm/lib/stop.js rename to deps/npm/lib/commands/stop.js index ec5fe76ad678df..869d81fdf16dcb 100644 --- a/deps/npm/lib/stop.js +++ b/deps/npm/lib/commands/stop.js @@ -1,4 +1,4 @@ -const LifecycleCmd = require('./utils/lifecycle-cmd.js') +const LifecycleCmd = require('../lifecycle-cmd.js') // This ends up calling run-script(['stop', ...args]) class Stop extends LifecycleCmd { diff --git a/deps/npm/lib/team.js b/deps/npm/lib/commands/team.js similarity index 95% rename from deps/npm/lib/team.js rename to deps/npm/lib/commands/team.js index 46d5a0977d0bba..b337a7536051f8 100644 --- a/deps/npm/lib/team.js +++ b/deps/npm/lib/commands/team.js @@ -1,9 +1,9 @@ const columns = require('cli-columns') const libteam = require('libnpmteam') -const otplease = require('./utils/otplease.js') +const otplease = require('../utils/otplease.js') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Team extends BaseCommand { static get description () { return 'Manage organization teams and team memberships' @@ -48,11 +48,7 @@ class Team extends BaseCommand { throw new Error(argv[2] + ' not recognized') } - exec (args, cb) { - this.team(args).then(() => cb()).catch(cb) - } - - async team ([cmd, entity = '', user = '']) { + async exec ([cmd, entity = '', user = '']) { // Entities are in the format : // XXX: "description" option to libnpmteam is used as a description of the // team, but in npm's options, this is a boolean meaning "show the @@ -72,7 +68,7 @@ class Team extends BaseCommand { return this.listTeams(entity, opts) } default: - throw this.usage + throw this.usageError() } }) } diff --git a/deps/npm/lib/test.js b/deps/npm/lib/commands/test.js similarity index 89% rename from deps/npm/lib/test.js rename to deps/npm/lib/commands/test.js index 8ab1e8582340ff..ef4048cafa5cfc 100644 --- a/deps/npm/lib/test.js +++ b/deps/npm/lib/commands/test.js @@ -1,4 +1,4 @@ -const LifecycleCmd = require('./utils/lifecycle-cmd.js') +const LifecycleCmd = require('../lifecycle-cmd.js') // This ends up calling run-script(['test', ...args]) class Test extends LifecycleCmd { diff --git a/deps/npm/lib/token.js b/deps/npm/lib/commands/token.js similarity index 95% rename from deps/npm/lib/token.js rename to deps/npm/lib/commands/token.js index 64015d7d40df94..f7b92ea1dde7df 100644 --- a/deps/npm/lib/token.js +++ b/deps/npm/lib/commands/token.js @@ -4,11 +4,11 @@ const { v4: isCidrV4, v6: isCidrV6 } = require('is-cidr') const log = require('npmlog') const profile = require('npm-profile') -const otplease = require('./utils/otplease.js') -const pulseTillDone = require('./utils/pulse-till-done.js') -const readUserInfo = require('./utils/read-user-info.js') +const otplease = require('../utils/otplease.js') +const pulseTillDone = require('../utils/pulse-till-done.js') +const readUserInfo = require('../utils/read-user-info.js') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Token extends BaseCommand { static get description () { return 'Manage your authentication tokens' @@ -50,11 +50,7 @@ class Token extends BaseCommand { throw new Error(argv[2] + ' not recognized') } - exec (args, cb) { - this.token(args).then(() => cb()).catch(cb) - } - - async token (args, cb) { + async exec (args, cb) { log.gauge.show('token') if (args.length === 0) return this.list() diff --git a/deps/npm/lib/uninstall.js b/deps/npm/lib/commands/uninstall.js similarity index 83% rename from deps/npm/lib/uninstall.js rename to deps/npm/lib/commands/uninstall.js index fbb2cef0fbf18e..09b6e47a78f0c3 100644 --- a/deps/npm/lib/uninstall.js +++ b/deps/npm/lib/commands/uninstall.js @@ -2,10 +2,10 @@ const { resolve } = require('path') const Arborist = require('@npmcli/arborist') const rpj = require('read-package-json-fast') -const reifyFinish = require('./utils/reify-finish.js') -const completion = require('./utils/completion/installed-shallow.js') +const reifyFinish = require('../utils/reify-finish.js') +const completion = require('../utils/completion/installed-shallow.js') -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') class Uninstall extends ArboristWorkspaceCmd { static get description () { return 'Remove a package' @@ -31,11 +31,7 @@ class Uninstall extends ArboristWorkspaceCmd { return completion(this.npm, opts) } - exec (args, cb) { - this.uninstall(args).then(() => cb()).catch(cb) - } - - async uninstall (args) { + async exec (args) { // the /path/to/node_modules/.. const global = this.npm.config.get('global') const path = global @@ -54,7 +50,7 @@ class Uninstall extends ArboristWorkspaceCmd { if (er.code !== 'ENOENT' && er.code !== 'ENOTDIR') throw er else - throw this.usage + throw this.usageError() } args.push(pkg.name) diff --git a/deps/npm/lib/unpublish.js b/deps/npm/lib/commands/unpublish.js similarity index 89% rename from deps/npm/lib/unpublish.js rename to deps/npm/lib/commands/unpublish.js index 32a634013a7c47..60ab4a5f9be8be 100644 --- a/deps/npm/lib/unpublish.js +++ b/deps/npm/lib/commands/unpublish.js @@ -6,10 +6,10 @@ const npmFetch = require('npm-registry-fetch') const libunpub = require('libnpmpublish').unpublish const readJson = util.promisify(require('read-package-json')) -const otplease = require('./utils/otplease.js') -const getIdentity = require('./utils/get-identity.js') +const otplease = require('../utils/otplease.js') +const getIdentity = require('../utils/get-identity.js') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Unpublish extends BaseCommand { static get description () { return 'Remove a package from the registry' @@ -62,15 +62,7 @@ class Unpublish extends BaseCommand { return versions.map(v => `${pkgs[0]}@${v}`) } - exec (args, cb) { - this.unpublish(args).then(() => cb()).catch(cb) - } - - execWorkspaces (args, filters, cb) { - this.unpublishWorkspaces(args, filters).then(() => cb()).catch(cb) - } - - async unpublish (args) { + async exec (args) { if (args.length > 1) throw this.usageError() @@ -127,7 +119,7 @@ class Unpublish extends BaseCommand { this.npm.output(`- ${pkgName}${pkgVersion}`) } - async unpublishWorkspaces (args, filters) { + async execWorkspaces (args, filters) { await this.setWorkspaces(filters) const force = this.npm.config.get('force') @@ -139,7 +131,7 @@ class Unpublish extends BaseCommand { } for (const name of this.workspaceNames) - await this.unpublish([name]) + await this.exec([name]) } } module.exports = Unpublish diff --git a/deps/npm/lib/unstar.js b/deps/npm/lib/commands/unstar.js similarity index 91% rename from deps/npm/lib/unstar.js rename to deps/npm/lib/commands/unstar.js index 36ce1daf1a5b86..9f7573a9d12864 100644 --- a/deps/npm/lib/unstar.js +++ b/deps/npm/lib/commands/unstar.js @@ -20,9 +20,9 @@ class Unstar extends Star { ] } - exec (args, cb) { + async exec (args) { this.npm.config.set('star.unstar', true) - super.exec(args, cb) + return super.exec(args) } } module.exports = Unstar diff --git a/deps/npm/lib/update.js b/deps/npm/lib/commands/update.js similarity index 85% rename from deps/npm/lib/update.js rename to deps/npm/lib/commands/update.js index 393c8f0f67e5fd..7423cb7943da0f 100644 --- a/deps/npm/lib/update.js +++ b/deps/npm/lib/commands/update.js @@ -3,10 +3,10 @@ const path = require('path') const Arborist = require('@npmcli/arborist') const log = require('npmlog') -const reifyFinish = require('./utils/reify-finish.js') -const completion = require('./utils/completion/installed-deep.js') +const reifyFinish = require('../utils/reify-finish.js') +const completion = require('../utils/completion/installed-deep.js') -const ArboristWorkspaceCmd = require('./workspaces/arborist-cmd.js') +const ArboristWorkspaceCmd = require('../arborist-cmd.js') class Update extends ArboristWorkspaceCmd { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -46,11 +46,7 @@ class Update extends ArboristWorkspaceCmd { return completion(this.npm, opts) } - exec (args, cb) { - this.update(args).then(() => cb()).catch(cb) - } - - async update (args) { + async exec (args) { const update = args.length === 0 ? true : args const global = path.resolve(this.npm.globalDir, '..') const where = this.npm.config.get('global') diff --git a/deps/npm/lib/version.js b/deps/npm/lib/commands/version.js similarity index 89% rename from deps/npm/lib/version.js rename to deps/npm/lib/commands/version.js index 917a647474b959..60e1e36f580803 100644 --- a/deps/npm/lib/version.js +++ b/deps/npm/lib/commands/version.js @@ -3,7 +3,7 @@ const { resolve } = require('path') const { promisify } = require('util') const readFile = promisify(require('fs').readFile) -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Version extends BaseCommand { static get description () { @@ -52,33 +52,25 @@ class Version extends BaseCommand { ] } - exec (args, cb) { - return this.version(args).then(() => cb()).catch(cb) - } - - execWorkspaces (args, filters, cb) { - this.versionWorkspaces(args, filters).then(() => cb()).catch(cb) - } - - async version (args) { + async exec (args) { switch (args.length) { case 0: return this.list() case 1: return this.change(args) default: - throw this.usage + throw this.usageError() } } - async versionWorkspaces (args, filters) { + async execWorkspaces (args, filters) { switch (args.length) { case 0: return this.listWorkspaces(filters) case 1: return this.changeWorkspaces(args, filters) default: - throw this.usage + throw this.usageError() } } diff --git a/deps/npm/lib/view.js b/deps/npm/lib/commands/view.js similarity index 97% rename from deps/npm/lib/view.js rename to deps/npm/lib/commands/view.js index 46b1b5edfea7aa..24d13cfcfb3df4 100644 --- a/deps/npm/lib/view.js +++ b/deps/npm/lib/commands/view.js @@ -7,7 +7,7 @@ const jsonParse = require('json-parse-even-better-errors') const log = require('npmlog') const npa = require('npm-package-arg') const { resolve } = require('path') -const formatBytes = require('./utils/format-bytes.js') +const formatBytes = require('../utils/format-bytes.js') const relativeDate = require('tiny-relative-date') const semver = require('semver') const style = require('ansistyles') @@ -17,8 +17,8 @@ const { packument } = require('pacote') const readFile = promisify(fs.readFile) const readJson = async file => jsonParse(await readFile(file, 'utf8')) -const Queryable = require('./utils/queryable.js') -const BaseCommand = require('./base-command.js') +const Queryable = require('../utils/queryable.js') +const BaseCommand = require('../base-command.js') class View extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -92,15 +92,7 @@ class View extends BaseCommand { } } - exec (args, cb) { - this.view(args).then(() => cb()).catch(cb) - } - - execWorkspaces (args, filters, cb) { - this.viewWorkspaces(args, filters).then(() => cb()).catch(cb) - } - - async view (args) { + async exec (args) { if (!args.length) args = ['.'] let pkg = args.shift() @@ -144,7 +136,7 @@ class View extends BaseCommand { } } - async viewWorkspaces (args, filters) { + async execWorkspaces (args, filters) { if (!args.length) args = ['.'] @@ -153,7 +145,7 @@ class View extends BaseCommand { const local = /^\.@/.test(pkg) || pkg === '.' if (!local) { this.npm.log.warn('Ignoring workspaces for specified package(s)') - return this.view([pkg, ...args]) + return this.exec([pkg, ...args]) } let wholePackument = false if (!args.length) { diff --git a/deps/npm/lib/whoami.js b/deps/npm/lib/commands/whoami.js similarity index 74% rename from deps/npm/lib/whoami.js rename to deps/npm/lib/commands/whoami.js index 82c4520d9e8830..6b6f43f01687ff 100644 --- a/deps/npm/lib/whoami.js +++ b/deps/npm/lib/commands/whoami.js @@ -1,6 +1,6 @@ -const getIdentity = require('./utils/get-identity.js') +const getIdentity = require('../utils/get-identity.js') -const BaseCommand = require('./base-command.js') +const BaseCommand = require('../base-command.js') class Whoami extends BaseCommand { /* istanbul ignore next - see test/lib/load-all-commands.js */ static get description () { @@ -17,11 +17,7 @@ class Whoami extends BaseCommand { return ['registry'] } - exec (args, cb) { - this.whoami(args).then(() => cb()).catch(cb) - } - - async whoami (args) { + async exec (args) { const username = await getIdentity(this.npm, this.npm.flatOptions) this.npm.output( this.npm.config.get('json') ? JSON.stringify(username) : username diff --git a/deps/npm/lib/lifecycle-cmd.js b/deps/npm/lib/lifecycle-cmd.js new file mode 100644 index 00000000000000..a00d58334d0bc1 --- /dev/null +++ b/deps/npm/lib/lifecycle-cmd.js @@ -0,0 +1,18 @@ +// The implementation of commands that are just "run a script" +// restart, start, stop, test + +const BaseCommand = require('./base-command.js') +class LifecycleCmd extends BaseCommand { + static get usage () { + return ['[-- ]'] + } + + async exec (args, cb) { + return this.npm.exec('run-script', [this.constructor.name, ...args]) + } + + async execWorkspaces (args, filters, cb) { + return this.npm.exec('run-script', [this.constructor.name, ...args]) + } +} +module.exports = LifecycleCmd diff --git a/deps/npm/lib/npm.js b/deps/npm/lib/npm.js index 63c5ede8a53edc..4b7b3440ff5ca2 100644 --- a/deps/npm/lib/npm.js +++ b/deps/npm/lib/npm.js @@ -9,29 +9,6 @@ require('graceful-fs').gracefulify(require('fs')) // TODO make this only ever load once (or unload) in tests const procLogListener = require('./utils/proc-log-listener.js') -const proxyCmds = new Proxy({}, { - get: (target, cmd) => { - const actual = deref(cmd) - if (actual && !Reflect.has(target, actual)) { - const Impl = require(`./${actual}.js`) - const impl = new Impl(npm) - // Our existing npm.commands[x] act like a function with attributes, but - // our modules have non-inumerable attributes so we can't just assign - // them to an anonymous function like we used to. This acts like that - // old way of doing things, until we can make breaking changes to the - // npm.commands[x] api - target[actual] = new Proxy( - (args, cb) => npm[_runCmd](actual, impl, args, cb), - { - get: (target, attr, receiver) => { - return Reflect.get(impl, attr, receiver) - }, - }) - } - return target[actual] - }, -}) - // Timers in progress const timers = new Map() // Finished timers @@ -63,23 +40,26 @@ const cleanUpLogFiles = require('./utils/cleanup-log-files.js') const getProjectScope = require('./utils/get-project-scope.js') let warnedNonDashArg = false -const _runCmd = Symbol('_runCmd') const _load = Symbol('_load') const _tmpFolder = Symbol('_tmpFolder') const _title = Symbol('_title') +const pkg = require('../package.json') + +class Npm extends EventEmitter { + static get version () { + return pkg.version + } -const npm = module.exports = new class extends EventEmitter { constructor () { super() this.started = Date.now() this.command = null - this.commands = proxyCmds this.timings = timings this.timers = timers - this.perfStart() + process.on('time', processOnTimeHandler) + process.on('timeEnd', processOnTimeEndHandler) procLogListener() process.emit('time', 'npm') - this.version = require('../package.json').version this.config = new Config({ npmPath: dirname(__dirname), definitions, @@ -90,14 +70,8 @@ const npm = module.exports = new class extends EventEmitter { this.updateNotification = null } - perfStart () { - process.on('time', processOnTimeHandler) - process.on('timeEnd', processOnTimeEndHandler) - } - - perfStop () { - process.off('time', processOnTimeHandler) - process.off('timeEnd', processOnTimeEndHandler) + get version () { + return this.constructor.version } get shelloutCommands () { @@ -108,21 +82,32 @@ const npm = module.exports = new class extends EventEmitter { return deref(c) } - // this will only ever be called with cmd set to the canonical command name - [_runCmd] (cmd, impl, args, cb) { - if (!this.loaded) { - throw new Error( - 'Call npm.load() before using this command.\n' + - 'See lib/cli.js for example usage.' - ) + // Get an instantiated npm command + // npm.command is already taken as the currently running command, a refactor + // would be needed to change this + async cmd (cmd) { + await this.load() + const command = this.deref(cmd) + if (!command) { + throw Object.assign(new Error(`Unknown command ${cmd}`), { + code: 'EUNKNOWNCOMMAND', + }) } + const Impl = require(`./commands/${command}.js`) + const impl = new Impl(this) + return impl + } + // Call an npm command + async exec (cmd, args) { + const command = await this.cmd(cmd) process.emit('time', `command:${cmd}`) + // since 'test', 'start', 'stop', etc. commands re-enter this function // to call the run-script command, we need to only set it one time. if (!this.command) { - process.env.npm_command = cmd - this.command = cmd + process.env.npm_command = command.name + this.command = command.name } // Options are prefixed by a hyphen-minus (-, \u2d). @@ -138,42 +123,38 @@ const npm = module.exports = new class extends EventEmitter { const workspacesEnabled = this.config.get('workspaces') const workspacesFilters = this.config.get('workspace') if (workspacesEnabled === false && workspacesFilters.length > 0) - return cb(new Error('Can not use --no-workspaces and --workspace at the same time')) + throw new Error('Can not use --no-workspaces and --workspace at the same time') const filterByWorkspaces = workspacesEnabled || workspacesFilters.length > 0 // normally this would go in the constructor, but our tests don't // actually use a real npm object so this.npm.config isn't always // populated. this is the compromise until we can make that a reality // and then move this into the constructor. - impl.workspaces = this.config.get('workspaces') - impl.workspacePaths = null + command.workspaces = this.config.get('workspaces') + command.workspacePaths = null // normally this would be evaluated in base-command#setWorkspaces, see // above for explanation - impl.includeWorkspaceRoot = this.config.get('include-workspace-root') + command.includeWorkspaceRoot = this.config.get('include-workspace-root') if (this.config.get('usage')) { - this.output(impl.usage) - cb() - } else if (filterByWorkspaces) { + this.output(command.usage) + return + } + if (filterByWorkspaces) { if (this.config.get('global')) - return cb(new Error('Workspaces not supported for global packages')) + throw new Error('Workspaces not supported for global packages') - impl.execWorkspaces(args, this.config.get('workspace'), er => { + return command.execWorkspaces(args, this.config.get('workspace')).finally(() => { process.emit('timeEnd', `command:${cmd}`) - cb(er) }) } else { - impl.exec(args, er => { + return command.exec(args).finally(() => { process.emit('timeEnd', `command:${cmd}`) - cb(er) }) } } - load (cb) { - if (cb && typeof cb !== 'function') - throw new TypeError('callback must be a function if provided') - + async load () { if (!this.loadPromise) { process.emit('time', 'npm:load') this.log.pause() @@ -190,12 +171,7 @@ const npm = module.exports = new class extends EventEmitter { }) }) } - if (!cb) - return this.loadPromise - - // loadPromise is returned here for legacy purposes, old code was allowing - // the mixing of callback and promise here. - return this.loadPromise.then(cb, cb) + return this.loadPromise } get loaded () { @@ -366,4 +342,5 @@ const npm = module.exports = new class extends EventEmitter { console.log(...msg) this.log.showProgress() } -}() +} +module.exports = Npm diff --git a/deps/npm/lib/utils/did-you-mean.js b/deps/npm/lib/utils/did-you-mean.js index c324253af24065..953048309856b3 100644 --- a/deps/npm/lib/utils/did-you-mean.js +++ b/deps/npm/lib/utils/did-you-mean.js @@ -3,10 +3,14 @@ const readJson = require('read-package-json-fast') const { cmdList } = require('./cmd-list.js') const didYouMean = async (npm, path, scmd) => { - let best = cmdList + // const cmd = await npm.cmd(str) + const close = cmdList .filter(cmd => distance(scmd, cmd) < scmd.length * 0.4 && scmd !== cmd) - .map(str => ` npm ${str} # ${npm.commands[str].description}`) - + let best = [] + for (const str of close) { + const cmd = await npm.cmd(str) + best.push(` npm ${str} # ${cmd.description}`) + } // We would already be suggesting this in `npm x` so omit them here const runScripts = ['stop', 'start', 'test', 'restart'] try { diff --git a/deps/npm/lib/utils/lifecycle-cmd.js b/deps/npm/lib/utils/lifecycle-cmd.js deleted file mode 100644 index 2c5b89dfcdd048..00000000000000 --- a/deps/npm/lib/utils/lifecycle-cmd.js +++ /dev/null @@ -1,18 +0,0 @@ -// The implementation of commands that are just "run a script" -// restart, start, stop, test - -const BaseCommand = require('../base-command.js') -class LifecycleCmd extends BaseCommand { - static get usage () { - return ['[-- ]'] - } - - exec (args, cb) { - this.npm.commands['run-script']([this.constructor.name, ...args], cb) - } - - execWorkspaces (args, filters, cb) { - this.npm.commands['run-script']([this.constructor.name, ...args], cb) - } -} -module.exports = LifecycleCmd diff --git a/deps/npm/lib/utils/npm-usage.js b/deps/npm/lib/utils/npm-usage.js index f6785867c0ae54..d54c8ac5479dc8 100644 --- a/deps/npm/lib/utils/npm-usage.js +++ b/deps/npm/lib/utils/npm-usage.js @@ -2,7 +2,7 @@ const { dirname } = require('path') const { cmdList } = require('./cmd-list') const localeCompare = require('@isaacs/string-locale-compare')('en') -module.exports = (npm) => { +module.exports = async (npm) => { const usesBrowser = npm.config.get('viewer') === 'browser' ? ' (in a browser)' : '' return `npm @@ -19,7 +19,7 @@ npm help search for help on ${usesBrowser} npm help npm more involved overview${usesBrowser} All commands: -${allCommands(npm)} +${await allCommands(npm)} Specify configs in the ini-formatted file: ${npm.config.get('userconfig')} @@ -31,7 +31,7 @@ Configuration fields: npm help 7 config npm@${npm.version} ${dirname(dirname(__dirname))}` } -const allCommands = (npm) => { +const allCommands = async (npm) => { if (npm.config.get('long')) return usages(npm) return ('\n ' + wrap(cmdList)) @@ -55,15 +55,16 @@ const wrap = (arr) => { return out.join('\n ').substr(2) } -const usages = (npm) => { +const usages = async (npm) => { // return a string of : let maxLen = 0 - return cmdList.reduce((set, c) => { - set.push([c, npm.commands[c].usage]) + const set = [] + for (const c of cmdList) { + const cmd = await npm.cmd(c) + set.push([c, cmd.usage]) maxLen = Math.max(maxLen, c.length) - return set - }, []) - .sort(([a], [b]) => localeCompare(a, b)) + } + return set.sort(([a], [b]) => localeCompare(a, b)) .map(([c, usage]) => `\n ${c}${' '.repeat(maxLen - c.length + 1)}${ (usage.split('\n').join('\n' + ' '.repeat(maxLen + 5)))}`) .join('\n') diff --git a/deps/npm/lib/utils/reify-finish.js b/deps/npm/lib/utils/reify-finish.js index 1c02b93a412949..a9ac4c61f5b8e6 100644 --- a/deps/npm/lib/utils/reify-finish.js +++ b/deps/npm/lib/utils/reify-finish.js @@ -1,8 +1,6 @@ const reifyOutput = require('./reify-output.js') const ini = require('ini') -const util = require('util') -const fs = require('fs') -const { writeFile } = fs.promises || { writeFile: util.promisify(fs.writeFile) } +const { writeFile } = require('fs').promises const {resolve} = require('path') const reifyFinish = async (npm, arb) => { diff --git a/deps/npm/man/man1/npm-access.1 b/deps/npm/man/man1/npm-access.1 index 2b4165b5f38197..6ee369df5a920c 100644 --- a/deps/npm/man/man1/npm-access.1 +++ b/deps/npm/man/man1/npm-access.1 @@ -1,4 +1,4 @@ -.TH "NPM\-ACCESS" "1" "October 2021" "" "" +.TH "NPM\-ACCESS" "1" "November 2021" "" "" .SH "NAME" \fBnpm-access\fR \- Set access level on published packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-adduser.1 b/deps/npm/man/man1/npm-adduser.1 index e4820299c8c71e..10d035f75304b8 100644 --- a/deps/npm/man/man1/npm-adduser.1 +++ b/deps/npm/man/man1/npm-adduser.1 @@ -1,4 +1,4 @@ -.TH "NPM\-ADDUSER" "1" "October 2021" "" "" +.TH "NPM\-ADDUSER" "1" "November 2021" "" "" .SH "NAME" \fBnpm-adduser\fR \- Add a registry user account .SS Synopsis diff --git a/deps/npm/man/man1/npm-audit.1 b/deps/npm/man/man1/npm-audit.1 index 50199ed00f9c6b..4f2c25c6753fe8 100644 --- a/deps/npm/man/man1/npm-audit.1 +++ b/deps/npm/man/man1/npm-audit.1 @@ -1,4 +1,4 @@ -.TH "NPM\-AUDIT" "1" "October 2021" "" "" +.TH "NPM\-AUDIT" "1" "November 2021" "" "" .SH "NAME" \fBnpm-audit\fR \- Run a security audit .SS Synopsis diff --git a/deps/npm/man/man1/npm-bin.1 b/deps/npm/man/man1/npm-bin.1 index 49fda132144d49..927373bc4be172 100644 --- a/deps/npm/man/man1/npm-bin.1 +++ b/deps/npm/man/man1/npm-bin.1 @@ -1,4 +1,4 @@ -.TH "NPM\-BIN" "1" "October 2021" "" "" +.TH "NPM\-BIN" "1" "November 2021" "" "" .SH "NAME" \fBnpm-bin\fR \- Display npm bin folder .SS Synopsis diff --git a/deps/npm/man/man1/npm-bugs.1 b/deps/npm/man/man1/npm-bugs.1 index 2d7ab52ee2efc4..2356611d4c5776 100644 --- a/deps/npm/man/man1/npm-bugs.1 +++ b/deps/npm/man/man1/npm-bugs.1 @@ -1,4 +1,4 @@ -.TH "NPM\-BUGS" "1" "October 2021" "" "" +.TH "NPM\-BUGS" "1" "November 2021" "" "" .SH "NAME" \fBnpm-bugs\fR \- Report bugs for a package in a web browser .SS Synopsis diff --git a/deps/npm/man/man1/npm-cache.1 b/deps/npm/man/man1/npm-cache.1 index f8d27facf85cb1..1f93ecf7e551d5 100644 --- a/deps/npm/man/man1/npm-cache.1 +++ b/deps/npm/man/man1/npm-cache.1 @@ -1,4 +1,4 @@ -.TH "NPM\-CACHE" "1" "October 2021" "" "" +.TH "NPM\-CACHE" "1" "November 2021" "" "" .SH "NAME" \fBnpm-cache\fR \- Manipulates packages cache .SS Synopsis diff --git a/deps/npm/man/man1/npm-ci.1 b/deps/npm/man/man1/npm-ci.1 index 44bba089603889..9e9951fbbf64e3 100644 --- a/deps/npm/man/man1/npm-ci.1 +++ b/deps/npm/man/man1/npm-ci.1 @@ -1,4 +1,4 @@ -.TH "NPM\-CI" "1" "October 2021" "" "" +.TH "NPM\-CI" "1" "November 2021" "" "" .SH "NAME" \fBnpm-ci\fR \- Install a project with a clean slate .SS Synopsis diff --git a/deps/npm/man/man1/npm-completion.1 b/deps/npm/man/man1/npm-completion.1 index ec9d085f2dfdab..c79b8b0d889c45 100644 --- a/deps/npm/man/man1/npm-completion.1 +++ b/deps/npm/man/man1/npm-completion.1 @@ -1,4 +1,4 @@ -.TH "NPM\-COMPLETION" "1" "October 2021" "" "" +.TH "NPM\-COMPLETION" "1" "November 2021" "" "" .SH "NAME" \fBnpm-completion\fR \- Tab Completion for npm .SS Synopsis diff --git a/deps/npm/man/man1/npm-config.1 b/deps/npm/man/man1/npm-config.1 index a28909f0240cf7..87b2e4082b62a6 100644 --- a/deps/npm/man/man1/npm-config.1 +++ b/deps/npm/man/man1/npm-config.1 @@ -1,4 +1,4 @@ -.TH "NPM\-CONFIG" "1" "October 2021" "" "" +.TH "NPM\-CONFIG" "1" "November 2021" "" "" .SH "NAME" \fBnpm-config\fR \- Manage the npm configuration files .SS Synopsis diff --git a/deps/npm/man/man1/npm-dedupe.1 b/deps/npm/man/man1/npm-dedupe.1 index 647d079b2ed013..e619784485cc39 100644 --- a/deps/npm/man/man1/npm-dedupe.1 +++ b/deps/npm/man/man1/npm-dedupe.1 @@ -1,4 +1,4 @@ -.TH "NPM\-DEDUPE" "1" "October 2021" "" "" +.TH "NPM\-DEDUPE" "1" "November 2021" "" "" .SH "NAME" \fBnpm-dedupe\fR \- Reduce duplication in the package tree .SS Synopsis diff --git a/deps/npm/man/man1/npm-deprecate.1 b/deps/npm/man/man1/npm-deprecate.1 index 73a2c73b58cc9a..a4eb24c0be060e 100644 --- a/deps/npm/man/man1/npm-deprecate.1 +++ b/deps/npm/man/man1/npm-deprecate.1 @@ -1,4 +1,4 @@ -.TH "NPM\-DEPRECATE" "1" "October 2021" "" "" +.TH "NPM\-DEPRECATE" "1" "November 2021" "" "" .SH "NAME" \fBnpm-deprecate\fR \- Deprecate a version of a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-diff.1 b/deps/npm/man/man1/npm-diff.1 index a03ef8012893bd..74e801df1e6035 100644 --- a/deps/npm/man/man1/npm-diff.1 +++ b/deps/npm/man/man1/npm-diff.1 @@ -1,4 +1,4 @@ -.TH "NPM\-DIFF" "1" "October 2021" "" "" +.TH "NPM\-DIFF" "1" "November 2021" "" "" .SH "NAME" \fBnpm-diff\fR \- The registry diff command .SS Synopsis diff --git a/deps/npm/man/man1/npm-dist-tag.1 b/deps/npm/man/man1/npm-dist-tag.1 index f6c62ad17ecafc..5d52da1d13953a 100644 --- a/deps/npm/man/man1/npm-dist-tag.1 +++ b/deps/npm/man/man1/npm-dist-tag.1 @@ -1,4 +1,4 @@ -.TH "NPM\-DIST\-TAG" "1" "October 2021" "" "" +.TH "NPM\-DIST\-TAG" "1" "November 2021" "" "" .SH "NAME" \fBnpm-dist-tag\fR \- Modify package distribution tags .SS Synopsis diff --git a/deps/npm/man/man1/npm-docs.1 b/deps/npm/man/man1/npm-docs.1 index 48c01c74cd825c..edbeef32a4430a 100644 --- a/deps/npm/man/man1/npm-docs.1 +++ b/deps/npm/man/man1/npm-docs.1 @@ -1,4 +1,4 @@ -.TH "NPM\-DOCS" "1" "October 2021" "" "" +.TH "NPM\-DOCS" "1" "November 2021" "" "" .SH "NAME" \fBnpm-docs\fR \- Open documentation for a package in a web browser .SS Synopsis diff --git a/deps/npm/man/man1/npm-doctor.1 b/deps/npm/man/man1/npm-doctor.1 index 69e1112ba29908..9c371ff0cce6d9 100644 --- a/deps/npm/man/man1/npm-doctor.1 +++ b/deps/npm/man/man1/npm-doctor.1 @@ -1,4 +1,4 @@ -.TH "NPM\-DOCTOR" "1" "October 2021" "" "" +.TH "NPM\-DOCTOR" "1" "November 2021" "" "" .SH "NAME" \fBnpm-doctor\fR \- Check your npm environment .SS Synopsis diff --git a/deps/npm/man/man1/npm-edit.1 b/deps/npm/man/man1/npm-edit.1 index b157e053b67220..b8b0404eb5aefd 100644 --- a/deps/npm/man/man1/npm-edit.1 +++ b/deps/npm/man/man1/npm-edit.1 @@ -1,4 +1,4 @@ -.TH "NPM\-EDIT" "1" "October 2021" "" "" +.TH "NPM\-EDIT" "1" "November 2021" "" "" .SH "NAME" \fBnpm-edit\fR \- Edit an installed package .SS Synopsis diff --git a/deps/npm/man/man1/npm-exec.1 b/deps/npm/man/man1/npm-exec.1 index 1a5b5e3ab761d1..6d6100c15d3997 100644 --- a/deps/npm/man/man1/npm-exec.1 +++ b/deps/npm/man/man1/npm-exec.1 @@ -1,4 +1,4 @@ -.TH "NPM\-EXEC" "1" "October 2021" "" "" +.TH "NPM\-EXEC" "1" "November 2021" "" "" .SH "NAME" \fBnpm-exec\fR \- Run a command from a local or remote npm package .SS Synopsis diff --git a/deps/npm/man/man1/npm-explain.1 b/deps/npm/man/man1/npm-explain.1 index 7be793018f489e..239c988cf5a187 100644 --- a/deps/npm/man/man1/npm-explain.1 +++ b/deps/npm/man/man1/npm-explain.1 @@ -1,4 +1,4 @@ -.TH "NPM\-EXPLAIN" "1" "October 2021" "" "" +.TH "NPM\-EXPLAIN" "1" "November 2021" "" "" .SH "NAME" \fBnpm-explain\fR \- Explain installed packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-explore.1 b/deps/npm/man/man1/npm-explore.1 index c0878727f65a59..8f0097241d7c97 100644 --- a/deps/npm/man/man1/npm-explore.1 +++ b/deps/npm/man/man1/npm-explore.1 @@ -1,4 +1,4 @@ -.TH "NPM\-EXPLORE" "1" "October 2021" "" "" +.TH "NPM\-EXPLORE" "1" "November 2021" "" "" .SH "NAME" \fBnpm-explore\fR \- Browse an installed package .SS Synopsis diff --git a/deps/npm/man/man1/npm-find-dupes.1 b/deps/npm/man/man1/npm-find-dupes.1 index ccba76e2c85d89..49fff29263f000 100644 --- a/deps/npm/man/man1/npm-find-dupes.1 +++ b/deps/npm/man/man1/npm-find-dupes.1 @@ -1,4 +1,4 @@ -.TH "NPM\-FIND\-DUPES" "1" "October 2021" "" "" +.TH "NPM\-FIND\-DUPES" "1" "November 2021" "" "" .SH "NAME" \fBnpm-find-dupes\fR \- Find duplication in the package tree .SS Synopsis diff --git a/deps/npm/man/man1/npm-fund.1 b/deps/npm/man/man1/npm-fund.1 index 9743e3eef7a42c..de01552c76daf9 100644 --- a/deps/npm/man/man1/npm-fund.1 +++ b/deps/npm/man/man1/npm-fund.1 @@ -1,4 +1,4 @@ -.TH "NPM\-FUND" "1" "October 2021" "" "" +.TH "NPM\-FUND" "1" "November 2021" "" "" .SH "NAME" \fBnpm-fund\fR \- Retrieve funding information .SS Synopsis diff --git a/deps/npm/man/man1/npm-help-search.1 b/deps/npm/man/man1/npm-help-search.1 index 22107cbd0f7ac4..12ee237f06c074 100644 --- a/deps/npm/man/man1/npm-help-search.1 +++ b/deps/npm/man/man1/npm-help-search.1 @@ -1,4 +1,4 @@ -.TH "NPM\-HELP\-SEARCH" "1" "October 2021" "" "" +.TH "NPM\-HELP\-SEARCH" "1" "November 2021" "" "" .SH "NAME" \fBnpm-help-search\fR \- Search npm help documentation .SS Synopsis diff --git a/deps/npm/man/man1/npm-help.1 b/deps/npm/man/man1/npm-help.1 index eaf8fd26e18637..aa62e72ac016d3 100644 --- a/deps/npm/man/man1/npm-help.1 +++ b/deps/npm/man/man1/npm-help.1 @@ -1,4 +1,4 @@ -.TH "NPM\-HELP" "1" "October 2021" "" "" +.TH "NPM\-HELP" "1" "November 2021" "" "" .SH "NAME" \fBnpm-help\fR \- Get help on npm .SS Synopsis diff --git a/deps/npm/man/man1/npm-hook.1 b/deps/npm/man/man1/npm-hook.1 index 20f5af5615d55a..8ebd352d87bf76 100644 --- a/deps/npm/man/man1/npm-hook.1 +++ b/deps/npm/man/man1/npm-hook.1 @@ -1,4 +1,4 @@ -.TH "NPM\-HOOK" "1" "October 2021" "" "" +.TH "NPM\-HOOK" "1" "November 2021" "" "" .SH "NAME" \fBnpm-hook\fR \- Manage registry hooks .SS Synopsis diff --git a/deps/npm/man/man1/npm-init.1 b/deps/npm/man/man1/npm-init.1 index ce2e8d410d08b4..65108e2c0778af 100644 --- a/deps/npm/man/man1/npm-init.1 +++ b/deps/npm/man/man1/npm-init.1 @@ -1,4 +1,4 @@ -.TH "NPM\-INIT" "1" "October 2021" "" "" +.TH "NPM\-INIT" "1" "November 2021" "" "" .SH "NAME" \fBnpm-init\fR \- Create a package\.json file .SS Synopsis diff --git a/deps/npm/man/man1/npm-install-ci-test.1 b/deps/npm/man/man1/npm-install-ci-test.1 index b92b9af0e5f065..df9f22e7da56c3 100644 --- a/deps/npm/man/man1/npm-install-ci-test.1 +++ b/deps/npm/man/man1/npm-install-ci-test.1 @@ -1,4 +1,4 @@ -.TH "NPM\-INSTALL\-CI\-TEST" "1" "October 2021" "" "" +.TH "NPM\-INSTALL\-CI\-TEST" "1" "November 2021" "" "" .SH "NAME" \fBnpm-install-ci-test\fR \- Install a project with a clean slate and run tests .SS Synopsis diff --git a/deps/npm/man/man1/npm-install-test.1 b/deps/npm/man/man1/npm-install-test.1 index 91e1fc1684e808..7250721f6d63b4 100644 --- a/deps/npm/man/man1/npm-install-test.1 +++ b/deps/npm/man/man1/npm-install-test.1 @@ -1,4 +1,4 @@ -.TH "NPM\-INSTALL\-TEST" "1" "October 2021" "" "" +.TH "NPM\-INSTALL\-TEST" "1" "November 2021" "" "" .SH "NAME" \fBnpm-install-test\fR \- Install package(s) and run tests .SS Synopsis diff --git a/deps/npm/man/man1/npm-install.1 b/deps/npm/man/man1/npm-install.1 index f803da89b21e43..aa13fa70cfc18c 100644 --- a/deps/npm/man/man1/npm-install.1 +++ b/deps/npm/man/man1/npm-install.1 @@ -1,4 +1,4 @@ -.TH "NPM\-INSTALL" "1" "October 2021" "" "" +.TH "NPM\-INSTALL" "1" "November 2021" "" "" .SH "NAME" \fBnpm-install\fR \- Install a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-link.1 b/deps/npm/man/man1/npm-link.1 index 8e1086b044581d..83700438ce032c 100644 --- a/deps/npm/man/man1/npm-link.1 +++ b/deps/npm/man/man1/npm-link.1 @@ -1,4 +1,4 @@ -.TH "NPM\-LINK" "1" "October 2021" "" "" +.TH "NPM\-LINK" "1" "November 2021" "" "" .SH "NAME" \fBnpm-link\fR \- Symlink a package folder .SS Synopsis diff --git a/deps/npm/man/man1/npm-logout.1 b/deps/npm/man/man1/npm-logout.1 index bc7c1d32eda9c3..a9f0ebe55e17e6 100644 --- a/deps/npm/man/man1/npm-logout.1 +++ b/deps/npm/man/man1/npm-logout.1 @@ -1,4 +1,4 @@ -.TH "NPM\-LOGOUT" "1" "October 2021" "" "" +.TH "NPM\-LOGOUT" "1" "November 2021" "" "" .SH "NAME" \fBnpm-logout\fR \- Log out of the registry .SS Synopsis diff --git a/deps/npm/man/man1/npm-ls.1 b/deps/npm/man/man1/npm-ls.1 index 99609df8d79047..ec9ee9c106798a 100644 --- a/deps/npm/man/man1/npm-ls.1 +++ b/deps/npm/man/man1/npm-ls.1 @@ -1,4 +1,4 @@ -.TH "NPM\-LS" "1" "October 2021" "" "" +.TH "NPM\-LS" "1" "November 2021" "" "" .SH "NAME" \fBnpm-ls\fR \- List installed packages .SS Synopsis @@ -26,7 +26,7 @@ example, running \fBnpm ls promzard\fP in npm's source tree will show: .P .RS 2 .nf -npm@8\.1\.2 /path/to/npm +npm@8\.1\.3 /path/to/npm └─┬ init\-package\-json@0\.0\.4 └── promzard@0\.1\.5 .fi diff --git a/deps/npm/man/man1/npm-org.1 b/deps/npm/man/man1/npm-org.1 index 4145f7db8c9921..c92d90a759d24b 100644 --- a/deps/npm/man/man1/npm-org.1 +++ b/deps/npm/man/man1/npm-org.1 @@ -1,4 +1,4 @@ -.TH "NPM\-ORG" "1" "October 2021" "" "" +.TH "NPM\-ORG" "1" "November 2021" "" "" .SH "NAME" \fBnpm-org\fR \- Manage orgs .SS Synopsis diff --git a/deps/npm/man/man1/npm-outdated.1 b/deps/npm/man/man1/npm-outdated.1 index f6e285f9880e30..6477c2ea0d7c64 100644 --- a/deps/npm/man/man1/npm-outdated.1 +++ b/deps/npm/man/man1/npm-outdated.1 @@ -1,4 +1,4 @@ -.TH "NPM\-OUTDATED" "1" "October 2021" "" "" +.TH "NPM\-OUTDATED" "1" "November 2021" "" "" .SH "NAME" \fBnpm-outdated\fR \- Check for outdated packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-owner.1 b/deps/npm/man/man1/npm-owner.1 index ed5e7a8089ce3e..a7d6b45b74ef2a 100644 --- a/deps/npm/man/man1/npm-owner.1 +++ b/deps/npm/man/man1/npm-owner.1 @@ -1,4 +1,4 @@ -.TH "NPM\-OWNER" "1" "October 2021" "" "" +.TH "NPM\-OWNER" "1" "November 2021" "" "" .SH "NAME" \fBnpm-owner\fR \- Manage package owners .SS Synopsis diff --git a/deps/npm/man/man1/npm-pack.1 b/deps/npm/man/man1/npm-pack.1 index 3dadbd98442dd5..13bc7336664764 100644 --- a/deps/npm/man/man1/npm-pack.1 +++ b/deps/npm/man/man1/npm-pack.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PACK" "1" "October 2021" "" "" +.TH "NPM\-PACK" "1" "November 2021" "" "" .SH "NAME" \fBnpm-pack\fR \- Create a tarball from a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-ping.1 b/deps/npm/man/man1/npm-ping.1 index 21d7af989637b6..75db070280e8ad 100644 --- a/deps/npm/man/man1/npm-ping.1 +++ b/deps/npm/man/man1/npm-ping.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PING" "1" "October 2021" "" "" +.TH "NPM\-PING" "1" "November 2021" "" "" .SH "NAME" \fBnpm-ping\fR \- Ping npm registry .SS Synopsis diff --git a/deps/npm/man/man1/npm-pkg.1 b/deps/npm/man/man1/npm-pkg.1 index aab33b40a29c56..aaa37abe842785 100644 --- a/deps/npm/man/man1/npm-pkg.1 +++ b/deps/npm/man/man1/npm-pkg.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PKG" "1" "October 2021" "" "" +.TH "NPM\-PKG" "1" "November 2021" "" "" .SH "NAME" \fBnpm-pkg\fR \- Manages your package\.json .SS Synopsis diff --git a/deps/npm/man/man1/npm-prefix.1 b/deps/npm/man/man1/npm-prefix.1 index 720e06ba5b2847..f986f28c758bf3 100644 --- a/deps/npm/man/man1/npm-prefix.1 +++ b/deps/npm/man/man1/npm-prefix.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PREFIX" "1" "October 2021" "" "" +.TH "NPM\-PREFIX" "1" "November 2021" "" "" .SH "NAME" \fBnpm-prefix\fR \- Display prefix .SS Synopsis diff --git a/deps/npm/man/man1/npm-profile.1 b/deps/npm/man/man1/npm-profile.1 index 7da569195af9b2..e3a365ecd1e665 100644 --- a/deps/npm/man/man1/npm-profile.1 +++ b/deps/npm/man/man1/npm-profile.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PROFILE" "1" "October 2021" "" "" +.TH "NPM\-PROFILE" "1" "November 2021" "" "" .SH "NAME" \fBnpm-profile\fR \- Change settings on your registry profile .SS Synopsis diff --git a/deps/npm/man/man1/npm-prune.1 b/deps/npm/man/man1/npm-prune.1 index f37deae4f55290..4fb47b337b2d00 100644 --- a/deps/npm/man/man1/npm-prune.1 +++ b/deps/npm/man/man1/npm-prune.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PRUNE" "1" "October 2021" "" "" +.TH "NPM\-PRUNE" "1" "November 2021" "" "" .SH "NAME" \fBnpm-prune\fR \- Remove extraneous packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-publish.1 b/deps/npm/man/man1/npm-publish.1 index 1ba1f74b9ff7da..6657ee20e58e9e 100644 --- a/deps/npm/man/man1/npm-publish.1 +++ b/deps/npm/man/man1/npm-publish.1 @@ -1,4 +1,4 @@ -.TH "NPM\-PUBLISH" "1" "October 2021" "" "" +.TH "NPM\-PUBLISH" "1" "November 2021" "" "" .SH "NAME" \fBnpm-publish\fR \- Publish a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-rebuild.1 b/deps/npm/man/man1/npm-rebuild.1 index d5365fea4c74de..1f5ecab8dd1290 100644 --- a/deps/npm/man/man1/npm-rebuild.1 +++ b/deps/npm/man/man1/npm-rebuild.1 @@ -1,4 +1,4 @@ -.TH "NPM\-REBUILD" "1" "October 2021" "" "" +.TH "NPM\-REBUILD" "1" "November 2021" "" "" .SH "NAME" \fBnpm-rebuild\fR \- Rebuild a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-repo.1 b/deps/npm/man/man1/npm-repo.1 index 50c9ee88cc7582..e763152ac8c041 100644 --- a/deps/npm/man/man1/npm-repo.1 +++ b/deps/npm/man/man1/npm-repo.1 @@ -1,4 +1,4 @@ -.TH "NPM\-REPO" "1" "October 2021" "" "" +.TH "NPM\-REPO" "1" "November 2021" "" "" .SH "NAME" \fBnpm-repo\fR \- Open package repository page in the browser .SS Synopsis diff --git a/deps/npm/man/man1/npm-restart.1 b/deps/npm/man/man1/npm-restart.1 index e9007b25324d29..d113d2fdb695fb 100644 --- a/deps/npm/man/man1/npm-restart.1 +++ b/deps/npm/man/man1/npm-restart.1 @@ -1,4 +1,4 @@ -.TH "NPM\-RESTART" "1" "October 2021" "" "" +.TH "NPM\-RESTART" "1" "November 2021" "" "" .SH "NAME" \fBnpm-restart\fR \- Restart a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-root.1 b/deps/npm/man/man1/npm-root.1 index 93e8d02e293983..24b6a36e2348c5 100644 --- a/deps/npm/man/man1/npm-root.1 +++ b/deps/npm/man/man1/npm-root.1 @@ -1,4 +1,4 @@ -.TH "NPM\-ROOT" "1" "October 2021" "" "" +.TH "NPM\-ROOT" "1" "November 2021" "" "" .SH "NAME" \fBnpm-root\fR \- Display npm root .SS Synopsis diff --git a/deps/npm/man/man1/npm-run-script.1 b/deps/npm/man/man1/npm-run-script.1 index 2700d8f5a7d825..da566d33f2fd50 100644 --- a/deps/npm/man/man1/npm-run-script.1 +++ b/deps/npm/man/man1/npm-run-script.1 @@ -1,4 +1,4 @@ -.TH "NPM\-RUN\-SCRIPT" "1" "October 2021" "" "" +.TH "NPM\-RUN\-SCRIPT" "1" "November 2021" "" "" .SH "NAME" \fBnpm-run-script\fR \- Run arbitrary package scripts .SS Synopsis diff --git a/deps/npm/man/man1/npm-search.1 b/deps/npm/man/man1/npm-search.1 index ab148fff87a7cc..281ad48c3fb2e4 100644 --- a/deps/npm/man/man1/npm-search.1 +++ b/deps/npm/man/man1/npm-search.1 @@ -1,4 +1,4 @@ -.TH "NPM\-SEARCH" "1" "October 2021" "" "" +.TH "NPM\-SEARCH" "1" "November 2021" "" "" .SH "NAME" \fBnpm-search\fR \- Search for packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-set-script.1 b/deps/npm/man/man1/npm-set-script.1 index 74a1f3ca13a167..453a2ccec6d970 100644 --- a/deps/npm/man/man1/npm-set-script.1 +++ b/deps/npm/man/man1/npm-set-script.1 @@ -1,4 +1,4 @@ -.TH "NPM\-SET\-SCRIPT" "1" "October 2021" "" "" +.TH "NPM\-SET\-SCRIPT" "1" "November 2021" "" "" .SH "NAME" \fBnpm-set-script\fR \- Set tasks in the scripts section of package\.json .SS Synopsis diff --git a/deps/npm/man/man1/npm-shrinkwrap.1 b/deps/npm/man/man1/npm-shrinkwrap.1 index 1acb119477fd10..793c13d6d7283c 100644 --- a/deps/npm/man/man1/npm-shrinkwrap.1 +++ b/deps/npm/man/man1/npm-shrinkwrap.1 @@ -1,4 +1,4 @@ -.TH "NPM\-SHRINKWRAP" "1" "October 2021" "" "" +.TH "NPM\-SHRINKWRAP" "1" "November 2021" "" "" .SH "NAME" \fBnpm-shrinkwrap\fR \- Lock down dependency versions for publication .SS Synopsis diff --git a/deps/npm/man/man1/npm-star.1 b/deps/npm/man/man1/npm-star.1 index c6213e5f2537cb..ed2cb430043a6f 100644 --- a/deps/npm/man/man1/npm-star.1 +++ b/deps/npm/man/man1/npm-star.1 @@ -1,4 +1,4 @@ -.TH "NPM\-STAR" "1" "October 2021" "" "" +.TH "NPM\-STAR" "1" "November 2021" "" "" .SH "NAME" \fBnpm-star\fR \- Mark your favorite packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-stars.1 b/deps/npm/man/man1/npm-stars.1 index fa0726fae5c555..93221b69d1ed66 100644 --- a/deps/npm/man/man1/npm-stars.1 +++ b/deps/npm/man/man1/npm-stars.1 @@ -1,4 +1,4 @@ -.TH "NPM\-STARS" "1" "October 2021" "" "" +.TH "NPM\-STARS" "1" "November 2021" "" "" .SH "NAME" \fBnpm-stars\fR \- View packages marked as favorites .SS Synopsis diff --git a/deps/npm/man/man1/npm-start.1 b/deps/npm/man/man1/npm-start.1 index 008116df0043ac..ca5d0490ed3084 100644 --- a/deps/npm/man/man1/npm-start.1 +++ b/deps/npm/man/man1/npm-start.1 @@ -1,4 +1,4 @@ -.TH "NPM\-START" "1" "October 2021" "" "" +.TH "NPM\-START" "1" "November 2021" "" "" .SH "NAME" \fBnpm-start\fR \- Start a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-stop.1 b/deps/npm/man/man1/npm-stop.1 index 60be71f35f404f..ff301333aa72b9 100644 --- a/deps/npm/man/man1/npm-stop.1 +++ b/deps/npm/man/man1/npm-stop.1 @@ -1,4 +1,4 @@ -.TH "NPM\-STOP" "1" "October 2021" "" "" +.TH "NPM\-STOP" "1" "November 2021" "" "" .SH "NAME" \fBnpm-stop\fR \- Stop a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-team.1 b/deps/npm/man/man1/npm-team.1 index 5892ff04fa4520..97e06883db62e6 100644 --- a/deps/npm/man/man1/npm-team.1 +++ b/deps/npm/man/man1/npm-team.1 @@ -1,4 +1,4 @@ -.TH "NPM\-TEAM" "1" "October 2021" "" "" +.TH "NPM\-TEAM" "1" "November 2021" "" "" .SH "NAME" \fBnpm-team\fR \- Manage organization teams and team memberships .SS Synopsis diff --git a/deps/npm/man/man1/npm-test.1 b/deps/npm/man/man1/npm-test.1 index 6d7f7998934729..abff79323aa9c3 100644 --- a/deps/npm/man/man1/npm-test.1 +++ b/deps/npm/man/man1/npm-test.1 @@ -1,4 +1,4 @@ -.TH "NPM\-TEST" "1" "October 2021" "" "" +.TH "NPM\-TEST" "1" "November 2021" "" "" .SH "NAME" \fBnpm-test\fR \- Test a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-token.1 b/deps/npm/man/man1/npm-token.1 index f78d21b821d7c7..99476c0ce1f818 100644 --- a/deps/npm/man/man1/npm-token.1 +++ b/deps/npm/man/man1/npm-token.1 @@ -1,4 +1,4 @@ -.TH "NPM\-TOKEN" "1" "October 2021" "" "" +.TH "NPM\-TOKEN" "1" "November 2021" "" "" .SH "NAME" \fBnpm-token\fR \- Manage your authentication tokens .SS Synopsis diff --git a/deps/npm/man/man1/npm-uninstall.1 b/deps/npm/man/man1/npm-uninstall.1 index d9062bad3708e7..16af51f32e4c74 100644 --- a/deps/npm/man/man1/npm-uninstall.1 +++ b/deps/npm/man/man1/npm-uninstall.1 @@ -1,4 +1,4 @@ -.TH "NPM\-UNINSTALL" "1" "October 2021" "" "" +.TH "NPM\-UNINSTALL" "1" "November 2021" "" "" .SH "NAME" \fBnpm-uninstall\fR \- Remove a package .SS Synopsis diff --git a/deps/npm/man/man1/npm-unpublish.1 b/deps/npm/man/man1/npm-unpublish.1 index cb397bc66c2bee..8d3b3e0298f21c 100644 --- a/deps/npm/man/man1/npm-unpublish.1 +++ b/deps/npm/man/man1/npm-unpublish.1 @@ -1,4 +1,4 @@ -.TH "NPM\-UNPUBLISH" "1" "October 2021" "" "" +.TH "NPM\-UNPUBLISH" "1" "November 2021" "" "" .SH "NAME" \fBnpm-unpublish\fR \- Remove a package from the registry .SS Synopsis diff --git a/deps/npm/man/man1/npm-unstar.1 b/deps/npm/man/man1/npm-unstar.1 index 4720b5b5c561bb..c61a8a5bd503fc 100644 --- a/deps/npm/man/man1/npm-unstar.1 +++ b/deps/npm/man/man1/npm-unstar.1 @@ -1,4 +1,4 @@ -.TH "NPM\-UNSTAR" "1" "October 2021" "" "" +.TH "NPM\-UNSTAR" "1" "November 2021" "" "" .SH "NAME" \fBnpm-unstar\fR \- Remove an item from your favorite packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-update.1 b/deps/npm/man/man1/npm-update.1 index 19e2c7f0a82281..800b69de2dc81e 100644 --- a/deps/npm/man/man1/npm-update.1 +++ b/deps/npm/man/man1/npm-update.1 @@ -1,4 +1,4 @@ -.TH "NPM\-UPDATE" "1" "October 2021" "" "" +.TH "NPM\-UPDATE" "1" "November 2021" "" "" .SH "NAME" \fBnpm-update\fR \- Update packages .SS Synopsis diff --git a/deps/npm/man/man1/npm-version.1 b/deps/npm/man/man1/npm-version.1 index 1caf6a227d7f0c..ebe993deb50fef 100644 --- a/deps/npm/man/man1/npm-version.1 +++ b/deps/npm/man/man1/npm-version.1 @@ -1,4 +1,4 @@ -.TH "NPM\-VERSION" "1" "October 2021" "" "" +.TH "NPM\-VERSION" "1" "November 2021" "" "" .SH "NAME" \fBnpm-version\fR \- Bump a package version .SS Synopsis diff --git a/deps/npm/man/man1/npm-view.1 b/deps/npm/man/man1/npm-view.1 index 4114ab30f0b4bd..5af03df4b35a57 100644 --- a/deps/npm/man/man1/npm-view.1 +++ b/deps/npm/man/man1/npm-view.1 @@ -1,4 +1,4 @@ -.TH "NPM\-VIEW" "1" "October 2021" "" "" +.TH "NPM\-VIEW" "1" "November 2021" "" "" .SH "NAME" \fBnpm-view\fR \- View registry info .SS Synopsis diff --git a/deps/npm/man/man1/npm-whoami.1 b/deps/npm/man/man1/npm-whoami.1 index 00daba3b5b2602..e3c75244550c69 100644 --- a/deps/npm/man/man1/npm-whoami.1 +++ b/deps/npm/man/man1/npm-whoami.1 @@ -1,4 +1,4 @@ -.TH "NPM\-WHOAMI" "1" "October 2021" "" "" +.TH "NPM\-WHOAMI" "1" "November 2021" "" "" .SH "NAME" \fBnpm-whoami\fR \- Display npm username .SS Synopsis diff --git a/deps/npm/man/man1/npm.1 b/deps/npm/man/man1/npm.1 index eb30baef3eb93d..0b91c46df384ae 100644 --- a/deps/npm/man/man1/npm.1 +++ b/deps/npm/man/man1/npm.1 @@ -1,4 +1,4 @@ -.TH "NPM" "1" "October 2021" "" "" +.TH "NPM" "1" "November 2021" "" "" .SH "NAME" \fBnpm\fR \- javascript package manager .SS Synopsis @@ -10,7 +10,7 @@ npm [args] .RE .SS Version .P -8\.1\.2 +8\.1\.3 .SS Description .P npm is the package manager for the Node JavaScript platform\. It puts diff --git a/deps/npm/man/man1/npx.1 b/deps/npm/man/man1/npx.1 index 0415274fe55dad..46c9be0529e673 100644 --- a/deps/npm/man/man1/npx.1 +++ b/deps/npm/man/man1/npx.1 @@ -1,4 +1,4 @@ -.TH "NPX" "1" "October 2021" "" "" +.TH "NPX" "1" "November 2021" "" "" .SH "NAME" \fBnpx\fR \- Run a command from a local or remote npm package .SS Synopsis diff --git a/deps/npm/man/man5/folders.5 b/deps/npm/man/man5/folders.5 index d06cc982adafae..859e3b38bf6c7a 100644 --- a/deps/npm/man/man5/folders.5 +++ b/deps/npm/man/man5/folders.5 @@ -1,4 +1,4 @@ -.TH "FOLDERS" "5" "October 2021" "" "" +.TH "FOLDERS" "5" "November 2021" "" "" .SH "NAME" \fBfolders\fR \- Folder Structures Used by npm .SS Description diff --git a/deps/npm/man/man5/install.5 b/deps/npm/man/man5/install.5 index deacc9b294850e..99a90dcaaf8546 100644 --- a/deps/npm/man/man5/install.5 +++ b/deps/npm/man/man5/install.5 @@ -1,4 +1,4 @@ -.TH "INSTALL" "5" "October 2021" "" "" +.TH "INSTALL" "5" "November 2021" "" "" .SH "NAME" \fBinstall\fR \- Download and install node and npm .SS Description diff --git a/deps/npm/man/man5/npm-shrinkwrap-json.5 b/deps/npm/man/man5/npm-shrinkwrap-json.5 index 52ff45477f154c..9fdb54c6b1a781 100644 --- a/deps/npm/man/man5/npm-shrinkwrap-json.5 +++ b/deps/npm/man/man5/npm-shrinkwrap-json.5 @@ -1,4 +1,4 @@ -.TH "NPM\-SHRINKWRAP\.JSON" "5" "October 2021" "" "" +.TH "NPM\-SHRINKWRAP\.JSON" "5" "November 2021" "" "" .SH "NAME" \fBnpm-shrinkwrap.json\fR \- A publishable lockfile .SS Description diff --git a/deps/npm/man/man5/npmrc.5 b/deps/npm/man/man5/npmrc.5 index be1135edb541d6..60c03a8c14947c 100644 --- a/deps/npm/man/man5/npmrc.5 +++ b/deps/npm/man/man5/npmrc.5 @@ -1,4 +1,4 @@ -.TH "NPMRC" "5" "October 2021" "" "" +.TH "NPMRC" "5" "November 2021" "" "" .SH "NAME" \fBnpmrc\fR \- The npm config files .SS Description diff --git a/deps/npm/man/man5/package-json.5 b/deps/npm/man/man5/package-json.5 index eddbcda9b4309c..857d5649530e47 100644 --- a/deps/npm/man/man5/package-json.5 +++ b/deps/npm/man/man5/package-json.5 @@ -1,4 +1,4 @@ -.TH "PACKAGE\.JSON" "5" "October 2021" "" "" +.TH "PACKAGE\.JSON" "5" "November 2021" "" "" .SH "NAME" \fBpackage.json\fR \- Specifics of npm's package\.json handling .SS Description diff --git a/deps/npm/man/man5/package-lock-json.5 b/deps/npm/man/man5/package-lock-json.5 index 7f0952fbcc81e4..8544d70b711916 100644 --- a/deps/npm/man/man5/package-lock-json.5 +++ b/deps/npm/man/man5/package-lock-json.5 @@ -1,4 +1,4 @@ -.TH "PACKAGE\-LOCK\.JSON" "5" "October 2021" "" "" +.TH "PACKAGE\-LOCK\.JSON" "5" "November 2021" "" "" .SH "NAME" \fBpackage-lock.json\fR \- A manifestation of the manifest .SS Description diff --git a/deps/npm/man/man7/config.7 b/deps/npm/man/man7/config.7 index 98fbf2060ec993..2157f70cceeaa6 100644 --- a/deps/npm/man/man7/config.7 +++ b/deps/npm/man/man7/config.7 @@ -1,4 +1,4 @@ -.TH "CONFIG" "7" "October 2021" "" "" +.TH "CONFIG" "7" "November 2021" "" "" .SH "NAME" \fBconfig\fR \- More than you probably want to know about npm configuration .SS Description diff --git a/deps/npm/man/man7/developers.7 b/deps/npm/man/man7/developers.7 index 589cd74ff0a58f..23ee3b5778378b 100644 --- a/deps/npm/man/man7/developers.7 +++ b/deps/npm/man/man7/developers.7 @@ -1,4 +1,4 @@ -.TH "DEVELOPERS" "7" "October 2021" "" "" +.TH "DEVELOPERS" "7" "November 2021" "" "" .SH "NAME" \fBdevelopers\fR \- Developer Guide .SS Description diff --git a/deps/npm/man/man7/orgs.7 b/deps/npm/man/man7/orgs.7 index 2cc52cf20dc0f3..a6664a1dac7bc4 100644 --- a/deps/npm/man/man7/orgs.7 +++ b/deps/npm/man/man7/orgs.7 @@ -1,4 +1,4 @@ -.TH "ORGS" "7" "October 2021" "" "" +.TH "ORGS" "7" "November 2021" "" "" .SH "NAME" \fBorgs\fR \- Working with Teams & Orgs .SS Description diff --git a/deps/npm/man/man7/registry.7 b/deps/npm/man/man7/registry.7 index 40e924f976aa4b..6b46806bf026ed 100644 --- a/deps/npm/man/man7/registry.7 +++ b/deps/npm/man/man7/registry.7 @@ -1,4 +1,4 @@ -.TH "REGISTRY" "7" "October 2021" "" "" +.TH "REGISTRY" "7" "November 2021" "" "" .SH "NAME" \fBregistry\fR \- The JavaScript Package Registry .SS Description diff --git a/deps/npm/man/man7/removal.7 b/deps/npm/man/man7/removal.7 index b152cd47cc2cb7..24d66dfa92edb2 100644 --- a/deps/npm/man/man7/removal.7 +++ b/deps/npm/man/man7/removal.7 @@ -1,4 +1,4 @@ -.TH "REMOVAL" "7" "October 2021" "" "" +.TH "REMOVAL" "7" "November 2021" "" "" .SH "NAME" \fBremoval\fR \- Cleaning the Slate .SS Synopsis diff --git a/deps/npm/man/man7/scope.7 b/deps/npm/man/man7/scope.7 index f5626388f2a6e3..f5fa03206b79ce 100644 --- a/deps/npm/man/man7/scope.7 +++ b/deps/npm/man/man7/scope.7 @@ -1,4 +1,4 @@ -.TH "SCOPE" "7" "October 2021" "" "" +.TH "SCOPE" "7" "November 2021" "" "" .SH "NAME" \fBscope\fR \- Scoped packages .SS Description diff --git a/deps/npm/man/man7/scripts.7 b/deps/npm/man/man7/scripts.7 index 9c9d07adce5de5..9d1659eeee015d 100644 --- a/deps/npm/man/man7/scripts.7 +++ b/deps/npm/man/man7/scripts.7 @@ -1,4 +1,4 @@ -.TH "SCRIPTS" "7" "October 2021" "" "" +.TH "SCRIPTS" "7" "November 2021" "" "" .SH "NAME" \fBscripts\fR \- How npm handles the "scripts" field .SS Description diff --git a/deps/npm/man/man7/workspaces.7 b/deps/npm/man/man7/workspaces.7 index 82c4ee9f585e95..c72ae28b11035c 100644 --- a/deps/npm/man/man7/workspaces.7 +++ b/deps/npm/man/man7/workspaces.7 @@ -1,4 +1,4 @@ -.TH "WORKSPACES" "7" "October 2021" "" "" +.TH "WORKSPACES" "7" "November 2021" "" "" .SH "NAME" \fBworkspaces\fR \- Working with workspaces .SS Description diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js index 658ece7a93618f..978743b38255f7 100644 --- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js +++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js @@ -1173,6 +1173,10 @@ module.exports = cls => class Reifier extends cls { } let newSpec + // True if the dependency is getting installed from a local file path + // In this case it is not possible to do the normal version comparisons + // as the new version will be a file path + const isLocalDep = req.type === 'directory' || req.type === 'file' if (req.registry) { const version = child.version const prefixRange = version ? this[_savePrefix] + version : '*' @@ -1204,7 +1208,7 @@ module.exports = cls => class Reifier extends cls { } else { newSpec = h.shortcut(opt) } - } else if (req.type === 'directory' || req.type === 'file') { + } else if (isLocalDep) { // save the relative path in package.json // Normally saveSpec is updated with the proper relative // path already, but it's possible to specify a full absolute @@ -1233,11 +1237,11 @@ module.exports = cls => class Reifier extends cls { if (hasSubKey(pkg, 'devDependencies', name)) { pkg.devDependencies[name] = newSpec // don't update peer or optional if we don't have to - if (hasSubKey(pkg, 'peerDependencies', name) && !intersects(newSpec, pkg.peerDependencies[name])) { + if (hasSubKey(pkg, 'peerDependencies', name) && (isLocalDep || !intersects(newSpec, pkg.peerDependencies[name]))) { pkg.peerDependencies[name] = newSpec } - if (hasSubKey(pkg, 'optionalDependencies', name) && !intersects(newSpec, pkg.optionalDependencies[name])) { + if (hasSubKey(pkg, 'optionalDependencies', name) && (isLocalDep || !intersects(newSpec, pkg.optionalDependencies[name]))) { pkg.optionalDependencies[name] = newSpec } } else { diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/place-dep.js b/deps/npm/node_modules/@npmcli/arborist/lib/place-dep.js index 1fe930876a86dc..be735d5fc1c4b6 100644 --- a/deps/npm/node_modules/@npmcli/arborist/lib/place-dep.js +++ b/deps/npm/node_modules/@npmcli/arborist/lib/place-dep.js @@ -407,11 +407,12 @@ class PlaceDep { for (const entryEdge of peerEntrySets(edge.from).keys()) { // either this one needs to be pruned and re-evaluated, or marked // as peerConflicted and warned about. If the entryEdge comes in from - // the root, then we have to leave it alone, and in that case, it - // will have already warned or crashed by getting to this point. + // the root or a workspace, then we have to leave it alone, and in that + // case, it will have already warned or crashed by getting to this point const entryNode = entryEdge.to const deepestTarget = deepestNestingTarget(entryNode) - if (deepestTarget !== target && !entryEdge.from.isRoot) { + if (deepestTarget !== target && + !(entryEdge.from.isProjectRoot || entryEdge.from.isWorkspace)) { prunePeerSets.push(...gatherDepSet([entryNode], e => { return e.to !== entryNode && !e.peerConflicted })) diff --git a/deps/npm/node_modules/@npmcli/arborist/package.json b/deps/npm/node_modules/@npmcli/arborist/package.json index cfa74a805b1163..dfe2b6f08f56a3 100644 --- a/deps/npm/node_modules/@npmcli/arborist/package.json +++ b/deps/npm/node_modules/@npmcli/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "4.0.3", + "version": "4.0.4", "description": "Manage node_modules trees", "dependencies": { "@isaacs/string-locale-compare": "^1.0.1", diff --git a/deps/npm/node_modules/@npmcli/config/lib/index.js b/deps/npm/node_modules/@npmcli/config/lib/index.js index f947896f0ba348..724ce14c38fc94 100644 --- a/deps/npm/node_modules/@npmcli/config/lib/index.js +++ b/deps/npm/node_modules/@npmcli/config/lib/index.js @@ -497,6 +497,12 @@ class Config { } async loadProjectConfig () { + if (this[_get]('global') === true || this[_get]('location') === 'global') { + this.data.get('project').source = '(global mode enabled, ignored)' + this.sources.set(this.data.get('project').source, 'project') + return + } + // the localPrefix can be set by the CLI config, but otherwise is // found by walking up the folder tree await this.loadLocalPrefix() diff --git a/deps/npm/node_modules/@npmcli/config/package.json b/deps/npm/node_modules/@npmcli/config/package.json index b31eecbe359797..f36d8f7b11ec59 100644 --- a/deps/npm/node_modules/@npmcli/config/package.json +++ b/deps/npm/node_modules/@npmcli/config/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/config", - "version": "2.3.0", + "version": "2.3.1", "files": [ "lib" ], diff --git a/deps/npm/node_modules/libnpmdiff/index.js b/deps/npm/node_modules/libnpmdiff/index.js index 73dc3ee64e3ce8..2d074c3d1bb678 100644 --- a/deps/npm/node_modules/libnpmdiff/index.js +++ b/deps/npm/node_modules/libnpmdiff/index.js @@ -4,6 +4,10 @@ const formatDiff = require('./lib/format-diff.js') const getTarball = require('./lib/tarball.js') const untar = require('./lib/untar.js') +// TODO: we test this condition in the diff command +// so this error probably doesnt need to be here. Or +// if it does we should figure out a standard code +// so we can catch it in the cli and display it consistently const argsError = () => Object.assign( new TypeError('libnpmdiff needs two arguments to compare'), diff --git a/deps/npm/package.json b/deps/npm/package.json index cb8b46e8a480f6..ab525df05ce014 100644 --- a/deps/npm/package.json +++ b/deps/npm/package.json @@ -1,5 +1,5 @@ { - "version": "8.1.2", + "version": "8.1.3", "name": "npm", "description": "a package manager for JavaScript", "workspaces": [ @@ -55,7 +55,7 @@ }, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^4.0.3", + "@npmcli/arborist": "^4.0.4", "@npmcli/ci-detect": "^1.4.0", "@npmcli/config": "^2.3.0", "@npmcli/map-workspaces": "^2.0.0", @@ -220,7 +220,7 @@ "sudotest:nocleanup": "sudo NO_TEST_CLEANUP=1 npm run test --", "posttest": "npm run lint", "eslint": "eslint", - "lint": "npm run eslint -- test/lib test/bin bin lib scripts docs smoke-tests", + "lint": "npm run eslint -- bin docs lib scripts smoke-tests test ./*.js", "lintfix": "npm run lint -- --fix", "prelint": "rimraf test/npm_cache*", "resetdeps": "bash scripts/resetdeps.sh", diff --git a/deps/npm/tap-snapshots/test/lib/config.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/config.js.test.cjs similarity index 95% rename from deps/npm/tap-snapshots/test/lib/config.js.test.cjs rename to deps/npm/tap-snapshots/test/lib/commands/config.js.test.cjs index e6f9e9280ac387..c7be15f0c75eb6 100644 --- a/deps/npm/tap-snapshots/test/lib/config.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/config.js.test.cjs @@ -5,7 +5,7 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/config.js TAP config list --json > output matches snapshot 1`] = ` +exports[`test/lib/commands/config.js TAP config list --json > output matches snapshot 1`] = ` { "prefix": "{LOCALPREFIX}", "userconfig": "{HOME}/.npmrc", @@ -160,7 +160,7 @@ exports[`test/lib/config.js TAP config list --json > output matches snapshot 1`] } ` -exports[`test/lib/config.js TAP config list --long > output matches snapshot 1`] = ` +exports[`test/lib/commands/config.js TAP config list --long > output matches snapshot 1`] = ` ; "default" config from default values _auth = (protected) @@ -221,18 +221,18 @@ include = [] include-staged = false include-workspace-root = false init-author-email = "" -init-author-name = "" +init-author-name = "" init-author-url = "" init-license = "ISC" init-module = "{HOME}/.npm-init.js" -init-version = "1.0.0" +init-version = "1.0.0" init.author.email = "" -init.author.name = "" +init.author.name = "" init.author.url = "" init.license = "ISC" init.module = "{HOME}/.npm-init.js" -init.version = "1.0.0" -json = false +init.version = "1.0.0" +json = false key = null legacy-bundling = false legacy-peer-deps = false @@ -329,7 +329,7 @@ prefix = "{LOCALPREFIX}" userconfig = "{HOME}/.npmrc" ` -exports[`test/lib/config.js TAP config list > output matches snapshot 1`] = ` +exports[`test/lib/commands/config.js TAP config list > output matches snapshot 1`] = ` ; "cli" config from command line options prefix = "{LOCALPREFIX}" diff --git a/deps/npm/tap-snapshots/test/lib/dist-tag.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/dist-tag.js.test.cjs similarity index 53% rename from deps/npm/tap-snapshots/test/lib/dist-tag.js.test.cjs rename to deps/npm/tap-snapshots/test/lib/commands/dist-tag.js.test.cjs index d6e101c5079f75..1bea3cafd4acab 100644 --- a/deps/npm/tap-snapshots/test/lib/dist-tag.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/dist-tag.js.test.cjs @@ -5,7 +5,7 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/dist-tag.js TAP add missing args > should exit usage error message 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP add missing args > should exit usage error message 1`] = ` Error: Usage: npm dist-tag @@ -27,7 +27,7 @@ Run "npm help dist-tag" for more info { } ` -exports[`test/lib/dist-tag.js TAP add missing pkg name > should exit usage error message 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP add missing pkg name > should exit usage error message 1`] = ` Error: Usage: npm dist-tag @@ -49,16 +49,16 @@ Run "npm help dist-tag" for more info { } ` -exports[`test/lib/dist-tag.js TAP add new tag > should return success msg 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP add new tag > should return success msg 1`] = ` +c: @scoped/another@7.7.7 ` -exports[`test/lib/dist-tag.js TAP add using valid semver range as name > should return success msg 1`] = ` -dist-tag add 1.0.0 to @scoped/another@7.7.7 +exports[`test/lib/commands/dist-tag.js TAP add using valid semver range as name > should return success msg 1`] = ` +dist-tag add 1.0.0 to @scoped/another@7.7.7 ` -exports[`test/lib/dist-tag.js TAP borked cmd usage > should show usage error 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP borked cmd usage > should show usage error 1`] = ` Error: Usage: npm dist-tag @@ -80,7 +80,7 @@ Run "npm help dist-tag" for more info { } ` -exports[`test/lib/dist-tag.js TAP ls global > should throw basic usage 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP ls global > should throw basic usage 1`] = ` Error: Usage: npm dist-tag @@ -102,13 +102,13 @@ Run "npm help dist-tag" for more info { } ` -exports[`test/lib/dist-tag.js TAP ls in current package > should list available tags for current package 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP ls in current package > should list available tags for current package 1`] = ` a: 0.0.1 b: 0.5.0 latest: 1.0.0 ` -exports[`test/lib/dist-tag.js TAP ls on missing name in current package > should throw usage error message 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP ls on missing name in current package > should throw usage error message 1`] = ` Error: Usage: npm dist-tag @@ -130,43 +130,43 @@ Run "npm help dist-tag" for more info { } ` -exports[`test/lib/dist-tag.js TAP ls on missing package > should log no dist-tag found msg 1`] = ` -dist-tag ls Couldn't get dist-tag data for foo@latest +exports[`test/lib/commands/dist-tag.js TAP ls on missing package > should log no dist-tag found msg 1`] = ` +dist-tag ls Couldn't get dist-tag data for foo@latest ` -exports[`test/lib/dist-tag.js TAP ls on missing package > should throw error message 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP ls on missing package > should throw error message 1`] = ` Error: No dist-tags found for foo ` -exports[`test/lib/dist-tag.js TAP ls on named package > should list tags for the specified package 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP ls on named package > should list tags for the specified package 1`] = ` a: 0.0.2 b: 0.6.0 latest: 2.0.0 ` -exports[`test/lib/dist-tag.js TAP no args in current package > should default to listing available tags for current package 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP no args in current package > should default to listing available tags for current package 1`] = ` a: 0.0.1 b: 0.5.0 latest: 1.0.0 ` -exports[`test/lib/dist-tag.js TAP only named package arg > should default to listing tags for the specified package 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP only named package arg > should default to listing tags for the specified package 1`] = ` a: 0.0.2 b: 0.6.0 latest: 2.0.0 ` -exports[`test/lib/dist-tag.js TAP remove existing tag > should log remove info 1`] = ` -dist-tag del c from @scoped/another +exports[`test/lib/commands/dist-tag.js TAP remove existing tag > should log remove info 1`] = ` +dist-tag del c from @scoped/another ` -exports[`test/lib/dist-tag.js TAP remove existing tag > should return success msg 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP remove existing tag > should return success msg 1`] = ` -c: @scoped/another@7.7.7 ` -exports[`test/lib/dist-tag.js TAP remove missing pkg name > should exit usage error message 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP remove missing pkg name > should exit usage error message 1`] = ` Error: Usage: npm dist-tag @@ -188,19 +188,19 @@ Run "npm help dist-tag" for more info { } ` -exports[`test/lib/dist-tag.js TAP remove non-existing tag > should log error msg 1`] = ` -dist-tag del nonexistent from @scoped/another -dist-tag del nonexistent is not a dist-tag on @scoped/another +exports[`test/lib/commands/dist-tag.js TAP remove non-existing tag > should log error msg 1`] = ` +dist-tag del nonexistent from @scoped/another +dist-tag del nonexistent is not a dist-tag on @scoped/another ` -exports[`test/lib/dist-tag.js TAP set existing version > should log warn msg 1`] = ` -dist-tag add b to @scoped/another@0.6.0 -dist-tag add b is already set to version 0.6.0 +exports[`test/lib/commands/dist-tag.js TAP set existing version > should log warn msg 1`] = ` +dist-tag add b to @scoped/another@0.6.0 +dist-tag add b is already set to version 0.6.0 ` -exports[`test/lib/dist-tag.js TAP workspaces no args > printed the expected output 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP workspaces no args > printed the expected output 1`] = ` workspace-a: latest-a: 1.0.0 latest: 1.0.0 @@ -212,7 +212,7 @@ latest-c: 3.0.0 latest: 3.0.0 ` -exports[`test/lib/dist-tag.js TAP workspaces no args, one failing workspace sets exitCode to 1 > printed the expected output 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP workspaces no args, one failing workspace sets exitCode to 1 > printed the expected output 1`] = ` workspace-a: latest-a: 1.0.0 latest: 1.0.0 @@ -225,13 +225,13 @@ latest: 3.0.0 workspace-d: ` -exports[`test/lib/dist-tag.js TAP workspaces no args, one workspace > printed the expected output 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP workspaces no args, one workspace > printed the expected output 1`] = ` workspace-a: latest-a: 1.0.0 latest: 1.0.0 ` -exports[`test/lib/dist-tag.js TAP workspaces one arg -- . > printed the expected output 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP workspaces one arg -- . > printed the expected output 1`] = ` workspace-a: latest-a: 1.0.0 latest: 1.0.0 @@ -243,7 +243,7 @@ latest-c: 3.0.0 latest: 3.0.0 ` -exports[`test/lib/dist-tag.js TAP workspaces one arg -- .@1, ignores version spec > printed the expected output 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP workspaces one arg -- .@1, ignores version spec > printed the expected output 1`] = ` workspace-a: latest-a: 1.0.0 latest: 1.0.0 @@ -255,7 +255,7 @@ latest-c: 3.0.0 latest: 3.0.0 ` -exports[`test/lib/dist-tag.js TAP workspaces one arg -- list > printed the expected output 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP workspaces one arg -- list > printed the expected output 1`] = ` workspace-a: latest-a: 1.0.0 latest: 1.0.0 @@ -267,7 +267,7 @@ latest-c: 3.0.0 latest: 3.0.0 ` -exports[`test/lib/dist-tag.js TAP workspaces two args -- list, . > printed the expected output 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP workspaces two args -- list, . > printed the expected output 1`] = ` workspace-a: latest-a: 1.0.0 latest: 1.0.0 @@ -279,7 +279,7 @@ latest-c: 3.0.0 latest: 3.0.0 ` -exports[`test/lib/dist-tag.js TAP workspaces two args -- list, .@1, ignores version spec > printed the expected output 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP workspaces two args -- list, .@1, ignores version spec > printed the expected output 1`] = ` workspace-a: latest-a: 1.0.0 latest: 1.0.0 @@ -291,7 +291,7 @@ latest-c: 3.0.0 latest: 3.0.0 ` -exports[`test/lib/dist-tag.js TAP workspaces two args -- list, @scoped/pkg, logs a warning and ignores workspaces > printed the expected output 1`] = ` +exports[`test/lib/commands/dist-tag.js TAP workspaces two args -- list, @scoped/pkg, logs a warning and ignores workspaces > printed the expected output 1`] = ` a: 0.0.1 b: 0.5.0 latest: 1.0.0 diff --git a/deps/npm/tap-snapshots/test/lib/fund.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/fund.js.test.cjs similarity index 54% rename from deps/npm/tap-snapshots/test/lib/fund.js.test.cjs rename to deps/npm/tap-snapshots/test/lib/commands/fund.js.test.cjs index c078beb7d98665..f0df1e1c58ad46 100644 --- a/deps/npm/tap-snapshots/test/lib/fund.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/fund.js.test.cjs @@ -5,14 +5,14 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/fund.js TAP fund a package with type and multiple sources > should print prompt select message 1`] = ` +exports[`test/lib/commands/fund.js TAP fund a package with type and multiple sources > should print prompt select message 1`] = ` 1: Foo funding available at the following URL: http://example.com/foo 2: Lorem funding available at the following URL: http://example.com/foo-lorem Run \`npm fund [<@scope>/] --which=1\`, for example, to open the first funding URL listed in that package ` -exports[`test/lib/fund.js TAP fund colors > should print output with color info 1`] = ` +exports[`test/lib/commands/fund.js TAP fund colors > should print output with color info 1`] = ` test-fund-colors@1.0.0 +-- http://example.com/a | \`-- a@1.0.0 @@ -26,7 +26,7 @@ exports[`test/lib/fund.js TAP fund colors > should print output with color info ` -exports[`test/lib/fund.js TAP fund containing multi-level nested deps with no funding > should omit dependencies with no funding declared 1`] = ` +exports[`test/lib/commands/fund.js TAP fund containing multi-level nested deps with no funding > should omit dependencies with no funding declared 1`] = ` nested-no-funding-packages@1.0.0 +-- https://example.com/lorem | \`-- lorem@1.0.0 @@ -36,54 +36,54 @@ nested-no-funding-packages@1.0.0 ` -exports[`test/lib/fund.js TAP fund in which same maintainer owns all its deps > should print stack packages together 1`] = ` +exports[`test/lib/commands/fund.js TAP fund in which same maintainer owns all its deps > should print stack packages together 1`] = ` http://example.com/donate \`-- maintainer-owns-all-deps@1.0.0, dep-foo@1.0.0, dep-sub-foo@1.0.0, dep-bar@1.0.0 ` -exports[`test/lib/fund.js TAP fund pkg missing version number > should print name only 1`] = ` +exports[`test/lib/commands/fund.js TAP fund pkg missing version number > should print name only 1`] = ` http://example.com/foo \`-- foo ` -exports[`test/lib/fund.js TAP fund using nested packages with multiple sources > should prompt with all available URLs 1`] = ` +exports[`test/lib/commands/fund.js TAP fund using nested packages with multiple sources > should prompt with all available URLs 1`] = ` 1: Funding available at the following URL: https://one.example.com 2: Funding available at the following URL: https://two.example.com Run \`npm fund [<@scope>/] --which=1\`, for example, to open the first funding URL listed in that package ` -exports[`test/lib/fund.js TAP fund using nested packages with multiple sources, with a source number > should open the numbered URL 1`] = ` +exports[`test/lib/commands/fund.js TAP fund using nested packages with multiple sources, with a source number > should open the numbered URL 1`] = ` Funding available at the following URL: https://one.example.com ` -exports[`test/lib/fund.js TAP fund using package argument > should open funding url 1`] = ` +exports[`test/lib/commands/fund.js TAP fund using package argument > should open funding url 1`] = ` individual funding available at the following URL: http://example.com/donate ` -exports[`test/lib/fund.js TAP fund using pkg name while having conflicting versions > should open greatest version 1`] = ` +exports[`test/lib/commands/fund.js TAP fund using pkg name while having conflicting versions > should open greatest version 1`] = ` Funding available at the following URL: http://example.com/2 ` -exports[`test/lib/fund.js TAP fund using string shorthand > should open string-only url 1`] = ` +exports[`test/lib/commands/fund.js TAP fund using string shorthand > should open string-only url 1`] = ` Funding available at the following URL: https://example.com/sponsor ` -exports[`test/lib/fund.js TAP fund with no package containing funding > should print empty funding info 1`] = ` +exports[`test/lib/commands/fund.js TAP fund with no package containing funding > should print empty funding info 1`] = ` no-funding-package@0.0.0 ` -exports[`test/lib/fund.js TAP sub dep with fund info and a parent with no funding info > should nest sub dep as child of root 1`] = ` +exports[`test/lib/commands/fund.js TAP sub dep with fund info and a parent with no funding info > should nest sub dep as child of root 1`] = ` test-multiple-funding-sources@1.0.0 +-- http://example.com/b | \`-- b@1.0.0 @@ -93,7 +93,7 @@ test-multiple-funding-sources@1.0.0 ` -exports[`test/lib/fund.js TAP workspaces filter funding info by a specific workspace > should display only filtered workspace name and its deps 1`] = ` +exports[`test/lib/commands/fund.js TAP workspaces filter funding info by a specific workspace > should display only filtered workspace name and its deps 1`] = ` workspaces-support@1.0.0 \`-- https://example.com/a | \`-- a@1.0.0 @@ -103,7 +103,7 @@ workspaces-support@1.0.0 ` -exports[`test/lib/fund.js TAP workspaces filter funding info by a specific workspace > should display only filtered workspace path and its deps 1`] = ` +exports[`test/lib/commands/fund.js TAP workspaces filter funding info by a specific workspace > should display only filtered workspace path and its deps 1`] = ` workspaces-support@1.0.0 \`-- https://example.com/a | \`-- a@1.0.0 diff --git a/deps/npm/tap-snapshots/test/lib/init.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/init.js.test.cjs similarity index 64% rename from deps/npm/tap-snapshots/test/lib/init.js.test.cjs rename to deps/npm/tap-snapshots/test/lib/commands/init.js.test.cjs index 99ca9c7f1d7d7e..9dd0b4b6be36b7 100644 --- a/deps/npm/tap-snapshots/test/lib/init.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/init.js.test.cjs @@ -5,11 +5,11 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/init.js TAP npm init workspces with root > does not print helper info 1`] = ` +exports[`test/lib/commands/init.js TAP npm init workspces with root > does not print helper info 1`] = ` Array [] ` -exports[`test/lib/init.js TAP workspaces no args > should print helper info 1`] = ` +exports[`test/lib/commands/init.js TAP workspaces no args > should print helper info 1`] = ` Array [ Array [ String( @@ -28,10 +28,10 @@ Array [ ] ` -exports[`test/lib/init.js TAP workspaces no args, existing folder > should print helper info 1`] = ` +exports[`test/lib/commands/init.js TAP workspaces no args, existing folder > should print helper info 1`] = ` Array [] ` -exports[`test/lib/init.js TAP workspaces with arg but missing workspace folder > should print helper info 1`] = ` +exports[`test/lib/commands/init.js TAP workspaces with arg but missing workspace folder > should print helper info 1`] = ` Array [] ` diff --git a/deps/npm/tap-snapshots/test/lib/commands/link.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/link.js.test.cjs new file mode 100644 index 00000000000000..a9a10b20a2f83d --- /dev/null +++ b/deps/npm/tap-snapshots/test/lib/commands/link.js.test.cjs @@ -0,0 +1,45 @@ +/* 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/commands/link.js TAP link global linked pkg to local nm when using args > should create a local symlink to global pkg 1`] = ` +{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/@myscope/bar -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/global-prefix/lib/node_modules/@myscope/bar +{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/@myscope/linked -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/scoped-linked +{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/a -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/global-prefix/lib/node_modules/a +{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/link-me-too -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/link-me-too +{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/test-pkg-link -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/test-pkg-link + +` + +exports[`test/lib/commands/link.js TAP link global linked pkg to local workspace using args > should create a local symlink to global pkg 1`] = ` +{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/@myscope/bar -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/global-prefix/lib/node_modules/@myscope/bar +{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/@myscope/linked -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/scoped-linked +{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/a -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/global-prefix/lib/node_modules/a +{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/link-me-too -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/link-me-too +{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/test-pkg-link -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/test-pkg-link +{CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/x -> {CWD}/test/lib/commands/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/packages/x + +` + +exports[`test/lib/commands/link.js TAP link pkg already in global space > should create a local symlink to global pkg 1`] = ` +{CWD}/test/lib/commands/tap-testdir-link-link-pkg-already-in-global-space/my-project/node_modules/@myscope/linked -> {CWD}/test/lib/commands/tap-testdir-link-link-pkg-already-in-global-space/scoped-linked + +` + +exports[`test/lib/commands/link.js TAP link pkg already in global space when prefix is a symlink > should create a local symlink to global pkg 1`] = ` +{CWD}/test/lib/commands/tap-testdir-link-link-pkg-already-in-global-space-when-prefix-is-a-symlink/my-project/node_modules/@myscope/linked -> {CWD}/test/lib/commands/tap-testdir-link-link-pkg-already-in-global-space-when-prefix-is-a-symlink/scoped-linked + +` + +exports[`test/lib/commands/link.js TAP link to globalDir when in current working dir of pkg and no args > should create a global link to current pkg 1`] = ` +{CWD}/test/lib/commands/tap-testdir-link-link-to-globalDir-when-in-current-working-dir-of-pkg-and-no-args/global-prefix/lib/node_modules/test-pkg-link -> {CWD}/test/lib/commands/tap-testdir-link-link-to-globalDir-when-in-current-working-dir-of-pkg-and-no-args/test-pkg-link + +` + +exports[`test/lib/commands/link.js TAP link ws to globalDir when workspace specified and no args > should create a global link to current pkg 1`] = ` +{CWD}/test/lib/commands/tap-testdir-link-link-ws-to-globalDir-when-workspace-specified-and-no-args/global-prefix/lib/node_modules/a -> {CWD}/test/lib/commands/tap-testdir-link-link-ws-to-globalDir-when-workspace-specified-and-no-args/test-pkg-link/packages/a + +` diff --git a/deps/npm/tap-snapshots/test/lib/ls.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/ls.js.test.cjs similarity index 64% rename from deps/npm/tap-snapshots/test/lib/ls.js.test.cjs rename to deps/npm/tap-snapshots/test/lib/commands/ls.js.test.cjs index c550f447c4cada..d00312ea6d6d75 100644 --- a/deps/npm/tap-snapshots/test/lib/ls.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/ls.js.test.cjs @@ -5,7 +5,7 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/ls.js TAP ignore missing optional deps --json > ls --json problems 1`] = ` +exports[`test/lib/commands/ls.js TAP ignore missing optional deps --json > ls --json problems 1`] = ` Array [ "invalid: optional-wrong@3.2.1 {project}/node_modules/optional-wrong", "missing: peer-missing@1, required by test-npm-ls-ignore-missing-optional@1.2.3", @@ -16,7 +16,7 @@ Array [ ] ` -exports[`test/lib/ls.js TAP ignore missing optional deps --parseable > ls --parseable result 1`] = ` +exports[`test/lib/commands/ls.js TAP ignore missing optional deps --parseable > ls --parseable result 1`] = ` {project} {project}/node_modules/optional-ok {project}/node_modules/optional-wrong @@ -28,7 +28,7 @@ exports[`test/lib/ls.js TAP ignore missing optional deps --parseable > ls --pars {project}/node_modules/prod-wrong ` -exports[`test/lib/ls.js TAP ignore missing optional deps human output > ls result 1`] = ` +exports[`test/lib/commands/ls.js TAP ignore missing optional deps human output > ls result 1`] = ` test-npm-ls-ignore-missing-optional@1.2.3 {project} +-- unmet optional dependency optional-missing@1 +-- optional-ok@1.2.3 @@ -45,14 +45,14 @@ test-npm-ls-ignore-missing-optional@1.2.3 {project} ` -exports[`test/lib/ls.js TAP ls --depth=0 > should output tree containing only top-level dependencies 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --depth=0 > should output tree containing only top-level dependencies 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---depth-0 +-- chai@1.0.0 \`-- foo@1.0.0 ` -exports[`test/lib/ls.js TAP ls --depth=1 > should output tree containing top-level deps and their deps only 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --depth=1 > should output tree containing top-level deps and their deps only 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---depth-1 +-- a@1.0.0 | \`-- b@1.0.0 @@ -60,7 +60,7 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---depth-1 ` -exports[`test/lib/ls.js TAP ls --dev > should output tree containing dev deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --dev > should output tree containing dev deps 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---dev \`-- dev-dep@1.0.0 \`-- foo@1.0.0 @@ -68,18 +68,18 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---dev ` -exports[`test/lib/ls.js TAP ls --link > should output tree containing linked deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --link > should output tree containing linked deps 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---link \`-- linked-dep@1.0.0 -> ./linked-dep ` -exports[`test/lib/ls.js TAP ls --long --depth=0 > should output tree containing top-level deps with descriptions 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --long --depth=0 > should output tree containing top-level deps with descriptions 1`] = ` test-npm-ls@1.0.0 | {CWD}/tap-testdir-ls-ls---long---depth-0 -| +| +-- chai@1.0.0 -| +| +-- dev-dep@1.0.0 | A DEV dep kind of dep +-- optional-dep@1.0.0 @@ -91,18 +91,18 @@ test-npm-ls@1.0.0 ` -exports[`test/lib/ls.js TAP ls --long > should output tree info with descriptions 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --long > should output tree info with descriptions 1`] = ` test-npm-ls@1.0.0 | {CWD}/tap-testdir-ls-ls---long -| +| +-- chai@1.0.0 -| +| +-- dev-dep@1.0.0 | | A DEV dep kind of dep | \`-- foo@1.0.0 -| | +| | | \`-- dog@1.0.0 -| +| +-- optional-dep@1.0.0 | Maybe a dep? +-- peer-dep@1.0.0 @@ -114,7 +114,7 @@ test-npm-ls@1.0.0 ` -exports[`test/lib/ls.js TAP ls --only=development > should output tree containing only development deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --only=development > should output tree containing only development deps 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---only-development \`-- dev-dep@1.0.0 \`-- foo@1.0.0 @@ -122,7 +122,7 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---only-development ` -exports[`test/lib/ls.js TAP ls --only=prod > should output tree containing only prod deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --only=prod > should output tree containing only prod deps 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---only-prod +-- chai@1.0.0 +-- optional-dep@1.0.0 @@ -131,32 +131,32 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---only-prod ` -exports[`test/lib/ls.js TAP ls --parseable --depth=0 > should output tree containing only top-level dependencies 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable --depth=0 > should output tree containing only top-level dependencies 1`] = ` {CWD}/tap-testdir-ls-ls---parseable---depth-0 {CWD}/tap-testdir-ls-ls---parseable---depth-0/node_modules/chai {CWD}/tap-testdir-ls-ls---parseable---depth-0/node_modules/foo ` -exports[`test/lib/ls.js TAP ls --parseable --depth=1 > should output parseable containing top-level deps and their deps only 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable --depth=1 > should output parseable containing top-level deps and their deps only 1`] = ` {CWD}/tap-testdir-ls-ls---parseable---depth-1 {CWD}/tap-testdir-ls-ls---parseable---depth-1/node_modules/chai {CWD}/tap-testdir-ls-ls---parseable---depth-1/node_modules/foo {CWD}/tap-testdir-ls-ls---parseable---depth-1/node_modules/dog ` -exports[`test/lib/ls.js TAP ls --parseable --dev > should output tree containing dev deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable --dev > should output tree containing dev deps 1`] = ` {CWD}/tap-testdir-ls-ls---parseable---dev {CWD}/tap-testdir-ls-ls---parseable---dev/node_modules/dev-dep {CWD}/tap-testdir-ls-ls---parseable---dev/node_modules/foo {CWD}/tap-testdir-ls-ls---parseable---dev/node_modules/dog ` -exports[`test/lib/ls.js TAP ls --parseable --link > should output tree containing linked deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable --link > should output tree containing linked deps 1`] = ` {CWD}/tap-testdir-ls-ls---parseable---link {CWD}/tap-testdir-ls-ls---parseable---link/node_modules/linked-dep ` -exports[`test/lib/ls.js TAP ls --parseable --long --depth=0 > should output tree containing top-level deps with descriptions 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable --long --depth=0 > should output tree containing top-level deps with descriptions 1`] = ` {CWD}/tap-testdir-ls-ls---parseable---long---depth-0:test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---parseable---long---depth-0/node_modules/chai:chai@1.0.0 {CWD}/tap-testdir-ls-ls---parseable---long---depth-0/node_modules/dev-dep:dev-dep@1.0.0 @@ -165,7 +165,7 @@ exports[`test/lib/ls.js TAP ls --parseable --long --depth=0 > should output tree {CWD}/tap-testdir-ls-ls---parseable---long---depth-0/node_modules/prod-dep:prod-dep@1.0.0 ` -exports[`test/lib/ls.js TAP ls --parseable --long > should output tree info with descriptions 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable --long > should output tree info with descriptions 1`] = ` {CWD}/tap-testdir-ls-ls---parseable---long:test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---parseable---long/node_modules/chai:chai@1.0.0 {CWD}/tap-testdir-ls-ls---parseable---long/node_modules/dev-dep:dev-dep@1.0.0 @@ -177,14 +177,14 @@ exports[`test/lib/ls.js TAP ls --parseable --long > should output tree info with {CWD}/tap-testdir-ls-ls---parseable---long/node_modules/dog:dog@1.0.0 ` -exports[`test/lib/ls.js TAP ls --parseable --long missing/invalid/extraneous > should output parseable result containing EXTRANEOUS/INVALID labels 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable --long missing/invalid/extraneous > should output parseable result containing EXTRANEOUS/INVALID labels 1`] = ` {CWD}/tap-testdir-ls-ls---parseable---long-missing-invalid-extraneous:test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---parseable---long-missing-invalid-extraneous/node_modules/chai:chai@1.0.0:EXTRANEOUS {CWD}/tap-testdir-ls-ls---parseable---long-missing-invalid-extraneous/node_modules/foo:foo@1.0.0:INVALID {CWD}/tap-testdir-ls-ls---parseable---long-missing-invalid-extraneous/node_modules/dog:dog@1.0.0 ` -exports[`test/lib/ls.js TAP ls --parseable --long print symlink target location > should output parseable results with symlink targets 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable --long print symlink target location > should output parseable results with symlink targets 1`] = ` {CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location:test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location/node_modules/chai:chai@1.0.0 {CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location/node_modules/dev-dep:dev-dep@1.0.0 @@ -197,21 +197,21 @@ exports[`test/lib/ls.js TAP ls --parseable --long print symlink target location {CWD}/tap-testdir-ls-ls---parseable---long-print-symlink-target-location/node_modules/dog:dog@1.0.0 ` -exports[`test/lib/ls.js TAP ls --parseable --long with extraneous deps > should output long parseable output with extraneous info 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable --long with extraneous deps > should output long parseable output with extraneous info 1`] = ` {CWD}/tap-testdir-ls-ls---parseable---long-with-extraneous-deps:test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---parseable---long-with-extraneous-deps/node_modules/chai:chai@1.0.0:EXTRANEOUS {CWD}/tap-testdir-ls-ls---parseable---long-with-extraneous-deps/node_modules/foo:foo@1.0.0 {CWD}/tap-testdir-ls-ls---parseable---long-with-extraneous-deps/node_modules/dog:dog@1.0.0 ` -exports[`test/lib/ls.js TAP ls --parseable --only=development > should output tree containing only development deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable --only=development > should output tree containing only development deps 1`] = ` {CWD}/tap-testdir-ls-ls---parseable---only-development {CWD}/tap-testdir-ls-ls---parseable---only-development/node_modules/dev-dep {CWD}/tap-testdir-ls-ls---parseable---only-development/node_modules/foo {CWD}/tap-testdir-ls-ls---parseable---only-development/node_modules/dog ` -exports[`test/lib/ls.js TAP ls --parseable --only=prod > should output tree containing only prod deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable --only=prod > should output tree containing only prod deps 1`] = ` {CWD}/tap-testdir-ls-ls---parseable---only-prod {CWD}/tap-testdir-ls-ls---parseable---only-prod/node_modules/chai {CWD}/tap-testdir-ls-ls---parseable---only-prod/node_modules/optional-dep @@ -219,7 +219,7 @@ exports[`test/lib/ls.js TAP ls --parseable --only=prod > should output tree cont {CWD}/tap-testdir-ls-ls---parseable---only-prod/node_modules/prod-dep/node_modules/dog ` -exports[`test/lib/ls.js TAP ls --parseable --production > should output tree containing production deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable --production > should output tree containing production deps 1`] = ` {CWD}/tap-testdir-ls-ls---parseable---production {CWD}/tap-testdir-ls-ls---parseable---production/node_modules/chai {CWD}/tap-testdir-ls-ls---parseable---production/node_modules/optional-dep @@ -227,72 +227,72 @@ exports[`test/lib/ls.js TAP ls --parseable --production > should output tree con {CWD}/tap-testdir-ls-ls---parseable---production/node_modules/prod-dep/node_modules/dog ` -exports[`test/lib/ls.js TAP ls --parseable cycle deps > should print tree output omitting deduped ref 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable cycle deps > should print tree output omitting deduped ref 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-cycle-deps {CWD}/tap-testdir-ls-ls---parseable-cycle-deps/node_modules/a {CWD}/tap-testdir-ls-ls---parseable-cycle-deps/node_modules/b ` -exports[`test/lib/ls.js TAP ls --parseable default --depth value should be 0 > should output parseable output containing only top-level dependencies 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable default --depth value should be 0 > should output parseable output containing only top-level dependencies 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-default---depth-value-should-be-0 {CWD}/tap-testdir-ls-ls---parseable-default---depth-value-should-be-0/node_modules/chai {CWD}/tap-testdir-ls-ls---parseable-default---depth-value-should-be-0/node_modules/foo ` -exports[`test/lib/ls.js TAP ls --parseable empty location > should print empty result 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable empty location > should print empty result 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-empty-location ` -exports[`test/lib/ls.js TAP ls --parseable extraneous deps > should output containing problems info 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable extraneous deps > should output containing problems info 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-extraneous-deps {CWD}/tap-testdir-ls-ls---parseable-extraneous-deps/node_modules/chai {CWD}/tap-testdir-ls-ls---parseable-extraneous-deps/node_modules/foo {CWD}/tap-testdir-ls-ls---parseable-extraneous-deps/node_modules/dog ` -exports[`test/lib/ls.js TAP ls --parseable from and resolved properties > should not be printed in tree output 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable from and resolved properties > should not be printed in tree output 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-from-and-resolved-properties {CWD}/tap-testdir-ls-ls---parseable-from-and-resolved-properties/node_modules/simple-output ` -exports[`test/lib/ls.js TAP ls --parseable global > should print parseable output for global deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable global > should print parseable output for global deps 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-global {CWD}/tap-testdir-ls-ls---parseable-global/node_modules/a {CWD}/tap-testdir-ls-ls---parseable-global/node_modules/b {CWD}/tap-testdir-ls-ls---parseable-global/node_modules/b/node_modules/c ` -exports[`test/lib/ls.js TAP ls --parseable json read problems > should print empty result 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable json read problems > should print empty result 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-json-read-problems ` -exports[`test/lib/ls.js TAP ls --parseable missing package.json > should output parseable missing name/version of top-level package 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable missing package.json > should output parseable missing name/version of top-level package 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-missing-package.json {CWD}/tap-testdir-ls-ls---parseable-missing-package.json/node_modules/chai {CWD}/tap-testdir-ls-ls---parseable-missing-package.json/node_modules/dog {CWD}/tap-testdir-ls-ls---parseable-missing-package.json/node_modules/foo ` -exports[`test/lib/ls.js TAP ls --parseable missing/invalid/extraneous > should output parseable containing top-level deps and their deps only 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable missing/invalid/extraneous > should output parseable containing top-level deps and their deps only 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-missing-invalid-extraneous {CWD}/tap-testdir-ls-ls---parseable-missing-invalid-extraneous/node_modules/chai {CWD}/tap-testdir-ls-ls---parseable-missing-invalid-extraneous/node_modules/foo {CWD}/tap-testdir-ls-ls---parseable-missing-invalid-extraneous/node_modules/dog ` -exports[`test/lib/ls.js TAP ls --parseable no args > should output parseable representation of dependencies structure 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable no args > should output parseable representation of dependencies structure 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-no-args {CWD}/tap-testdir-ls-ls---parseable-no-args/node_modules/chai {CWD}/tap-testdir-ls-ls---parseable-no-args/node_modules/foo {CWD}/tap-testdir-ls-ls---parseable-no-args/node_modules/dog ` -exports[`test/lib/ls.js TAP ls --parseable resolved points to git ref > should output tree containing git refs 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable resolved points to git ref > should output tree containing git refs 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-resolved-points-to-git-ref {CWD}/tap-testdir-ls-ls---parseable-resolved-points-to-git-ref/node_modules/abbrev ` -exports[`test/lib/ls.js TAP ls --parseable unmet optional dep > should output parseable with empty entry for missing optional deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable unmet optional dep > should output parseable with empty entry for missing optional deps 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-unmet-optional-dep {CWD}/tap-testdir-ls-ls---parseable-unmet-optional-dep/node_modules/chai {CWD}/tap-testdir-ls-ls---parseable-unmet-optional-dep/node_modules/dev-dep @@ -304,7 +304,7 @@ exports[`test/lib/ls.js TAP ls --parseable unmet optional dep > should output pa {CWD}/tap-testdir-ls-ls---parseable-unmet-optional-dep/node_modules/dog ` -exports[`test/lib/ls.js TAP ls --parseable unmet peer dep > should output parseable signaling missing peer dep in problems 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable unmet peer dep > should output parseable signaling missing peer dep in problems 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-unmet-peer-dep {CWD}/tap-testdir-ls-ls---parseable-unmet-peer-dep/node_modules/chai {CWD}/tap-testdir-ls-ls---parseable-unmet-peer-dep/node_modules/dev-dep @@ -316,29 +316,29 @@ exports[`test/lib/ls.js TAP ls --parseable unmet peer dep > should output parsea {CWD}/tap-testdir-ls-ls---parseable-unmet-peer-dep/node_modules/dog ` -exports[`test/lib/ls.js TAP ls --parseable using aliases > should output tree containing aliases 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable using aliases > should output tree containing aliases 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-using-aliases {CWD}/tap-testdir-ls-ls---parseable-using-aliases/node_modules/a ` -exports[`test/lib/ls.js TAP ls --parseable with filter arg > should output parseable contaning only occurrences of filtered by package 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable with filter arg > should output parseable contaning only occurrences of filtered by package 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-with-filter-arg/node_modules/chai ` -exports[`test/lib/ls.js TAP ls --parseable with filter arg nested dep > should output parseable contaning only occurrences of filtered package 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable with filter arg nested dep > should output parseable contaning only occurrences of filtered package 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-with-filter-arg-nested-dep/node_modules/dog ` -exports[`test/lib/ls.js TAP ls --parseable with missing filter arg > should output parseable output containing no dependencies info 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable with missing filter arg > should output parseable output containing no dependencies info 1`] = ` ` -exports[`test/lib/ls.js TAP ls --parseable with multiple filter args > should output parseable contaning only occurrences of multiple filtered packages and their ancestors 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --parseable with multiple filter args > should output parseable contaning only occurrences of multiple filtered packages and their ancestors 1`] = ` {CWD}/tap-testdir-ls-ls---parseable-with-multiple-filter-args/node_modules/chai {CWD}/tap-testdir-ls-ls---parseable-with-multiple-filter-args/node_modules/dog ` -exports[`test/lib/ls.js TAP ls --production > should output tree containing production deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls --production > should output tree containing production deps 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---production +-- chai@1.0.0 +-- optional-dep@1.0.0 @@ -347,13 +347,13 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls---production ` -exports[`test/lib/ls.js TAP ls broken resolved field > should NOT print git refs in output tree 1`] = ` +exports[`test/lib/commands/ls.js TAP ls broken resolved field > should NOT print git refs in output tree 1`] = ` npm-broken-resolved-field-test@1.0.0 {CWD}/tap-testdir-ls-ls-broken-resolved-field \`-- a@1.0.1 ` -exports[`test/lib/ls.js TAP ls colored output > should output tree containing color info 1`] = ` +exports[`test/lib/commands/ls.js TAP ls colored output > should output tree containing color info 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-colored-output +-- chai@1.0.0 extraneous +-- foo@1.0.0 invalid: "^2.0.0" from the root project @@ -362,7 +362,7 @@ exports[`test/lib/ls.js TAP ls colored output > should output tree containing co  ` -exports[`test/lib/ls.js TAP ls cycle deps > should print tree output containing deduped ref 1`] = ` +exports[`test/lib/commands/ls.js TAP ls cycle deps > should print tree output containing deduped ref 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-cycle-deps \`-- a@1.0.0 \`-- b@1.0.0 @@ -370,7 +370,7 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-cycle-deps ` -exports[`test/lib/ls.js TAP ls cycle deps with filter args > should print tree output containing deduped ref 1`] = ` +exports[`test/lib/commands/ls.js TAP ls cycle deps with filter args > should print tree output containing deduped ref 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-cycle-deps-with-filter-args \`-- a@1.0.0  \`-- b@1.0.0 @@ -378,7 +378,7 @@ exports[`test/lib/ls.js TAP ls cycle deps with filter args > should print tree o  ` -exports[`test/lib/ls.js TAP ls deduped missing dep > should output parseable signaling missing peer dep in problems 1`] = ` +exports[`test/lib/commands/ls.js TAP ls deduped missing dep > should output parseable signaling missing peer dep in problems 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-deduped-missing-dep +-- a@1.0.0 | \`-- UNMET DEPENDENCY b@^1.0.0 @@ -386,20 +386,20 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-deduped-missing-dep ` -exports[`test/lib/ls.js TAP ls default --depth value should be 0 > should output tree containing only top-level dependencies 1`] = ` +exports[`test/lib/commands/ls.js TAP ls default --depth value should be 0 > should output tree containing only top-level dependencies 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-default---depth-value-should-be-0 +-- chai@1.0.0 \`-- foo@1.0.0 ` -exports[`test/lib/ls.js TAP ls empty location > should print empty result 1`] = ` +exports[`test/lib/commands/ls.js TAP ls empty location > should print empty result 1`] = ` {CWD}/tap-testdir-ls-ls-empty-location \`-- (empty) ` -exports[`test/lib/ls.js TAP ls extraneous deps > should output containing problems info 1`] = ` +exports[`test/lib/commands/ls.js TAP ls extraneous deps > should output containing problems info 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-extraneous-deps +-- chai@1.0.0 extraneous \`-- foo@1.0.0 @@ -407,19 +407,19 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-extraneous-deps ` -exports[`test/lib/ls.js TAP ls filter pkg arg using depth option > should list a in top-level only 1`] = ` +exports[`test/lib/commands/ls.js TAP ls filter pkg arg using depth option > should list a in top-level only 1`] = ` test-pkg-arg-filter-with-depth-opt@1.0.0 {CWD}/tap-testdir-ls-ls-filter-pkg-arg-using-depth-option \`-- a@1.0.0 ` -exports[`test/lib/ls.js TAP ls filter pkg arg using depth option > should print empty results msg 1`] = ` +exports[`test/lib/commands/ls.js TAP ls filter pkg arg using depth option > should print empty results msg 1`] = ` test-pkg-arg-filter-with-depth-opt@1.0.0 {CWD}/tap-testdir-ls-ls-filter-pkg-arg-using-depth-option \`-- (empty) ` -exports[`test/lib/ls.js TAP ls filter pkg arg using depth option > should print expected result 1`] = ` +exports[`test/lib/commands/ls.js TAP ls filter pkg arg using depth option > should print expected result 1`] = ` test-pkg-arg-filter-with-depth-opt@1.0.0 {CWD}/tap-testdir-ls-ls-filter-pkg-arg-using-depth-option \`-- b@1.0.0 \`-- c@1.0.0 @@ -427,7 +427,7 @@ test-pkg-arg-filter-with-depth-opt@1.0.0 {CWD}/tap-testdir-ls-ls-filter-pkg-arg- ` -exports[`test/lib/ls.js TAP ls filtering by child of missing dep > should print tree and not duplicate child of missing items 1`] = ` +exports[`test/lib/commands/ls.js TAP ls filtering by child of missing dep > should print tree and not duplicate child of missing items 1`] = ` filter-by-child-of-missing-dep@1.0.0 {CWD}/tap-testdir-ls-ls-filtering-by-child-of-missing-dep +-- b@1.0.0 extraneous | \`-- c@1.0.0 deduped @@ -437,13 +437,13 @@ filter-by-child-of-missing-dep@1.0.0 {CWD}/tap-testdir-ls-ls-filtering-by-child- ` -exports[`test/lib/ls.js TAP ls from and resolved properties > should not be printed in tree output 1`] = ` +exports[`test/lib/commands/ls.js TAP ls from and resolved properties > should not be printed in tree output 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-from-and-resolved-properties \`-- simple-output@2.1.1 ` -exports[`test/lib/ls.js TAP ls global > should print tree and not mark top-level items extraneous 1`] = ` +exports[`test/lib/commands/ls.js TAP ls global > should print tree and not mark top-level items extraneous 1`] = ` {CWD}/tap-testdir-ls-ls-global +-- a@1.0.0 \`-- b@1.0.0 @@ -451,7 +451,7 @@ exports[`test/lib/ls.js TAP ls global > should print tree and not mark top-level ` -exports[`test/lib/ls.js TAP ls invalid deduped dep > should output tree signaling mismatching peer dep in problems 1`] = ` +exports[`test/lib/commands/ls.js TAP ls invalid deduped dep > should output tree signaling mismatching peer dep in problems 1`] = ` invalid-deduped-dep@1.0.0 {CWD}/tap-testdir-ls-ls-invalid-deduped-dep +-- a@1.0.0 | \`-- b@1.0.0 deduped invalid: "^2.0.0" from the root project, "^2.0.0" from node_modules/a @@ -459,7 +459,7 @@ exports[`test/lib/ls.js TAP ls invalid deduped dep > should output tree signalin  ` -exports[`test/lib/ls.js TAP ls invalid peer dep > should output tree signaling mismatching peer dep in problems 1`] = ` +exports[`test/lib/commands/ls.js TAP ls invalid peer dep > should output tree signaling mismatching peer dep in problems 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-invalid-peer-dep +-- chai@1.0.0 +-- dev-dep@1.0.0 @@ -472,20 +472,20 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-invalid-peer-dep ` -exports[`test/lib/ls.js TAP ls json read problems > should print empty result 1`] = ` +exports[`test/lib/commands/ls.js TAP ls json read problems > should print empty result 1`] = ` {CWD}/tap-testdir-ls-ls-json-read-problems \`-- (empty) ` -exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should filter by parent folder workspace config 1`] = ` +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should filter by parent folder workspace config 1`] = ` workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +-- e@1.0.0 -> ./group/e \`-- f@1.0.0 -> ./group/f ` -exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should filter single workspace 1`] = ` +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should filter single workspace 1`] = ` workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +-- a@1.0.0 -> ./a | \`-- d@1.0.0 deduped -> ./d @@ -493,7 +493,7 @@ workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspac ` -exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should filter using workspace config 1`] = ` +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should filter using workspace config 1`] = ` workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces \`-- a@1.0.0 -> ./a +-- baz@1.0.0 @@ -504,7 +504,7 @@ workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspac ` -exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should list --all workspaces properly 1`] = ` +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should list --all workspaces properly 1`] = ` workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +-- a@1.0.0 -> ./a | +-- baz@1.0.0 @@ -519,7 +519,7 @@ workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspac ` -exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should list only prod deps of workspaces 1`] = ` +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should list only prod deps of workspaces 1`] = ` workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +-- a@1.0.0 -> ./a | +-- c@1.0.0 @@ -533,7 +533,7 @@ workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspac ` -exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should list workspaces properly with default configs 1`] = ` +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should list workspaces properly with default configs 1`] = ` workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces +-- a@1.0.0 -> ./a | +-- baz@1.0.0 @@ -547,13 +547,13 @@ exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should lis  ` -exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should not list workspaces with --no-workspaces 1`] = ` +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should not list workspaces with --no-workspaces 1`] = ` workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces \`-- (empty)  ` -exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should print all tree and filter by dep within only the ws subtree 1`] = ` +exports[`test/lib/commands/ls.js TAP ls loading a tree containing workspaces > should print all tree and filter by dep within only the ws subtree 1`] = ` workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces \`-- d@1.0.0 -> ./d \`-- foo@1.1.1 @@ -561,7 +561,7 @@ workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspac ` -exports[`test/lib/ls.js TAP ls missing package.json > should output tree missing name/version of top-level package 1`] = ` +exports[`test/lib/commands/ls.js TAP ls missing package.json > should output tree missing name/version of top-level package 1`] = ` {CWD}/tap-testdir-ls-ls-missing-package.json +-- chai@1.0.0 extraneous +-- dog@1.0.0 extraneous @@ -570,7 +570,7 @@ exports[`test/lib/ls.js TAP ls missing package.json > should output tree missing ` -exports[`test/lib/ls.js TAP ls missing/invalid/extraneous > should output tree containing missing, invalid, extraneous labels 1`] = ` +exports[`test/lib/commands/ls.js TAP ls missing/invalid/extraneous > should output tree containing missing, invalid, extraneous labels 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-missing-invalid-extraneous +-- chai@1.0.0 extraneous +-- foo@1.0.0 invalid: "^2.0.0" from the root project @@ -579,7 +579,7 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-missing-invalid-extraneous ` -exports[`test/lib/ls.js TAP ls no args > should output tree representation of dependencies structure 1`] = ` +exports[`test/lib/commands/ls.js TAP ls no args > should output tree representation of dependencies structure 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-no-args +-- chai@1.0.0 \`-- foo@1.0.0 @@ -587,7 +587,7 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-no-args ` -exports[`test/lib/ls.js TAP ls print deduped symlinks > should output tree containing linked deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls print deduped symlinks > should output tree containing linked deps 1`] = ` print-deduped-symlinks@1.0.0 {CWD}/tap-testdir-ls-ls-print-deduped-symlinks +-- a@1.0.0 | \`-- b@1.0.0 deduped -> ./b @@ -595,13 +595,13 @@ print-deduped-symlinks@1.0.0 {CWD}/tap-testdir-ls-ls-print-deduped-symlinks ` -exports[`test/lib/ls.js TAP ls resolved points to git ref > should output tree containing git refs 1`] = ` +exports[`test/lib/commands/ls.js TAP ls resolved points to git ref > should output tree containing git refs 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-resolved-points-to-git-ref \`-- abbrev@1.1.1 (git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c) ` -exports[`test/lib/ls.js TAP ls unmet optional dep > should output tree with empty entry for missing optional deps 1`] = ` +exports[`test/lib/commands/ls.js TAP ls unmet optional dep > should output tree with empty entry for missing optional deps 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-unmet-optional-dep +-- chai@1.0.0 +-- dev-dep@1.0.0 @@ -615,19 +615,19 @@ exports[`test/lib/ls.js TAP ls unmet optional dep > should output tree with empt  ` -exports[`test/lib/ls.js TAP ls unmet peer dep > should output tree signaling missing peer dep in problems 1`] = ` +exports[`test/lib/commands/ls.js TAP ls unmet peer dep > should output tree signaling missing peer dep in problems 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-unmet-peer-dep \`-- UNMET DEPENDENCY peer-dep@* ` -exports[`test/lib/ls.js TAP ls using aliases > should output tree containing aliases 1`] = ` +exports[`test/lib/commands/ls.js TAP ls using aliases > should output tree containing aliases 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-using-aliases \`-- a@npm:b@1.0.0 ` -exports[`test/lib/ls.js TAP ls with args and dedupe entries > should print tree output containing deduped ref 1`] = ` +exports[`test/lib/commands/ls.js TAP ls with args and dedupe entries > should print tree output containing deduped ref 1`] = ` dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-args-and-dedupe-entries +-- @npmcli/a@1.0.0 | \`-- @npmcli/b@1.1.2 deduped @@ -637,7 +637,7 @@ exports[`test/lib/ls.js TAP ls with args and dedupe entries > should print tree  ` -exports[`test/lib/ls.js TAP ls with args and different order of items > should print tree output containing deduped ref 1`] = ` +exports[`test/lib/commands/ls.js TAP ls with args and different order of items > should print tree output containing deduped ref 1`] = ` dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-args-and-different-order-of-items +-- @npmcli/a@1.0.0 | \`-- @npmcli/c@1.0.0 deduped @@ -647,32 +647,32 @@ dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-args-and-different-order-of-it ` -exports[`test/lib/ls.js TAP ls with dot filter arg > should output tree contaning only occurrences of filtered by package and colored output 1`] = ` +exports[`test/lib/commands/ls.js TAP ls with dot filter arg > should output tree contaning only occurrences of filtered by package and colored output 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-with-dot-filter-arg \`-- (empty) ` -exports[`test/lib/ls.js TAP ls with filter arg > should output tree contaning only occurrences of filtered by package and colored output 1`] = ` +exports[`test/lib/commands/ls.js TAP ls with filter arg > should output tree contaning only occurrences of filtered by package and colored output 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-with-filter-arg \`-- chai@1.0.0  ` -exports[`test/lib/ls.js TAP ls with filter arg nested dep > should output tree contaning only occurrences of filtered package and its ancestors 1`] = ` +exports[`test/lib/commands/ls.js TAP ls with filter arg nested dep > should output tree contaning only occurrences of filtered package and its ancestors 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-with-filter-arg-nested-dep \`-- foo@1.0.0 \`-- dog@1.0.0 ` -exports[`test/lib/ls.js TAP ls with missing filter arg > should output tree containing no dependencies info 1`] = ` +exports[`test/lib/commands/ls.js TAP ls with missing filter arg > should output tree containing no dependencies info 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-with-missing-filter-arg \`-- (empty) ` -exports[`test/lib/ls.js TAP ls with multiple filter args > should output tree contaning only occurrences of multiple filtered packages and their ancestors 1`] = ` +exports[`test/lib/commands/ls.js TAP ls with multiple filter args > should output tree contaning only occurrences of multiple filtered packages and their ancestors 1`] = ` test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-with-multiple-filter-args +-- chai@1.0.0 \`-- foo@1.0.0 @@ -680,7 +680,7 @@ test-npm-ls@1.0.0 {CWD}/tap-testdir-ls-ls-with-multiple-filter-args ` -exports[`test/lib/ls.js TAP ls with no args dedupe entries > should print tree output containing deduped ref 1`] = ` +exports[`test/lib/commands/ls.js TAP ls with no args dedupe entries > should print tree output containing deduped ref 1`] = ` dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-no-args-dedupe-entries +-- @npmcli/a@1.0.0 | \`-- @npmcli/b@1.1.2 deduped @@ -690,7 +690,7 @@ dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-no-args-dedupe-entries ` -exports[`test/lib/ls.js TAP ls with no args dedupe entries and not displaying all > should print tree output containing deduped ref 1`] = ` +exports[`test/lib/commands/ls.js TAP ls with no args dedupe entries and not displaying all > should print tree output containing deduped ref 1`] = ` dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-no-args-dedupe-entries-and-not-displaying-all +-- @npmcli/a@1.0.0 +-- @npmcli/b@1.1.2 @@ -698,7 +698,7 @@ dedupe-entries@1.0.0 {CWD}/tap-testdir-ls-ls-with-no-args-dedupe-entries-and-not ` -exports[`test/lib/ls.js TAP show multiple invalid reasons > ls result 1`] = ` +exports[`test/lib/commands/ls.js TAP show multiple invalid reasons > ls result 1`] = ` test-npm-ls@1.0.0 {cwd}/tap-testdir-ls-show-multiple-invalid-reasons +-- cat@1.0.0 invalid: "^2.0.0" from the root project | \`-- dog@1.0.0 deduped invalid: "^1.2.3" from the root project, "^2.0.0" from node_modules/cat diff --git a/deps/npm/tap-snapshots/test/lib/outdated.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/outdated.js.test.cjs similarity index 59% rename from deps/npm/tap-snapshots/test/lib/outdated.js.test.cjs rename to deps/npm/tap-snapshots/test/lib/commands/outdated.js.test.cjs index 15e8150311cf94..c286ad734e6b8f 100644 --- a/deps/npm/tap-snapshots/test/lib/outdated.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/outdated.js.test.cjs @@ -5,7 +5,7 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/outdated.js TAP should display outdated deps outdated --all > must match snapshot 1`] = ` +exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --all > must match snapshot 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps @@ -14,7 +14,7 @@ dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-should theta MISSING 1.0.1 1.0.1 - tap-testdir-outdated-should-display-outdated-deps ` -exports[`test/lib/outdated.js TAP should display outdated deps outdated --json --long > must match snapshot 1`] = ` +exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --json --long > must match snapshot 1`] = ` { "cat": { @@ -22,7 +22,7 @@ exports[`test/lib/outdated.js TAP should display outdated deps outdated --json - "wanted": "1.0.1", "latest": "1.0.1", "dependent": "tap-testdir-outdated-should-display-outdated-deps", - "location": "{CWD}/test/lib/tap-testdir-outdated-should-display-outdated-deps/node_modules/cat", + "location": "{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/cat", "type": "dependencies" }, "chai": { @@ -30,7 +30,7 @@ exports[`test/lib/outdated.js TAP should display outdated deps outdated --json - "wanted": "1.0.1", "latest": "1.0.1", "dependent": "tap-testdir-outdated-should-display-outdated-deps", - "location": "{CWD}/test/lib/tap-testdir-outdated-should-display-outdated-deps/node_modules/chai", + "location": "{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/chai", "type": "peerDependencies" }, "dog": { @@ -38,7 +38,7 @@ exports[`test/lib/outdated.js TAP should display outdated deps outdated --json - "wanted": "1.0.1", "latest": "2.0.0", "dependent": "tap-testdir-outdated-should-display-outdated-deps", - "location": "{CWD}/test/lib/tap-testdir-outdated-should-display-outdated-deps/node_modules/dog", + "location": "{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/dog", "type": "dependencies" }, "theta": { @@ -50,7 +50,7 @@ exports[`test/lib/outdated.js TAP should display outdated deps outdated --json - } ` -exports[`test/lib/outdated.js TAP should display outdated deps outdated --json > must match snapshot 1`] = ` +exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --json > must match snapshot 1`] = ` { "cat": { @@ -58,21 +58,21 @@ exports[`test/lib/outdated.js TAP should display outdated deps outdated --json > "wanted": "1.0.1", "latest": "1.0.1", "dependent": "tap-testdir-outdated-should-display-outdated-deps", - "location": "{CWD}/test/lib/tap-testdir-outdated-should-display-outdated-deps/node_modules/cat" + "location": "{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/cat" }, "chai": { "current": "1.0.0", "wanted": "1.0.1", "latest": "1.0.1", "dependent": "tap-testdir-outdated-should-display-outdated-deps", - "location": "{CWD}/test/lib/tap-testdir-outdated-should-display-outdated-deps/node_modules/chai" + "location": "{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/chai" }, "dog": { "current": "1.0.1", "wanted": "1.0.1", "latest": "2.0.0", "dependent": "tap-testdir-outdated-should-display-outdated-deps", - "location": "{CWD}/test/lib/tap-testdir-outdated-should-display-outdated-deps/node_modules/dog" + "location": "{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/dog" }, "theta": { "wanted": "1.0.1", @@ -82,7 +82,7 @@ exports[`test/lib/outdated.js TAP should display outdated deps outdated --json > } ` -exports[`test/lib/outdated.js TAP should display outdated deps outdated --long > must match snapshot 1`] = ` +exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --long > must match snapshot 1`] = ` Package Current Wanted Latest Location Depended by Package Type Homepage cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps dependencies @@ -91,7 +91,7 @@ dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-should theta MISSING 1.0.1 1.0.1 - tap-testdir-outdated-should-display-outdated-deps dependencies ` -exports[`test/lib/outdated.js TAP should display outdated deps outdated --omit=dev --omit=peer > must match snapshot 1`] = ` +exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --omit=dev --omit=peer > must match snapshot 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps @@ -99,7 +99,7 @@ exports[`test/lib/outdated.js TAP should display outdated deps outdated --omit=d theta MISSING 1.0.1 1.0.1 - tap-testdir-outdated-should-display-outdated-deps ` -exports[`test/lib/outdated.js TAP should display outdated deps outdated --omit=dev > must match snapshot 1`] = ` +exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --omit=dev > must match snapshot 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps @@ -108,7 +108,7 @@ exports[`test/lib/outdated.js TAP should display outdated deps outdated --omit=d theta MISSING 1.0.1 1.0.1 - tap-testdir-outdated-should-display-outdated-deps ` -exports[`test/lib/outdated.js TAP should display outdated deps outdated --omit=prod > must match snapshot 1`] = ` +exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --omit=prod > must match snapshot 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps @@ -116,23 +116,23 @@ exports[`test/lib/outdated.js TAP should display outdated deps outdated --omit=p dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-should-display-outdated-deps ` -exports[`test/lib/outdated.js TAP should display outdated deps outdated --parseable --long > must match snapshot 1`] = ` +exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --parseable --long > must match snapshot 1`] = ` -{CWD}/test/lib/tap-testdir-outdated-should-display-outdated-deps/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:tap-testdir-outdated-should-display-outdated-deps:dependencies: -{CWD}/test/lib/tap-testdir-outdated-should-display-outdated-deps/node_modules/chai:chai@1.0.1:chai@1.0.0:chai@1.0.1:tap-testdir-outdated-should-display-outdated-deps:peerDependencies: -{CWD}/test/lib/tap-testdir-outdated-should-display-outdated-deps/node_modules/dog:dog@1.0.1:dog@1.0.1:dog@2.0.0:tap-testdir-outdated-should-display-outdated-deps:dependencies: +{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:tap-testdir-outdated-should-display-outdated-deps:dependencies: +{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/chai:chai@1.0.1:chai@1.0.0:chai@1.0.1:tap-testdir-outdated-should-display-outdated-deps:peerDependencies: +{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/dog:dog@1.0.1:dog@1.0.1:dog@2.0.0:tap-testdir-outdated-should-display-outdated-deps:dependencies: :theta@1.0.1:MISSING:theta@1.0.1:tap-testdir-outdated-should-display-outdated-deps:dependencies: ` -exports[`test/lib/outdated.js TAP should display outdated deps outdated --parseable > must match snapshot 1`] = ` +exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated --parseable > must match snapshot 1`] = ` -{CWD}/test/lib/tap-testdir-outdated-should-display-outdated-deps/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:tap-testdir-outdated-should-display-outdated-deps -{CWD}/test/lib/tap-testdir-outdated-should-display-outdated-deps/node_modules/chai:chai@1.0.1:chai@1.0.0:chai@1.0.1:tap-testdir-outdated-should-display-outdated-deps -{CWD}/test/lib/tap-testdir-outdated-should-display-outdated-deps/node_modules/dog:dog@1.0.1:dog@1.0.1:dog@2.0.0:tap-testdir-outdated-should-display-outdated-deps +{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:tap-testdir-outdated-should-display-outdated-deps +{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/chai:chai@1.0.1:chai@1.0.0:chai@1.0.1:tap-testdir-outdated-should-display-outdated-deps +{CWD}/test/lib/commands/tap-testdir-outdated-should-display-outdated-deps/node_modules/dog:dog@1.0.1:dog@1.0.1:dog@2.0.0:tap-testdir-outdated-should-display-outdated-deps :theta@1.0.1:MISSING:theta@1.0.1:tap-testdir-outdated-should-display-outdated-deps ` -exports[`test/lib/outdated.js TAP should display outdated deps outdated > must match snapshot 1`] = ` +exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated > must match snapshot 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps @@ -141,19 +141,19 @@ exports[`test/lib/outdated.js TAP should display outdated deps outdated > must m theta MISSING 1.0.1 1.0.1 - tap-testdir-outdated-should-display-outdated-deps ` -exports[`test/lib/outdated.js TAP should display outdated deps outdated global > must match snapshot 1`] = ` +exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated global > must match snapshot 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat global ` -exports[`test/lib/outdated.js TAP should display outdated deps outdated specific dep > must match snapshot 1`] = ` +exports[`test/lib/commands/outdated.js TAP should display outdated deps outdated specific dep > must match snapshot 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat tap-testdir-outdated-should-display-outdated-deps ` -exports[`test/lib/outdated.js TAP workspaces > should display all dependencies 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces > should display all dependencies 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat a@1.0.0 @@ -162,7 +162,7 @@ dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-worksp theta MISSING 1.0.1 1.0.1 - c@1.0.0 ` -exports[`test/lib/outdated.js TAP workspaces > should display json results filtered by ws 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces > should display json results filtered by ws 1`] = ` { "cat": { @@ -170,44 +170,44 @@ exports[`test/lib/outdated.js TAP workspaces > should display json results filte "wanted": "1.0.1", "latest": "1.0.1", "dependent": "a", - "location": "{CWD}/test/lib/tap-testdir-outdated-workspaces/node_modules/cat" + "location": "{CWD}/test/lib/commands/tap-testdir-outdated-workspaces/node_modules/cat" } } ` -exports[`test/lib/outdated.js TAP workspaces > should display missing deps when filtering by ws 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces > should display missing deps when filtering by ws 1`] = ` Package Current Wanted Latest Location Depended by theta MISSING 1.0.1 1.0.1 - c@1.0.0 ` -exports[`test/lib/outdated.js TAP workspaces > should display nested deps when filtering by ws and using --all 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces > should display nested deps when filtering by ws and using --all 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat a@1.0.0 chai 1.0.0 1.0.1 1.0.1 node_modules/chai foo ` -exports[`test/lib/outdated.js TAP workspaces > should display no results if ws has no deps to display 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces > should display no results if ws has no deps to display 1`] = ` ` -exports[`test/lib/outdated.js TAP workspaces > should display only root outdated when ws disabled 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces > should display only root outdated when ws disabled 1`] = ` ` -exports[`test/lib/outdated.js TAP workspaces > should display parseable results filtered by ws 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces > should display parseable results filtered by ws 1`] = ` -{CWD}/test/lib/tap-testdir-outdated-workspaces/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:a +{CWD}/test/lib/commands/tap-testdir-outdated-workspaces/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:a ` -exports[`test/lib/outdated.js TAP workspaces > should display results filtered by ws 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces > should display results filtered by ws 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat a@1.0.0 ` -exports[`test/lib/outdated.js TAP workspaces > should display ws outdated deps human output 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces > should display ws outdated deps human output 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat a@1.0.0 @@ -215,7 +215,7 @@ dog 1.0.1 1.0.1 2.0.0 node_modules/dog tap-testdir-outdated-workspa theta MISSING 1.0.1 1.0.1 - c@1.0.0 ` -exports[`test/lib/outdated.js TAP workspaces > should display ws outdated deps json output 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces > should display ws outdated deps json output 1`] = ` { "cat": { @@ -223,14 +223,14 @@ exports[`test/lib/outdated.js TAP workspaces > should display ws outdated deps j "wanted": "1.0.1", "latest": "1.0.1", "dependent": "a", - "location": "{CWD}/test/lib/tap-testdir-outdated-workspaces/node_modules/cat" + "location": "{CWD}/test/lib/commands/tap-testdir-outdated-workspaces/node_modules/cat" }, "dog": { "current": "1.0.1", "wanted": "1.0.1", "latest": "2.0.0", "dependent": "tap-testdir-outdated-workspaces", - "location": "{CWD}/test/lib/tap-testdir-outdated-workspaces/node_modules/dog" + "location": "{CWD}/test/lib/commands/tap-testdir-outdated-workspaces/node_modules/dog" }, "theta": { "wanted": "1.0.1", @@ -240,14 +240,14 @@ exports[`test/lib/outdated.js TAP workspaces > should display ws outdated deps j } ` -exports[`test/lib/outdated.js TAP workspaces > should display ws outdated deps parseable output 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces > should display ws outdated deps parseable output 1`] = ` -{CWD}/test/lib/tap-testdir-outdated-workspaces/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:a -{CWD}/test/lib/tap-testdir-outdated-workspaces/node_modules/dog:dog@1.0.1:dog@1.0.1:dog@2.0.0:tap-testdir-outdated-workspaces +{CWD}/test/lib/commands/tap-testdir-outdated-workspaces/node_modules/cat:cat@1.0.1:cat@1.0.0:cat@1.0.1:a +{CWD}/test/lib/commands/tap-testdir-outdated-workspaces/node_modules/dog:dog@1.0.1:dog@1.0.1:dog@2.0.0:tap-testdir-outdated-workspaces :theta@1.0.1:MISSING:theta@1.0.1:c ` -exports[`test/lib/outdated.js TAP workspaces > should highlight ws in dependend by section 1`] = ` +exports[`test/lib/commands/outdated.js TAP workspaces > should highlight ws in dependend by section 1`] = ` Package Current Wanted Latest Location Depended by cat 1.0.0 1.0.1 1.0.1 node_modules/cat a@1.0.0 diff --git a/deps/npm/tap-snapshots/test/lib/owner.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/owner.js.test.cjs similarity index 72% rename from deps/npm/tap-snapshots/test/lib/owner.js.test.cjs rename to deps/npm/tap-snapshots/test/lib/commands/owner.js.test.cjs index 2d92b0ae5ed6f4..f3d7335e473074 100644 --- a/deps/npm/tap-snapshots/test/lib/owner.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/owner.js.test.cjs @@ -5,14 +5,14 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/owner.js TAP owner ls > should output owners of 1`] = ` +exports[`test/lib/commands/owner.js TAP owner ls > should output owners of 1`] = ` nlf ruyadorno darcyclarke isaacs ` -exports[`test/lib/owner.js TAP owner ls no args > should output owners of cwd package 1`] = ` +exports[`test/lib/commands/owner.js TAP owner ls no args > should output owners of cwd package 1`] = ` nlf ruyadorno darcyclarke diff --git a/deps/npm/tap-snapshots/test/lib/profile.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/profile.js.test.cjs similarity index 59% rename from deps/npm/tap-snapshots/test/lib/profile.js.test.cjs rename to deps/npm/tap-snapshots/test/lib/commands/profile.js.test.cjs index 58975515162f6d..31205b7fedc05c 100644 --- a/deps/npm/tap-snapshots/test/lib/profile.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/profile.js.test.cjs @@ -5,7 +5,7 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/profile.js TAP enable-2fa from token and set otp, retries on pending and verifies with qrcode > should output 2fa enablement success msgs 1`] = ` +exports[`test/lib/commands/profile.js TAP enable-2fa from token and set otp, retries on pending and verifies with qrcode > should output 2fa enablement success msgs 1`] = ` Scan into your authenticator app: qrcode Or enter code: @@ -16,23 +16,23 @@ You will need these to recover access to your account if you lose your authentic 789101 ` -exports[`test/lib/profile.js TAP profile get --parseable > should output parseable result value 1`] = ` +exports[`test/lib/commands/profile.js TAP profile get --parseable > should output parseable result value 1`] = ` foo ` -exports[`test/lib/profile.js TAP profile get multiple args --parseable > should output parseable profile value results 1`] = ` +exports[`test/lib/commands/profile.js TAP profile get multiple args --parseable > should output parseable profile value results 1`] = ` foo foo@github.com (verified) https://github.com/npm ` -exports[`test/lib/profile.js TAP profile get multiple args comma separated > should output all keys 1`] = ` +exports[`test/lib/commands/profile.js TAP profile get multiple args comma separated > should output all keys 1`] = ` foo foo@github.com (verified) https://github.com/npm ` -exports[`test/lib/profile.js TAP profile get multiple args default output > should output all keys 1`] = ` +exports[`test/lib/commands/profile.js TAP profile get multiple args default output > should output all keys 1`] = ` foo foo@github.com (verified) https://github.com/npm ` -exports[`test/lib/profile.js TAP profile get no args --parseable > should output all profile info as parseable result 1`] = ` +exports[`test/lib/commands/profile.js TAP profile get no args --parseable > should output all profile info as parseable result 1`] = ` tfa auth-and-writes name foo email foo@github.com @@ -46,7 +46,7 @@ twitter https://twitter.com/npmjs github https://github.com/npm ` -exports[`test/lib/profile.js TAP profile get no args default output > should output table with contents 1`] = ` +exports[`test/lib/commands/profile.js TAP profile get no args default output > should output table with contents 1`] = ` name: foo email: foo@github.com (verified) two-factor auth: auth-and-writes @@ -59,7 +59,7 @@ created: 2015-02-26T01:26:37.384Z updated: 2020-08-12T16:19:35.326Z ` -exports[`test/lib/profile.js TAP profile get no args no tfa enabled > should output expected profile values 1`] = ` +exports[`test/lib/commands/profile.js TAP profile get no args no tfa enabled > should output expected profile values 1`] = ` name: foo email: foo@github.com (verified) two-factor auth: disabled @@ -72,7 +72,7 @@ created: 2015-02-26T01:26:37.384Z updated: 2020-08-12T16:19:35.326Z ` -exports[`test/lib/profile.js TAP profile get no args profile has cidr_whitelist item > should output table with contents 1`] = ` +exports[`test/lib/commands/profile.js TAP profile get no args profile has cidr_whitelist item > should output table with contents 1`] = ` name: foo email: foo@github.com (verified) two-factor auth: auth-and-writes @@ -86,7 +86,7 @@ updated: 2020-08-12T16:19:35.326Z cidr_whitelist: 192.168.1.1 ` -exports[`test/lib/profile.js TAP profile get no args unverified email > should output table with contents 1`] = ` +exports[`test/lib/commands/profile.js TAP profile get no args unverified email > should output table with contents 1`] = ` name: foo email: foo@github.com(unverified) two-factor auth: auth-and-writes @@ -99,6 +99,6 @@ created: 2015-02-26T01:26:37.384Z updated: 2020-08-12T16:19:35.326Z ` -exports[`test/lib/profile.js TAP profile set writable key --parseable > should output parseable set key success msg 1`] = ` +exports[`test/lib/commands/profile.js TAP profile set writable key --parseable > should output parseable set key success msg 1`] = ` fullname Lorem Ipsum ` diff --git a/deps/npm/tap-snapshots/test/lib/publish.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/publish.js.test.cjs similarity index 72% rename from deps/npm/tap-snapshots/test/lib/publish.js.test.cjs rename to deps/npm/tap-snapshots/test/lib/commands/publish.js.test.cjs index 38457821ab0c2b..6c50c921549095 100644 --- a/deps/npm/tap-snapshots/test/lib/publish.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/publish.js.test.cjs @@ -5,13 +5,13 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/publish.js TAP private workspaces colorless > should output all publishes 1`] = ` +exports[`test/lib/commands/publish.js TAP private workspaces colorless > should output all publishes 1`] = ` Array [ "+ @npmcli/b@1.0.0", ] ` -exports[`test/lib/publish.js TAP private workspaces colorless > should publish all non-private workspaces 1`] = ` +exports[`test/lib/commands/publish.js TAP private workspaces colorless > should publish all non-private workspaces 1`] = ` Array [ Object { "_id": "@npmcli/b@1.0.0", @@ -22,13 +22,13 @@ Array [ ] ` -exports[`test/lib/publish.js TAP private workspaces with color > should output all publishes 1`] = ` +exports[`test/lib/commands/publish.js TAP private workspaces with color > should output all publishes 1`] = ` Array [ "+ @npmcli/b@1.0.0", ] ` -exports[`test/lib/publish.js TAP private workspaces with color > should publish all non-private workspaces 1`] = ` +exports[`test/lib/commands/publish.js TAP private workspaces with color > should publish all non-private workspaces 1`] = ` Array [ Object { "_id": "@npmcli/b@1.0.0", @@ -39,8 +39,8 @@ Array [ ] ` -exports[`test/lib/publish.js TAP shows usage with wrong set of arguments > should print usage 1`] = ` -Error: +exports[`test/lib/commands/publish.js TAP shows usage with wrong set of arguments > should print usage 1`] = ` +Error: Usage: npm publish Publish a package @@ -58,7 +58,7 @@ Run "npm help publish" for more info { } ` -exports[`test/lib/publish.js TAP workspaces all workspaces > should output all publishes 1`] = ` +exports[`test/lib/commands/publish.js TAP workspaces all workspaces > should output all publishes 1`] = ` Array [ "+ workspace-a@1.2.3-a", "+ workspace-b@1.2.3-n", @@ -66,7 +66,7 @@ Array [ ] ` -exports[`test/lib/publish.js TAP workspaces all workspaces > should publish all workspaces 1`] = ` +exports[`test/lib/commands/publish.js TAP workspaces all workspaces > should publish all workspaces 1`] = ` Array [ Object { "_id": "workspace-a@1.2.3-a", @@ -101,7 +101,7 @@ Array [ ] ` -exports[`test/lib/publish.js TAP workspaces json > should output all publishes as json 1`] = ` +exports[`test/lib/commands/publish.js TAP workspaces json > should output all publishes as json 1`] = ` Array [ String( { @@ -119,7 +119,7 @@ Array [ ] ` -exports[`test/lib/publish.js TAP workspaces json > should publish all workspaces 1`] = ` +exports[`test/lib/commands/publish.js TAP workspaces json > should publish all workspaces 1`] = ` Array [ Object { "_id": "workspace-a@1.2.3-a", @@ -154,13 +154,13 @@ Array [ ] ` -exports[`test/lib/publish.js TAP workspaces one workspace > should output one publish 1`] = ` +exports[`test/lib/commands/publish.js TAP workspaces one workspace > should output one publish 1`] = ` Array [ "+ workspace-a@1.2.3-a", ] ` -exports[`test/lib/publish.js TAP workspaces one workspace > should publish given workspace 1`] = ` +exports[`test/lib/commands/publish.js TAP workspaces one workspace > should publish given workspace 1`] = ` Array [ Object { "_id": "workspace-a@1.2.3-a", diff --git a/deps/npm/tap-snapshots/test/lib/search.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/search.js.test.cjs similarity index 79% rename from deps/npm/tap-snapshots/test/lib/search.js.test.cjs rename to deps/npm/tap-snapshots/test/lib/commands/search.js.test.cjs index 4b4dc75ea3e896..9e27c4be47e1c1 100644 --- a/deps/npm/tap-snapshots/test/lib/search.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/search.js.test.cjs @@ -5,16 +5,16 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/search.js TAP empty search results > should have expected search results 1`] = ` +exports[`test/lib/commands/search.js TAP empty search results > should have expected search results 1`] = ` No matches found for "foo" ` -exports[`test/lib/search.js TAP search --searchexclude --searchopts > should have filtered expected search results 1`] = ` +exports[`test/lib/commands/search.js TAP search --searchexclude --searchopts > should have filtered expected search results 1`] = ` NAME | AUTHOR | DATE | VERSION | KEYWORDS -foo | =foo | prehistoric | 1.0.0 | +foo | =foo | prehistoric | 1.0.0 | ` -exports[`test/lib/search.js TAP search > should have expected search results 1`] = ` -NAME | AUTHOR | DATE | VERSION | KEYWORDS -libnpm | =nlf… | 2019-07-16 | 3.0.1 | npm api package manager liblibnpmaccess | =nlf… | 2020-11-03 | 4.0.1 | @evocateur/libnpmaccess | =evocateur | 2019-07-16 | 3.1.2 | @evocateur/libnpmpublish | =evocateur | 2019-07-16 | 1.2.2 | libnpmorg | =nlf… | 2020-11-03 | 2.0.1 | libnpm npm package manager api orgs teamslibnpmsearch | =nlf… | 2020-12-08 | 3.1.0 | npm search api libnpmlibnpmteam | =nlf… | 2020-11-03 | 2.0.2 | libnpmhook | =nlf… | 2020-11-03 | 6.0.1 | npm hooks registry npm apilibnpmpublish | =nlf… | 2020-11-03 | 4.0.0 | libnpmfund | =nlf… | 2020-12-08 | 1.0.2 | npm npmcli libnpm cli git fund gitfund@npmcli/map-workspaces | =nlf… | 2020-09-30 | 1.0.1 | npm npmcli libnpm cli workspaces map-workspaceslibnpmversion | =nlf… | 2020-11-04 | 1.0.7 | @types/libnpmsearch | =types | 2019-09-26 | 2.0.1 | +exports[`test/lib/commands/search.js TAP search > should have expected search results 1`] = ` +NAME | AUTHOR | DATE | VERSION | KEYWORDS +libnpm | =nlf… | 2019-07-16 | 3.0.1 | npm api package manager liblibnpmaccess | =nlf… | 2020-11-03 | 4.0.1 | @evocateur/libnpmaccess | =evocateur | 2019-07-16 | 3.1.2 | @evocateur/libnpmpublish | =evocateur | 2019-07-16 | 1.2.2 | libnpmorg | =nlf… | 2020-11-03 | 2.0.1 | libnpm npm package manager api orgs teamslibnpmsearch | =nlf… | 2020-12-08 | 3.1.0 | npm search api libnpmlibnpmteam | =nlf… | 2020-11-03 | 2.0.2 | libnpmhook | =nlf… | 2020-11-03 | 6.0.1 | npm hooks registry npm apilibnpmpublish | =nlf… | 2020-11-03 | 4.0.0 | libnpmfund | =nlf… | 2020-12-08 | 1.0.2 | npm npmcli libnpm cli git fund gitfund@npmcli/map-workspaces | =nlf… | 2020-09-30 | 1.0.1 | npm npmcli libnpm cli workspaces map-workspaceslibnpmversion | =nlf… | 2020-11-04 | 1.0.7 | @types/libnpmsearch | =types | 2019-09-26 | 2.0.1 | ` diff --git a/deps/npm/tap-snapshots/test/lib/commands/shrinkwrap.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/shrinkwrap.js.test.cjs new file mode 100644 index 00000000000000..a0d5795776d6f1 --- /dev/null +++ b/deps/npm/tap-snapshots/test/lib/commands/shrinkwrap.js.test.cjs @@ -0,0 +1,396 @@ +/* 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/commands/shrinkwrap.js TAP with hidden lockfile ancient > must match snapshot 1`] = ` +{ + "localPrefix": { + "node_modules": { + ".package-lock.json": { + "lockfileVersion": 1 + } + } + }, + "config": {}, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-ancient", + "lockfileVersion": 1, + "requires": true + }, + "logs": [ + "created a lockfile as npm-shrinkwrap.json" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile ancient upgrade > must match snapshot 1`] = ` +{ + "localPrefix": { + "node_modules": { + ".package-lock.json": { + "lockfileVersion": 1 + } + } + }, + "config": { + "lockfileVersion": 3 + }, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-ancient-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": {} + }, + "logs": [ + "created a lockfile as npm-shrinkwrap.json with version 3" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile existing > must match snapshot 1`] = ` +{ + "localPrefix": { + "node_modules": { + ".package-lock.json": { + "lockfileVersion": 2 + } + } + }, + "config": {}, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-existing", + "lockfileVersion": 2, + "requires": true, + "packages": {} + }, + "logs": [ + "created a lockfile as npm-shrinkwrap.json" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile existing downgrade > must match snapshot 1`] = ` +{ + "localPrefix": { + "node_modules": { + ".package-lock.json": { + "lockfileVersion": 2 + } + } + }, + "config": { + "lockfileVersion": 1 + }, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-existing-downgrade", + "lockfileVersion": 1, + "requires": true + }, + "logs": [ + "created a lockfile as npm-shrinkwrap.json with version 1" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile existing upgrade > must match snapshot 1`] = ` +{ + "localPrefix": { + "node_modules": { + ".package-lock.json": { + "lockfileVersion": 2 + } + } + }, + "config": { + "lockfileVersion": 3 + }, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-hidden-lockfile-existing-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": {} + }, + "logs": [ + "created a lockfile as npm-shrinkwrap.json with version 3" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with nothing ancient > must match snapshot 1`] = ` +{ + "localPrefix": {}, + "config": {}, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-nothing-ancient", + "lockfileVersion": 2, + "requires": true, + "packages": {} + }, + "logs": [ + "created a lockfile as npm-shrinkwrap.json with version 2" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with nothing ancient upgrade > must match snapshot 1`] = ` +{ + "localPrefix": {}, + "config": { + "lockfileVersion": 3 + }, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-nothing-ancient-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": {} + }, + "logs": [ + "created a lockfile as npm-shrinkwrap.json with version 3" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json ancient > must match snapshot 1`] = ` +{ + "localPrefix": { + "npm-shrinkwrap.json": { + "lockfileVersion": 1 + } + }, + "config": {}, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-ancient", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-ancient" + } + } + }, + "logs": [ + "npm-shrinkwrap.json updated to version 2" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json ancient upgrade > must match snapshot 1`] = ` +{ + "localPrefix": { + "npm-shrinkwrap.json": { + "lockfileVersion": 1 + } + }, + "config": { + "lockfileVersion": 3 + }, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-ancient-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-ancient-upgrade" + } + } + }, + "logs": [ + "npm-shrinkwrap.json updated to version 3" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json existing > must match snapshot 1`] = ` +{ + "localPrefix": { + "npm-shrinkwrap.json": { + "lockfileVersion": 2 + } + }, + "config": {}, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing" + } + } + }, + "logs": [ + "npm-shrinkwrap.json up to date" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json existing downgrade > must match snapshot 1`] = ` +{ + "localPrefix": { + "npm-shrinkwrap.json": { + "lockfileVersion": 2 + } + }, + "config": { + "lockfileVersion": 1 + }, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing-downgrade", + "lockfileVersion": 1, + "requires": true + }, + "logs": [ + "npm-shrinkwrap.json updated to version 1" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json existing upgrade > must match snapshot 1`] = ` +{ + "localPrefix": { + "npm-shrinkwrap.json": { + "lockfileVersion": 2 + } + }, + "config": { + "lockfileVersion": 3 + }, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-npm-shrinkwrap.json-existing-upgrade" + } + } + }, + "logs": [ + "npm-shrinkwrap.json updated to version 3" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json ancient > must match snapshot 1`] = ` +{ + "localPrefix": { + "package-lock.json": { + "lockfileVersion": 1 + } + }, + "config": {}, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-ancient", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-ancient" + } + } + }, + "logs": [ + "package-lock.json has been renamed to npm-shrinkwrap.json and updated to version 2" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json ancient upgrade > must match snapshot 1`] = ` +{ + "localPrefix": { + "package-lock.json": { + "lockfileVersion": 1 + } + }, + "config": { + "lockfileVersion": 3 + }, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-ancient-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-ancient-upgrade" + } + } + }, + "logs": [ + "package-lock.json has been renamed to npm-shrinkwrap.json and updated to version 3" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json existing > must match snapshot 1`] = ` +{ + "localPrefix": { + "package-lock.json": { + "lockfileVersion": 2 + } + }, + "config": {}, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing" + } + } + }, + "logs": [ + "package-lock.json has been renamed to npm-shrinkwrap.json" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json existing downgrade > must match snapshot 1`] = ` +{ + "localPrefix": { + "package-lock.json": { + "lockfileVersion": 2 + } + }, + "config": { + "lockfileVersion": 1 + }, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing-downgrade", + "lockfileVersion": 1, + "requires": true + }, + "logs": [ + "package-lock.json has been renamed to npm-shrinkwrap.json and updated to version 1" + ] +} +` + +exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json existing upgrade > must match snapshot 1`] = ` +{ + "localPrefix": { + "package-lock.json": { + "lockfileVersion": 2 + } + }, + "config": { + "lockfileVersion": 3 + }, + "shrinkwrap": { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing-upgrade", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tap-testdir-shrinkwrap-with-package-lock.json-existing-upgrade" + } + } + }, + "logs": [ + "package-lock.json has been renamed to npm-shrinkwrap.json and updated to version 3" + ] +} +` diff --git a/deps/npm/tap-snapshots/test/lib/stars.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/stars.js.test.cjs similarity index 78% rename from deps/npm/tap-snapshots/test/lib/stars.js.test.cjs rename to deps/npm/tap-snapshots/test/lib/commands/stars.js.test.cjs index ac628148fd7061..fbf074f718d1d9 100644 --- a/deps/npm/tap-snapshots/test/lib/stars.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/stars.js.test.cjs @@ -5,7 +5,7 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/stars.js TAP no args > should output a list of starred packages 1`] = ` +exports[`test/lib/commands/stars.js TAP no args > should output a list of starred packages 1`] = ` @npmcli/arborist @npmcli/map-workspaces diff --git a/deps/npm/tap-snapshots/test/lib/commands/team.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/team.js.test.cjs new file mode 100644 index 00000000000000..6a93234f54fc84 --- /dev/null +++ b/deps/npm/tap-snapshots/test/lib/commands/team.js.test.cjs @@ -0,0 +1,85 @@ +/* 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/commands/team.js TAP team add --parseable > should output success result for parseable add user 1`] = ` +foo npmcli:developers added +` + +exports[`test/lib/commands/team.js TAP team add default output > should output success result for add user 1`] = ` +foo added to @npmcli:developers +` + +exports[`test/lib/commands/team.js TAP team create --parseable > should output parseable success result for create team 1`] = ` +npmcli:newteam created +` + +exports[`test/lib/commands/team.js TAP team create default output > should output success result for create team 1`] = ` ++@npmcli:newteam +` + +exports[`test/lib/commands/team.js TAP team destroy --parseable > should output parseable result for destroy team 1`] = ` +npmcli:newteam deleted +` + +exports[`test/lib/commands/team.js TAP team destroy default output > should output success result for destroy team 1`] = ` +-@npmcli:newteam +` + +exports[`test/lib/commands/team.js TAP team ls --parseable > should list users for a parseable scope:team 1`] = ` +darcyclarke +isaacs +nlf +ruyadorno +` + +exports[`test/lib/commands/team.js TAP team ls default output > should list users for a given scope:team 1`] = ` + +@npmcli:developers has 4 users: +darcyclarke isaacs nlf ruyadorno +` + +exports[`test/lib/commands/team.js TAP team ls no users > should list no users for a given scope 1`] = ` + +@npmcli:developers has 0 users +` + +exports[`test/lib/commands/team.js TAP team ls single user > should list single user for a given scope 1`] = ` + +@npmcli:developers has 1 user: +foo +` + +exports[`test/lib/commands/team.js TAP team ls --parseable > should list teams for a parseable scope 1`] = ` +npmcli:designers +npmcli:developers +npmcli:product +` + +exports[`test/lib/commands/team.js TAP team ls default output > should list teams for a given scope 1`] = ` + +@npmcli has 3 teams: +@npmcli:designers @npmcli:developers @npmcli:product +` + +exports[`test/lib/commands/team.js TAP team ls no teams > should list no teams for a given scope 1`] = ` + +@npmcli has 0 teams +` + +exports[`test/lib/commands/team.js TAP team ls single team > should list single team for a given scope 1`] = ` + +@npmcli has 1 team: +@npmcli:developers +` + +exports[`test/lib/commands/team.js TAP team rm --parseable > should output parseable result for remove user 1`] = ` +foo npmcli:newteam removed +` + +exports[`test/lib/commands/team.js TAP team rm default output > should output success result for remove user 1`] = ` +foo removed from @npmcli:newteam +` diff --git a/deps/npm/tap-snapshots/test/lib/unpublish.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/unpublish.js.test.cjs similarity index 59% rename from deps/npm/tap-snapshots/test/lib/unpublish.js.test.cjs rename to deps/npm/tap-snapshots/test/lib/commands/unpublish.js.test.cjs index 5936bec6c759fe..d84f26f299868f 100644 --- a/deps/npm/tap-snapshots/test/lib/unpublish.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/unpublish.js.test.cjs @@ -5,10 +5,10 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/unpublish.js TAP workspaces all workspaces --force > should output all workspaces 1`] = ` +exports[`test/lib/commands/unpublish.js TAP workspaces all workspaces --force > should output all workspaces 1`] = ` - workspace-a- workspace-b- workspace-n ` -exports[`test/lib/unpublish.js TAP workspaces one workspace --force > should output one workspaces 1`] = ` +exports[`test/lib/commands/unpublish.js TAP workspaces one workspace --force > should output one workspaces 1`] = ` - workspace-a ` diff --git a/deps/npm/tap-snapshots/test/lib/view.js.test.cjs b/deps/npm/tap-snapshots/test/lib/commands/view.js.test.cjs similarity index 73% rename from deps/npm/tap-snapshots/test/lib/view.js.test.cjs rename to deps/npm/tap-snapshots/test/lib/commands/view.js.test.cjs index 9ed8334138cf85..10d38cb3f8c061 100644 --- a/deps/npm/tap-snapshots/test/lib/view.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/commands/view.js.test.cjs @@ -5,18 +5,18 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/view.js TAP should log info by field name array field - 1 element > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log info by field name array field - 1 element > must match snapshot 1`] = ` claudia ` -exports[`test/lib/view.js TAP should log info by field name array field - 2 elements > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log info by field name array field - 2 elements > must match snapshot 1`] = ` maintainers[0].name = 'claudia' maintainers[1].name = 'isaacs' ` -exports[`test/lib/view.js TAP should log info by field name maintainers with email > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log info by field name maintainers with email > must match snapshot 1`] = ` { "maintainers": [ @@ -35,7 +35,7 @@ exports[`test/lib/view.js TAP should log info by field name maintainers with ema } ` -exports[`test/lib/view.js TAP should log info by field name maintainers with url > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log info by field name maintainers with url > must match snapshot 1`] = ` [ "claudia (http://c.pink.com)", @@ -43,17 +43,17 @@ exports[`test/lib/view.js TAP should log info by field name maintainers with url ] ` -exports[`test/lib/view.js TAP should log info by field name nested field with brackets > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log info by field name nested field with brackets > must match snapshot 1`] = ` "123" ` -exports[`test/lib/view.js TAP should log info by field name readme > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log info by field name readme > must match snapshot 1`] = ` a very useful readme ` -exports[`test/lib/view.js TAP should log info by field name several fields > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log info by field name several fields > must match snapshot 1`] = ` { "name": "yellow", @@ -61,14 +61,14 @@ exports[`test/lib/view.js TAP should log info by field name several fields > mus } ` -exports[`test/lib/view.js TAP should log info by field name several fields with several versions > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log info by field name several fields with several versions > must match snapshot 1`] = ` yellow@1.0.0 'claudia' yellow@1.0.1 'claudia' yellow@1.0.2 'claudia' ` -exports[`test/lib/view.js TAP should log info of package in current working dir non-specific version > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log info of package in current working dir non-specific version > must match snapshot 1`] = ` blue@1.0.0 | Proprietary | deps: none | versions: 2 @@ -85,7 +85,7 @@ dist-tags: published yesterday ` -exports[`test/lib/view.js TAP should log info of package in current working dir specific version > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log info of package in current working dir specific version > must match snapshot 1`] = ` blue@1.0.0 | Proprietary | deps: none | versions: 2 @@ -102,7 +102,7 @@ dist-tags: published yesterday ` -exports[`test/lib/view.js TAP should log package info package from git > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log package info package from git > must match snapshot 1`] = ` green@1.0.0 | ACME | deps: 2 | versions: 2 @@ -132,7 +132,7 @@ dist-tags: latest: 1.0.0 ` -exports[`test/lib/view.js TAP should log package info package with --json and semver range > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log package info package with --json and semver range > must match snapshot 1`] = ` [ { @@ -168,7 +168,7 @@ exports[`test/lib/view.js TAP should log package info package with --json and se ] ` -exports[`test/lib/view.js TAP should log package info package with homepage > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log package info package with homepage > must match snapshot 1`] = ` orange@1.0.0 | Proprietary | deps: none | versions: 2 @@ -184,7 +184,7 @@ dist-tags: latest: 1.0.0 ` -exports[`test/lib/view.js TAP should log package info package with license, bugs, repository and other fields > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log package info package with license, bugs, repository and other fields > must match snapshot 1`] = ` green@1.0.0 | ACME | deps: 2 | versions: 2 @@ -214,7 +214,7 @@ dist-tags: latest: 1.0.0 ` -exports[`test/lib/view.js TAP should log package info package with maintainers info as object > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log package info package with maintainers info as object > must match snapshot 1`] = ` pink@1.0.0 | Proprietary | deps: none | versions: 2 @@ -229,7 +229,7 @@ dist-tags: latest: 1.0.0 ` -exports[`test/lib/view.js TAP should log package info package with more than 25 deps > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log package info package with more than 25 deps > must match snapshot 1`] = ` black@1.0.0 | Proprietary | deps: 25 | versions: 2 @@ -271,7 +271,7 @@ dist-tags: latest: 1.0.0 ` -exports[`test/lib/view.js TAP should log package info package with no modified time > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log package info package with no modified time > must match snapshot 1`] = ` cyan@1.0.0 | Proprietary | deps: none | versions: 2 @@ -288,7 +288,7 @@ dist-tags: published by claudia <claudia@cyan.com> ` -exports[`test/lib/view.js TAP should log package info package with no repo or homepage > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log package info package with no repo or homepage > must match snapshot 1`] = ` blue@1.0.0 | Proprietary | deps: none | versions: 2 @@ -305,7 +305,7 @@ dist-tags: published yesterday ` -exports[`test/lib/view.js TAP should log package info package with semver range > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP should log package info package with semver range > must match snapshot 1`] = ` blue@1.0.0 | Proprietary | deps: none | versions: 2 @@ -320,9 +320,22 @@ dist-tags: latest: 1.0.0 published yesterday + +blue@1.0.1 | Proprietary | deps: none | versions: 2 + +dist +.tarball:http://hm.blue.com/1.0.1.tgz +.shasum:124 +.integrity:--- +.unpackedSize:1 B + +dist-tags: +latest: 1.0.0 + +published over a year from now ` -exports[`test/lib/view.js TAP workspaces all workspaces --json > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP workspaces all workspaces --json > must match snapshot 1`] = ` { "green": { @@ -402,7 +415,7 @@ exports[`test/lib/view.js TAP workspaces all workspaces --json > must match snap } ` -exports[`test/lib/view.js TAP workspaces all workspaces > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP workspaces all workspaces > must match snapshot 1`] = ` green@1.0.0 | ACME | deps: 2 | versions: 2 @@ -444,17 +457,17 @@ dist-tags: latest: 1.0.0 ` -exports[`test/lib/view.js TAP workspaces all workspaces nonexistent field --json > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP workspaces all workspaces nonexistent field --json > must match snapshot 1`] = ` ` -exports[`test/lib/view.js TAP workspaces all workspaces nonexistent field > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP workspaces all workspaces nonexistent field > must match snapshot 1`] = ` green: orange: ` -exports[`test/lib/view.js TAP workspaces all workspaces single field --json > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP workspaces all workspaces single field --json > must match snapshot 1`] = ` { "green": "green", @@ -462,7 +475,7 @@ exports[`test/lib/view.js TAP workspaces all workspaces single field --json > mu } ` -exports[`test/lib/view.js TAP workspaces all workspaces single field > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP workspaces all workspaces single field > must match snapshot 1`] = ` green: green @@ -470,7 +483,7 @@ orange: orange ` -exports[`test/lib/view.js TAP workspaces one specific workspace > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP workspaces one specific workspace > must match snapshot 1`] = ` green@1.0.0 | ACME | deps: 2 | versions: 2 @@ -500,11 +513,11 @@ dist-tags: latest: 1.0.0 ` -exports[`test/lib/view.js TAP workspaces remote package name > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP workspaces remote package name > must match snapshot 1`] = ` Ignoring workspaces for specified package(s) ` -exports[`test/lib/view.js TAP workspaces remote package name > must match snapshot 2`] = ` +exports[`test/lib/commands/view.js TAP workspaces remote package name > must match snapshot 2`] = ` pink@1.0.0 | Proprietary | deps: none | versions: 2 @@ -519,7 +532,7 @@ dist-tags: latest: 1.0.0 ` -exports[`test/lib/view.js TAP workspaces single workspace --json > must match snapshot 1`] = ` +exports[`test/lib/commands/view.js TAP workspaces single workspace --json > must match snapshot 1`] = ` { "green": { diff --git a/deps/npm/tap-snapshots/test/lib/link.js.test.cjs b/deps/npm/tap-snapshots/test/lib/link.js.test.cjs deleted file mode 100644 index 0e20bcd994e3ab..00000000000000 --- a/deps/npm/tap-snapshots/test/lib/link.js.test.cjs +++ /dev/null @@ -1,45 +0,0 @@ -/* 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/link.js TAP link global linked pkg to local nm when using args > should create a local symlink to global pkg 1`] = ` -{CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/@myscope/bar -> {CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/global-prefix/lib/node_modules/@myscope/bar -{CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/@myscope/linked -> {CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/scoped-linked -{CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/a -> {CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/global-prefix/lib/node_modules/a -{CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/link-me-too -> {CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/link-me-too -{CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/my-project/node_modules/test-pkg-link -> {CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-nm-when-using-args/test-pkg-link - -` - -exports[`test/lib/link.js TAP link global linked pkg to local workspace using args > should create a local symlink to global pkg 1`] = ` -{CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/@myscope/bar -> {CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/global-prefix/lib/node_modules/@myscope/bar -{CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/@myscope/linked -> {CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/scoped-linked -{CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/a -> {CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/global-prefix/lib/node_modules/a -{CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/link-me-too -> {CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/link-me-too -{CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/test-pkg-link -> {CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/test-pkg-link -{CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/node_modules/x -> {CWD}/test/lib/tap-testdir-link-link-global-linked-pkg-to-local-workspace-using-args/my-project/packages/x - -` - -exports[`test/lib/link.js TAP link pkg already in global space > should create a local symlink to global pkg 1`] = ` -{CWD}/test/lib/tap-testdir-link-link-pkg-already-in-global-space/my-project/node_modules/@myscope/linked -> {CWD}/test/lib/tap-testdir-link-link-pkg-already-in-global-space/scoped-linked - -` - -exports[`test/lib/link.js TAP link pkg already in global space when prefix is a symlink > should create a local symlink to global pkg 1`] = ` -{CWD}/test/lib/tap-testdir-link-link-pkg-already-in-global-space-when-prefix-is-a-symlink/my-project/node_modules/@myscope/linked -> {CWD}/test/lib/tap-testdir-link-link-pkg-already-in-global-space-when-prefix-is-a-symlink/scoped-linked - -` - -exports[`test/lib/link.js TAP link to globalDir when in current working dir of pkg and no args > should create a global link to current pkg 1`] = ` -{CWD}/test/lib/tap-testdir-link-link-to-globalDir-when-in-current-working-dir-of-pkg-and-no-args/global-prefix/lib/node_modules/test-pkg-link -> {CWD}/test/lib/tap-testdir-link-link-to-globalDir-when-in-current-working-dir-of-pkg-and-no-args/test-pkg-link - -` - -exports[`test/lib/link.js TAP link ws to globalDir when workspace specified and no args > should create a global link to current pkg 1`] = ` -{CWD}/test/lib/tap-testdir-link-link-ws-to-globalDir-when-workspace-specified-and-no-args/global-prefix/lib/node_modules/a -> {CWD}/test/lib/tap-testdir-link-link-ws-to-globalDir-when-workspace-specified-and-no-args/test-pkg-link/packages/a - -` diff --git a/deps/npm/tap-snapshots/test/lib/team.js.test.cjs b/deps/npm/tap-snapshots/test/lib/team.js.test.cjs deleted file mode 100644 index 73123ee1af7f69..00000000000000 --- a/deps/npm/tap-snapshots/test/lib/team.js.test.cjs +++ /dev/null @@ -1,85 +0,0 @@ -/* 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/team.js TAP team add --parseable > should output success result for parseable add user 1`] = ` -foo npmcli:developers added -` - -exports[`test/lib/team.js TAP team add default output > should output success result for add user 1`] = ` -foo added to @npmcli:developers -` - -exports[`test/lib/team.js TAP team create --parseable > should output parseable success result for create team 1`] = ` -npmcli:newteam created -` - -exports[`test/lib/team.js TAP team create default output > should output success result for create team 1`] = ` -+@npmcli:newteam -` - -exports[`test/lib/team.js TAP team destroy --parseable > should output parseable result for destroy team 1`] = ` -npmcli:newteam deleted -` - -exports[`test/lib/team.js TAP team destroy default output > should output success result for destroy team 1`] = ` --@npmcli:newteam -` - -exports[`test/lib/team.js TAP team ls --parseable > should list users for a parseable scope:team 1`] = ` -darcyclarke -isaacs -nlf -ruyadorno -` - -exports[`test/lib/team.js TAP team ls default output > should list users for a given scope:team 1`] = ` - -@npmcli:developers has 4 users: -darcyclarke isaacs nlf ruyadorno -` - -exports[`test/lib/team.js TAP team ls no users > should list no users for a given scope 1`] = ` - -@npmcli:developers has 0 users -` - -exports[`test/lib/team.js TAP team ls single user > should list single user for a given scope 1`] = ` - -@npmcli:developers has 1 user: -foo -` - -exports[`test/lib/team.js TAP team ls --parseable > should list teams for a parseable scope 1`] = ` -npmcli:designers -npmcli:developers -npmcli:product -` - -exports[`test/lib/team.js TAP team ls default output > should list teams for a given scope 1`] = ` - -@npmcli has 3 teams: -@npmcli:designers @npmcli:developers @npmcli:product -` - -exports[`test/lib/team.js TAP team ls no teams > should list no teams for a given scope 1`] = ` - -@npmcli has 0 teams -` - -exports[`test/lib/team.js TAP team ls single team > should list single team for a given scope 1`] = ` - -@npmcli has 1 team: -@npmcli:developers -` - -exports[`test/lib/team.js TAP team rm --parseable > should output parseable result for remove user 1`] = ` -foo npmcli:newteam removed -` - -exports[`test/lib/team.js TAP team rm default output > should output success result for remove user 1`] = ` -foo removed from @npmcli:newteam -` diff --git a/deps/npm/tap-snapshots/test/lib/utils/error-message.js.test.cjs b/deps/npm/tap-snapshots/test/lib/utils/error-message.js.test.cjs index c963ca2040e6f5..f035285d7031a7 100644 --- a/deps/npm/tap-snapshots/test/lib/utils/error-message.js.test.cjs +++ b/deps/npm/tap-snapshots/test/lib/utils/error-message.js.test.cjs @@ -214,7 +214,7 @@ Object { } ` -exports[`test/lib/utils/error-message.js TAP bad engine with config loaded > must match snapshot 1`] = ` +exports[`test/lib/utils/error-message.js TAP bad engine without config loaded > must match snapshot 1`] = ` Object { "detail": Array [ Array [ @@ -222,7 +222,7 @@ Object { String( Not compatible with your version of node/npm: some@package Required: undefined - Actual: {"npm":"123.69.420-npm","node":"99.99.99"} + Actual: {"npm":"123.456.789-npm","node":"123.456.789-node"} ), ], ], @@ -246,7 +246,7 @@ Object { "notsup", String( Valid OS: !yours,mine - Valid Arch: x420,x69 + Valid Arch: x867,x5309 Actual OS: posix Actual Arch: x64 ), @@ -255,7 +255,7 @@ Object { "summary": Array [ Array [ "notsup", - "Unsupported platform for lodash@1.0.0: wanted {\\"os\\":\\"!yours,mine\\",\\"arch\\":\\"x420,x69\\"} (current: {\\"os\\":\\"posix\\",\\"arch\\":\\"x64\\"})", + "Unsupported platform for lodash@1.0.0: wanted {\\"os\\":\\"!yours,mine\\",\\"arch\\":\\"x867,x5309\\"} (current: {\\"os\\":\\"posix\\",\\"arch\\":\\"x64\\"})", ], ], } @@ -517,7 +517,7 @@ Object { previous versions of npm which has since been addressed. To permanently fix this problem, please run: - sudo chown -R 69:420 "/some/cache/dir" + sudo chown -R 867:5309 "/some/cache/dir" ), ], ], @@ -544,7 +544,7 @@ Object { previous versions of npm which has since been addressed. To permanently fix this problem, please run: - sudo chown -R 69:420 "/some/cache/dir" + sudo chown -R 867:5309 "/some/cache/dir" ), ], ], @@ -571,7 +571,7 @@ Object { previous versions of npm which has since been addressed. To permanently fix this problem, please run: - sudo chown -R 69:420 "/some/cache/dir" + sudo chown -R 867:5309 "/some/cache/dir" ), ], ], @@ -1145,7 +1145,7 @@ Object { String( Not compatible with your version of node/npm: some@package Required: undefined - Actual: {"npm":"123.69.420-npm","node":"123.69.420-node"} + Actual: {"npm":"123.456.789-npm","node":"99.99.99"} ), ], ], diff --git a/deps/npm/test/fixtures/mock-npm.js b/deps/npm/test/fixtures/mock-npm.js index 3faf8d5cf4f6be..0a7bc0e8ad8f00 100644 --- a/deps/npm/test/fixtures/mock-npm.js +++ b/deps/npm/test/fixtures/mock-npm.js @@ -2,19 +2,56 @@ const npmlog = require('npmlog') const procLog = require('../../lib/utils/proc-log-listener.js') procLog.reset() +// In theory we shouldn't have to do this if all the tests were tearing down +// their listeners properly, we're still getting warnings even though +// perfStop() and procLog.reset() is in the teardown script. This silences the +// warnings for now +require('events').defaultMaxListeners = Infinity + const realLog = {} for (const level in npmlog.levels) realLog[level] = npmlog[level] const { title, execPath } = process +// Eventually this should default to having a prefix of an empty testdir, and +// awaiting npm.load() unless told not to (for npm tests for example). Ideally +// the prefix of an empty dir is inferred rather than explicitly set const RealMockNpm = (t, otherMocks = {}) => { + const mock = {} + mock.logs = [] + mock.outputs = [] + mock.joinedOutput = () => { + return mock.outputs.map(o => o.join(' ')).join('\n') + } + const Npm = t.mock('../../lib/npm.js', otherMocks) + class MockNpm extends Npm { + constructor () { + super() + for (const level in npmlog.levels) { + npmlog[level] = (...msg) => { + mock.logs.push([level, ...msg]) + + const l = npmlog.level + npmlog.level = 'silent' + realLog[level](...msg) + npmlog.level = l + } + } + // npm.js tests need this restored to actually test this function! + mock.npmOutput = this.output + this.output = (...msg) => mock.outputs.push(msg) + } + } + mock.Npm = MockNpm t.afterEach(() => { - outputs.length = 0 - logs.length = 0 + mock.outputs.length = 0 + mock.logs.length = 0 }) + t.teardown(() => { - npm.perfStop() + process.removeAllListeners('time') + process.removeAllListeners('timeEnd') npmlog.record.length = 0 for (const level in npmlog.levels) npmlog[level] = realLog[level] @@ -24,33 +61,8 @@ const RealMockNpm = (t, otherMocks = {}) => { delete process.env.npm_command delete process.env.COLOR }) - const logs = [] - const outputs = [] - const joinedOutput = () => { - return outputs.map(o => o.join(' ')).join('\n') - } - const npm = t.mock('../../lib/npm.js', otherMocks) - const command = async (command, args = []) => { - return new Promise((resolve, reject) => { - npm.commands[command](args, err => { - if (err) - return reject(err) - return resolve() - }) - }) - } - for (const level in npmlog.levels) { - npmlog[level] = (...msg) => { - logs.push([level, ...msg]) - const l = npmlog.level - npmlog.level = 'silent' - realLog[level](...msg) - npmlog.level = l - } - } - npm.output = (...msg) => outputs.push(msg) - return { npm, logs, outputs, command, joinedOutput } + return mock } const realConfig = require('../../lib/utils/config') @@ -67,9 +79,8 @@ class MockNpm { const config = base.config || {} for (const attr in base) { - if (attr !== 'config') { + if (attr !== 'config') this[attr] = base[attr] - } } this.flatOptions = base.flatOptions || {} @@ -79,7 +90,7 @@ class MockNpm { find: (k) => ({...realConfig.defaults, ...config})[k], get: (k) => ({...realConfig.defaults, ...config})[k], set: (k, v) => config[k] = v, - list: [{ ...realConfig.defaults, ...config}] + list: [{ ...realConfig.defaults, ...config}], } if (!this.log) { this.log = { @@ -98,7 +109,7 @@ class MockNpm { } } - output(...msg) { + output (...msg) { if (this.base.output) return this.base.output(msg) this._mockOutputs.push(msg) @@ -106,10 +117,10 @@ class MockNpm { } const FakeMockNpm = (base = {}) => { - return new MockNpm(base) + return new MockNpm(base) } module.exports = { fake: FakeMockNpm, - real: RealMockNpm + real: RealMockNpm, } diff --git a/deps/npm/test/fixtures/sandbox.js b/deps/npm/test/fixtures/sandbox.js index 4cdd9b70dbc6f9..626e2ab5c509ca 100644 --- a/deps/npm/test/fixtures/sandbox.js +++ b/deps/npm/test/fixtures/sandbox.js @@ -6,16 +6,17 @@ const { promisify } = require('util') const mkdirp = require('mkdirp-infer-owner') const npmlog = require('npmlog') const rimraf = promisify(require('rimraf')) -const t = require('tap') -let active = null const chain = new Map() const sandboxes = new Map() +// Disable lint errors for assigning to process global +/* global process:writable */ + // keep a reference to the real process const _process = process -const processHook = createHook({ +createHook({ init: (asyncId, type, triggerAsyncId, resource) => { // track parentage of asyncIds chain.set(asyncId, triggerAsyncId) @@ -23,9 +24,8 @@ const processHook = createHook({ before: (asyncId) => { // find the nearest parent id that has a sandbox let parent = asyncId - while (chain.has(parent) && !sandboxes.has(parent)) { + while (chain.has(parent) && !sandboxes.has(parent)) parent = chain.get(parent) - } process = sandboxes.has(parent) ? sandboxes.get(parent) @@ -173,7 +173,7 @@ class Sandbox extends EventEmitter { if (this[_npm]) { // replace default config values with placeholders for (const name of redactedDefaults) { - let value = this[_npm].config.defaults[name] + const value = this[_npm].config.defaults[name] clean = clean.split(value).join(`{${name.toUpperCase()}}`) } @@ -201,21 +201,19 @@ class Sandbox extends EventEmitter { // test.teardown hook teardown () { - if (this[_parent]) { + if (this[_parent]) sandboxes.delete(this[_parent]) - } + return rimraf(this[_dirs].temp).catch(() => null) } // proxy get handler [_get] (target, prop, receiver) { - if (this[_data].has(prop)) { + if (this[_data].has(prop)) return this[_data].get(prop) - } - if (this[prop] !== undefined) { + if (this[prop] !== undefined) return Reflect.get(this, prop, this) - } const actual = Reflect.get(target, prop, receiver) if (typeof actual === 'function') { @@ -277,7 +275,8 @@ class Sandbox extends EventEmitter { ...argv, ] - this[_npm] = this[_test].mock('../../lib/npm.js', this[_mocks]) + const Npm = this[_test].mock('../../lib/npm.js', this[_mocks]) + this[_npm] = new Npm() this[_npm].output = (...args) => this[_output].push(args) await this[_npm].load() // in some node versions (later 10.x) our executionAsyncId at this point @@ -290,20 +289,7 @@ class Sandbox extends EventEmitter { } const cmd = this[_npm].argv.shift() - const impl = this[_npm].commands[cmd] - if (!impl) { - throw new Error(`Unknown command: ${cmd}`) - } - - return new Promise((resolve, reject) => { - impl(this[_npm].argv, (err) => { - if (err) { - return reject(err) - } - - return resolve() - }) - }) + return this[_npm].exec(cmd, this[_npm].argv) } async complete (command, argv, partial) { @@ -335,7 +321,8 @@ class Sandbox extends EventEmitter { ...argv, ] - this[_npm] = this[_test].mock('../../lib/npm.js', this[_mocks]) + const Npm = this[_test].mock('../../lib/npm.js', this[_mocks]) + this[_npm] = new Npm() this[_npm].output = (...args) => this[_output].push(args) await this[_npm].load() // in some node versions (later 10.x) our executionAsyncId at this point @@ -347,11 +334,7 @@ class Sandbox extends EventEmitter { process = this[_proxy] } - const impl = this[_npm].commands[command] - if (!impl) { - throw new Error(`Unknown command: ${cmd}`) - } - + const impl = await this[_npm].cmd(command) return impl.completion({ partialWord: partial, conf: { diff --git a/deps/npm/test/index.js b/deps/npm/test/index.js index 9f97709acf84ce..26db16e1f78baf 100644 --- a/deps/npm/test/index.js +++ b/deps/npm/test/index.js @@ -8,7 +8,7 @@ t.throws(() => require(index), { t.test('loading as main module will load the cli', t => { const { spawn } = require('child_process') - const LS = require('../lib/ls.js') + const LS = require('../lib/commands/ls.js') const ls = new LS({}) const p = spawn(process.execPath, [index, 'ls', '-h']) const out = [] diff --git a/deps/npm/test/lib/access.js b/deps/npm/test/lib/access.js deleted file mode 100644 index 5fd170bab484aa..00000000000000 --- a/deps/npm/test/lib/access.js +++ /dev/null @@ -1,535 +0,0 @@ -const t = require('tap') - -const Access = require('../../lib/access.js') - -const npm = { - output: () => null, -} - -t.test('completion', t => { - const access = new Access({ flatOptions: {} }) - const testComp = (argv, expect) => { - const res = access.completion({conf: {argv: {remain: argv}}}) - t.resolves(res, expect, argv.join(' ')) - } - - testComp(['npm', 'access'], [ - 'public', 'restricted', 'grant', 'revoke', 'ls-packages', - 'ls-collaborators', 'edit', '2fa-required', '2fa-not-required', - ]) - testComp(['npm', 'access', 'grant'], ['read-only', 'read-write']) - testComp(['npm', 'access', 'grant', 'read-only'], []) - testComp(['npm', 'access', 'public'], []) - testComp(['npm', 'access', 'restricted'], []) - testComp(['npm', 'access', 'revoke'], []) - testComp(['npm', 'access', 'ls-packages'], []) - testComp(['npm', 'access', 'ls-collaborators'], []) - testComp(['npm', 'access', 'edit'], []) - testComp(['npm', 'access', '2fa-required'], []) - testComp(['npm', 'access', '2fa-not-required'], []) - testComp(['npm', 'access', 'revoke'], []) - - t.rejects( - access.completion({conf: {argv: {remain: ['npm', 'access', 'foobar']}}}), - { message: 'foobar not recognized' } - ) - - t.end() -}) - -t.test('subcommand required', t => { - const access = new Access({ flatOptions: {} }) - access.exec([], (err) => { - t.match(err, access.usageError('Subcommand is required.')) - t.end() - }) -}) - -t.test('unrecognized subcommand', (t) => { - const access = new Access({ flatOptions: {} }) - access.exec(['blerg'], (err) => { - t.match( - err, - /Usage: blerg is not a recognized subcommand/, - 'should throw EUSAGE on missing subcommand' - ) - t.end() - }) -}) - -t.test('edit', (t) => { - const access = new Access({ flatOptions: {} }) - access.exec([ - 'edit', - '@scoped/another', - ], (err) => { - t.match( - err, - /edit subcommand is not implemented yet/, - 'should throw not implemented yet error' - ) - t.end() - }) -}) - -t.test('access public on unscoped package', (t) => { - const prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'npm-access-public-pkg', - }), - }) - const access = new Access({ prefix }) - access.exec([ - 'public', - ], (err) => { - t.match( - err, - /Usage: This command is only available for scoped packages/, - 'should throw scoped-restricted error' - ) - t.end() - }) -}) - -t.test('access public on scoped package', (t) => { - t.plan(4) - const name = '@scoped/npm-access-public-pkg' - const prefix = t.testdir({ - 'package.json': JSON.stringify({ name }), - }) - const Access = t.mock('../../lib/access.js', { - libnpmaccess: { - public: (pkg, { registry }) => { - t.equal(pkg, name, 'should use pkg name ref') - t.equal( - registry, - 'https://registry.npmjs.org', - 'should forward correct options' - ) - return true - }, - }, - }) - const access = new Access({ - flatOptions: { registry: 'https://registry.npmjs.org' }, - prefix, - }) - access.exec([ - 'public', - ], (err) => { - t.error(err, 'npm access') - t.ok('should successfully access public on scoped package') - }) -}) - -t.test('access public on missing package.json', (t) => { - const prefix = t.testdir({ - node_modules: {}, - }) - const access = new Access({ prefix }) - access.exec([ - 'public', - ], (err) => { - t.match( - err, - /no package name passed to command and no package.json found/, - 'should throw no package.json found error' - ) - t.end() - }) -}) - -t.test('access public on invalid package.json', (t) => { - const prefix = t.testdir({ - 'package.json': '{\n', - node_modules: {}, - }) - const access = new Access({ prefix }) - access.exec([ - 'public', - ], (err) => { - t.match( - err, - /JSONParseError/, - 'should throw failed to parse package.json' - ) - t.end() - }) -}) - -t.test('access restricted on unscoped package', (t) => { - const prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'npm-access-restricted-pkg', - }), - }) - const access = new Access({ prefix }) - access.exec([ - 'restricted', - ], (err) => { - t.match( - err, - /Usage: This command is only available for scoped packages/, - 'should throw scoped-restricted error' - ) - t.end() - }) -}) - -t.test('access restricted on scoped package', (t) => { - t.plan(4) - const name = '@scoped/npm-access-restricted-pkg' - const prefix = t.testdir({ - 'package.json': JSON.stringify({ name }), - }) - const Access = t.mock('../../lib/access.js', { - libnpmaccess: { - restricted: (pkg, { registry }) => { - t.equal(pkg, name, 'should use pkg name ref') - t.equal( - registry, - 'https://registry.npmjs.org', - 'should forward correct options' - ) - return true - }, - }, - }) - const access = new Access({ - flatOptions: { registry: 'https://registry.npmjs.org' }, - prefix, - }) - access.exec([ - 'restricted', - ], (err) => { - t.error(err, 'npm access') - t.ok('should successfully access restricted on scoped package') - }) -}) - -t.test('access restricted on missing package.json', (t) => { - const prefix = t.testdir({ - node_modules: {}, - }) - const access = new Access({ prefix }) - access.exec([ - 'restricted', - ], (err) => { - t.match( - err, - /no package name passed to command and no package.json found/, - 'should throw no package.json found error' - ) - t.end() - }) -}) - -t.test('access restricted on invalid package.json', (t) => { - const prefix = t.testdir({ - 'package.json': '{\n', - node_modules: {}, - }) - const access = new Access({ prefix }) - access.exec([ - 'restricted', - ], (err) => { - t.match( - err, - /JSONParseError/, - 'should throw failed to parse package.json' - ) - t.end() - }) -}) - -t.test('access grant read-only', (t) => { - t.plan(5) - const Access = t.mock('../../lib/access.js', { - libnpmaccess: { - grant: (spec, team, permissions) => { - t.equal(spec, '@scoped/another', 'should use expected spec') - t.equal(team, 'myorg:myteam', 'should use expected team') - t.equal(permissions, 'read-only', 'should forward permissions') - return true - }, - }, - }) - const access = new Access({}) - access.exec([ - 'grant', - 'read-only', - 'myorg:myteam', - '@scoped/another', - ], (err) => { - t.error(err, 'npm access') - t.ok('should successfully access grant read-only') - }) -}) - -t.test('access grant read-write', (t) => { - t.plan(5) - const Access = t.mock('../../lib/access.js', { - libnpmaccess: { - grant: (spec, team, permissions) => { - t.equal(spec, '@scoped/another', 'should use expected spec') - t.equal(team, 'myorg:myteam', 'should use expected team') - t.equal(permissions, 'read-write', 'should forward permissions') - return true - }, - }, - }) - const access = new Access({}) - access.exec([ - 'grant', - 'read-write', - 'myorg:myteam', - '@scoped/another', - ], (err) => { - t.error(err, 'npm access') - t.ok('should successfully access grant read-write') - }) -}) - -t.test('access grant current cwd', (t) => { - t.plan(5) - const prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'yargs', - }), - }) - const Access = t.mock('../../lib/access.js', { - libnpmaccess: { - grant: (spec, team, permissions) => { - t.equal(spec, 'yargs', 'should use expected spec') - t.equal(team, 'myorg:myteam', 'should use expected team') - t.equal(permissions, 'read-write', 'should forward permissions') - return true - }, - }, - }) - const access = new Access({ prefix }) - access.exec([ - 'grant', - 'read-write', - 'myorg:myteam', - ], (err) => { - t.error(err, 'npm access') - t.ok('should successfully access grant current cwd') - }) -}) - -t.test('access grant others', (t) => { - const access = new Access({ flatOptions: {} }) - access.exec([ - 'grant', - 'rerere', - 'myorg:myteam', - '@scoped/another', - ], (err) => { - t.match( - err, - /Usage: First argument must be either `read-only` or `read-write`./, - 'should throw unrecognized argument error' - ) - t.end() - }) -}) - -t.test('access grant missing team args', (t) => { - const access = new Access({ flatOptions: {} }) - access.exec([ - 'grant', - 'read-only', - undefined, - '@scoped/another', - ], (err) => { - t.match( - err, - /Usage: `` argument is required./, - 'should throw missing argument error' - ) - t.end() - }) -}) - -t.test('access grant malformed team arg', (t) => { - const access = new Access({ flatOptions: {} }) - access.exec([ - 'grant', - 'read-only', - 'foo', - '@scoped/another', - ], (err) => { - t.match( - err, - /Usage: Second argument used incorrect format.\n/, - 'should throw malformed arg error' - ) - t.end() - }) -}) - -t.test('access 2fa-required/2fa-not-required', t => { - t.plan(2) - const Access = t.mock('../../lib/access.js', { - libnpmaccess: { - tfaRequired: (spec) => { - t.equal(spec, '@scope/pkg', 'should use expected spec') - return true - }, - tfaNotRequired: (spec) => { - t.equal(spec, 'unscoped-pkg', 'should use expected spec') - return true - }, - }, - }) - const access = new Access({}) - - access.exec(['2fa-required', '@scope/pkg'], er => { - if (er) - throw er - }) - - access.exec(['2fa-not-required', 'unscoped-pkg'], er => { - if (er) - throw er - }) -}) - -t.test('access revoke', (t) => { - t.plan(4) - const Access = t.mock('../../lib/access.js', { - libnpmaccess: { - revoke: (spec, team) => { - t.equal(spec, '@scoped/another', 'should use expected spec') - t.equal(team, 'myorg:myteam', 'should use expected team') - return true - }, - }, - }) - const access = new Access({}) - access.exec([ - 'revoke', - 'myorg:myteam', - '@scoped/another', - ], (err) => { - t.error(err, 'npm access') - t.ok('should successfully access revoke') - }) -}) - -t.test('access revoke missing team args', (t) => { - const access = new Access({ flatOptions: {} }) - access.exec([ - 'revoke', - undefined, - '@scoped/another', - ], (err) => { - t.match( - err, - /Usage: `` argument is required./, - 'should throw missing argument error' - ) - t.end() - }) -}) - -t.test('access revoke malformed team arg', (t) => { - const access = new Access({ flatOptions: {} }) - access.exec([ - 'revoke', - 'foo', - '@scoped/another', - ], (err) => { - t.match( - err, - /Usage: First argument used incorrect format.\n/, - 'should throw malformed arg error' - ) - t.end() - }) -}) - -t.test('npm access ls-packages with no team', (t) => { - t.plan(3) - const Access = t.mock('../../lib/access.js', { - libnpmaccess: { - lsPackages: (entity) => { - t.equal(entity, 'foo', 'should use expected entity') - return {} - }, - }, - '../../lib/utils/get-identity.js': () => Promise.resolve('foo'), - }) - const access = new Access(npm) - access.exec([ - 'ls-packages', - ], (err) => { - t.error(err, 'npm access') - t.ok('should successfully access ls-packages with no team') - }) -}) - -t.test('access ls-packages on team', (t) => { - t.plan(3) - const Access = t.mock('../../lib/access.js', { - libnpmaccess: { - lsPackages: (entity) => { - t.equal(entity, 'myorg:myteam', 'should use expected entity') - return {} - }, - }, - }) - const access = new Access(npm) - access.exec([ - 'ls-packages', - 'myorg:myteam', - ], (err) => { - t.error(err, 'npm access') - t.ok('should successfully access ls-packages on team') - }) -}) - -t.test('access ls-collaborators on current', (t) => { - t.plan(3) - const prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'yargs', - }), - }) - const Access = t.mock('../../lib/access.js', { - libnpmaccess: { - lsCollaborators: (spec) => { - t.equal(spec, 'yargs', 'should use expected spec') - return {} - }, - }, - }) - const access = new Access({ prefix, ...npm }) - access.exec([ - 'ls-collaborators', - ], (err) => { - t.error(err, 'npm access') - t.ok('should successfully access ls-collaborators on current') - }) -}) - -t.test('access ls-collaborators on spec', (t) => { - t.plan(3) - const Access = t.mock('../../lib/access.js', { - libnpmaccess: { - lsCollaborators: (spec) => { - t.equal(spec, 'yargs', 'should use expected spec') - return {} - }, - }, - }) - const access = new Access(npm) - access.exec([ - 'ls-collaborators', - 'yargs', - ], (err) => { - t.error(err, 'npm access') - t.ok('should successfully access ls-packages with no team') - }) -}) diff --git a/deps/npm/test/lib/adduser.js b/deps/npm/test/lib/adduser.js deleted file mode 100644 index a66623e6682827..00000000000000 --- a/deps/npm/test/lib/adduser.js +++ /dev/null @@ -1,212 +0,0 @@ -const t = require('tap') -const { getCredentialsByURI, setCredentialsByURI } = - require('@npmcli/config').prototype - -let result = '' - -const _flatOptions = { - authType: 'legacy', - registry: 'https://registry.npmjs.org/', - scope: '', - fromFlatOptions: true, -} - -let failSave = false -let deletedConfig = {} -let registryOutput = '' -let setConfig = {} -const authDummy = (npm, options) => { - if (!options.fromFlatOptions) - throw new Error('did not pass full flatOptions to auth function') - - return Promise.resolve({ - message: 'success', - newCreds: { - username: 'u', - password: 'p', - email: 'u@npmjs.org', - }, - }) -} - -const deleteMock = (key, where) => { - deletedConfig = { - ...deletedConfig, - [key]: where, - } -} -const npm = { - flatOptions: _flatOptions, - config: { - delete: deleteMock, - get (key, where) { - if (!where || where === 'user') - return _flatOptions[key] - }, - getCredentialsByURI, - async save () { - if (failSave) - throw new Error('error saving user config') - }, - set (key, value, where) { - setConfig = { - ...setConfig, - [key]: { - value, - where, - }, - } - }, - setCredentialsByURI, - }, - output: msg => { - result = msg - }, -} - -const AddUser = t.mock('../../lib/adduser.js', { - npmlog: { - disableProgress: () => null, - notice: (_, msg) => { - registryOutput = msg - }, - }, - '../../lib/auth/legacy.js': authDummy, -}) - -const adduser = new AddUser(npm) - -t.test('usage', (t) => { - t.match(adduser.usage, 'adduser', 'usage has command name in it') - t.end() -}) -t.test('simple login', (t) => { - adduser.exec([], (err) => { - t.error(err, 'npm adduser') - - t.equal( - registryOutput, - 'Log in on https://registry.npmjs.org/', - 'should have correct message result' - ) - - t.same( - deletedConfig, - { - _token: 'user', - _password: 'user', - username: 'user', - _auth: 'user', - _authtoken: 'user', - '-authtoken': 'user', - _authToken: 'user', - '//registry.npmjs.org/:-authtoken': 'user', - '//registry.npmjs.org/:_authToken': 'user', - '//registry.npmjs.org/:_authtoken': 'user', - '//registry.npmjs.org/:always-auth': 'user', - '//registry.npmjs.org/:email': 'user', - }, - 'should delete token in user config' - ) - - t.same( - setConfig, - { - '//registry.npmjs.org/:_password': { value: 'cA==', where: 'user' }, - '//registry.npmjs.org/:username': { value: 'u', where: 'user' }, - email: { value: 'u@npmjs.org', where: 'user' }, - }, - 'should set expected user configs' - ) - - t.equal( - result, - 'success', - 'should output auth success msg' - ) - - registryOutput = '' - deletedConfig = {} - setConfig = {} - result = '' - t.end() - }) -}) - -t.test('bad auth type', (t) => { - _flatOptions.authType = 'foo' - - adduser.exec([], (err) => { - t.match( - err, - /Error: no such auth module/, - 'should throw bad auth type error' - ) - - _flatOptions.authType = 'legacy' - deletedConfig = {} - setConfig = {} - result = '' - t.end() - }) -}) - -t.test('scoped login', (t) => { - _flatOptions.scope = '@myscope' - - adduser.exec([], (err) => { - t.error(err, 'npm adduser') - - t.same( - setConfig['@myscope:registry'], - { value: 'https://registry.npmjs.org/', where: 'user' }, - 'should set scoped registry config' - ) - - _flatOptions.scope = '' - deletedConfig = {} - setConfig = {} - result = '' - t.end() - }) -}) - -t.test('scoped login with valid scoped registry config', (t) => { - _flatOptions['@myscope:registry'] = 'https://diff-registry.npmjs.com/' - _flatOptions.scope = '@myscope' - - adduser.exec([], (err) => { - t.error(err, 'npm adduser') - - t.same( - setConfig['@myscope:registry'], - { value: 'https://diff-registry.npmjs.com/', where: 'user' }, - 'should keep scoped registry config' - ) - - delete _flatOptions['@myscope:registry'] - _flatOptions.scope = '' - deletedConfig = {} - setConfig = {} - result = '' - t.end() - }) -}) - -t.test('save config failure', (t) => { - failSave = true - - adduser.exec([], (err) => { - t.match( - err, - /error saving user config/, - 'should throw config.save error' - ) - - failSave = false - deletedConfig = {} - setConfig = {} - result = '' - t.end() - }) -}) diff --git a/deps/npm/test/lib/workspaces/arborist-cmd.js b/deps/npm/test/lib/arborist-cmd.js similarity index 66% rename from deps/npm/test/lib/workspaces/arborist-cmd.js rename to deps/npm/test/lib/arborist-cmd.js index 75ac8f4ebf804a..3db862d233dc7e 100644 --- a/deps/npm/test/lib/workspaces/arborist-cmd.js +++ b/deps/npm/test/lib/arborist-cmd.js @@ -1,6 +1,6 @@ const { resolve } = require('path') const t = require('tap') -const ArboristCmd = require('../../../lib/workspaces/arborist-cmd.js') +const ArboristCmd = require('../../lib/arborist-cmd.js') t.test('arborist-cmd', async t => { const path = t.testdir({ @@ -48,69 +48,51 @@ t.test('arborist-cmd', async t => { cmd.npm = { localPrefix: path } // check filtering for a single workspace name - cmd.exec = function (args, cb) { + cmd.exec = async function (args) { t.same(this.workspaceNames, ['a'], 'should set array with single ws name') t.same(args, ['foo'], 'should get received args') - cb() } - await new Promise(res => { - cmd.execWorkspaces(['foo'], ['a'], res) - }) + await cmd.execWorkspaces(['foo'], ['a']) // check filtering single workspace by path - cmd.exec = function (args, cb) { + cmd.exec = async function (args) { t.same(this.workspaceNames, ['a'], 'should set array with single ws name from path') - cb() } - await new Promise(res => { - cmd.execWorkspaces([], ['./a'], res) - }) + await cmd.execWorkspaces([], ['./a']) // check filtering single workspace by full path - cmd.exec = function (args, cb) { + cmd.exec = function (args) { t.same(this.workspaceNames, ['a'], 'should set array with single ws name from full path') - cb() } - await new Promise(res => { - cmd.execWorkspaces([], [resolve(path, './a')], res) - }) + await cmd.execWorkspaces([], [resolve(path, './a')]) // filtering multiple workspaces by name - cmd.exec = function (args, cb) { + cmd.exec = async function (args) { t.same(this.workspaceNames, ['a', 'c'], 'should set array with multiple listed ws names') - cb() } - await new Promise(res => { - cmd.execWorkspaces([], ['a', 'c'], res) - }) + await cmd.execWorkspaces([], ['a', 'c']) // filtering multiple workspaces by path names - cmd.exec = function (args, cb) { + cmd.exec = async function (args) { t.same(this.workspaceNames, ['a', 'c'], 'should set array with multiple ws names from paths') - cb() } - await new Promise(res => { - cmd.execWorkspaces([], ['./a', 'group/c'], res) - }) + await cmd.execWorkspaces([], ['./a', 'group/c']) // filtering multiple workspaces by parent path name - cmd.exec = function (args, cb) { + cmd.exec = async function (args) { t.same(this.workspaceNames, ['c', 'd'], 'should set array with multiple ws names from a parent folder name') - cb() } - await new Promise(res => { - cmd.execWorkspaces([], ['./group'], res) - }) + await cmd.execWorkspaces([], ['./group']) }) -t.test('handle getWorkspaces raising an error', t => { - const ArboristCmd = t.mock('../../../lib/workspaces/arborist-cmd.js', { - '../../../lib/workspaces/get-workspaces.js': async () => { +t.test('handle getWorkspaces raising an error', async t => { + const ArboristCmd = t.mock('../../lib/arborist-cmd.js', { + '../../lib/workspaces/get-workspaces.js': async () => { throw new Error('oopsie') }, }) @@ -118,8 +100,8 @@ t.test('handle getWorkspaces raising an error', t => { const cmd = new TestCmd() cmd.npm = {} - cmd.execWorkspaces(['foo'], ['a'], er => { - t.match(er, { message: 'oopsie' }) - t.end() - }) + await t.rejects( + cmd.execWorkspaces(['foo'], ['a']), + { message: 'oopsie' } + ) }) diff --git a/deps/npm/test/lib/birthday.js b/deps/npm/test/lib/birthday.js deleted file mode 100644 index 05660d6fa3f205..00000000000000 --- a/deps/npm/test/lib/birthday.js +++ /dev/null @@ -1,27 +0,0 @@ -const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') - -const config = { - yes: false, - package: [], -} -const npm = mockNpm({ - config, - commands: { - exec: (args, cb) => { - t.equal(npm.config.get('yes'), true, 'should say yes') - t.strictSame(npm.config.get('package'), ['@npmcli/npm-birthday'], - 'uses correct package') - t.strictSame(args, ['npm-birthday'], 'called with correct args') - t.match(cb, Function, 'callback is a function') - cb() - }, - }, -}) - -const Birthday = require('../../lib/birthday.js') -const birthday = new Birthday(npm) - -let calledCb = false -birthday.exec([], () => calledCb = true) -t.equal(calledCb, true, 'called the callback') diff --git a/deps/npm/test/lib/cache.js b/deps/npm/test/lib/cache.js deleted file mode 100644 index c6405303202b8e..00000000000000 --- a/deps/npm/test/lib/cache.js +++ /dev/null @@ -1,480 +0,0 @@ -const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm.js') -const path = require('path') -const npa = require('npm-package-arg') - -const usageUtil = () => 'usage instructions' - -let outputOutput = [] - -let rimrafPath = '' -const rimraf = (path, cb) => { - rimrafPath = path - return cb() -} - -let logOutput = [] -const npmlog = { - silly: (...args) => { - logOutput.push(['silly', ...args]) - }, -} - -let tarballStreamSpec = '' -let tarballStreamOpts = {} -const pacote = { - tarball: { - stream: (spec, handler, opts) => { - tarballStreamSpec = spec - tarballStreamOpts = opts - return handler({ - resume: () => {}, - promise: () => Promise.resolve(), - }) - }, - }, -} - -let cacacheEntries = {} -let cacacheContent = {} - -const setupCacacheFixture = () => { - cacacheEntries = {} - cacacheContent = {} - const pkgs = [ - ['webpack@4.44.1', 'https://registry.npmjs.org', true], - ['npm@1.2.0', 'https://registry.npmjs.org', true], - ['webpack@4.47.0', 'https://registry.npmjs.org', true], - ['foo@1.2.3-beta', 'https://registry.npmjs.org', true], - ['ape-ecs@2.1.7', 'https://registry.npmjs.org', true], - ['@fritzy/staydown@3.1.1', 'https://registry.npmjs.org', true], - ['@gar/npm-expansion@2.1.0', 'https://registry.npmjs.org', true], - ['@gar/npm-expansion@3.0.0-beta', 'https://registry.npmjs.org', true], - ['extemporaneously@44.2.2', 'https://somerepo.github.org', false], - ['corrupted@3.1.0', 'https://registry.npmjs.org', true], - ['missing-dist@23.0.0', 'https://registry.npmjs.org', true], - ['missing-version@16.2.0', 'https://registry.npmjs.org', true], - ] - pkgs.forEach(pkg => addCacachePkg(...pkg)) - // corrupt the packument - cacacheContent[ - [cacacheEntries['make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted'].integrity] - ].data = Buffer.from('<>>>}"') - // nuke the version dist - cacacheContent[ - [cacacheEntries['make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist'].integrity] - ].data = Buffer.from(JSON.stringify({ versions: { '23.0.0': {} } })) - // make the version a non-object - cacacheContent[ - [cacacheEntries['make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version'].integrity] - ].data = Buffer.from(JSON.stringify({ versions: 'hello' })) -} - -const packuments = {} - -let contentId = 0 -const cacacheVerifyStats = { - keptSize: 100, - verifiedContent: 1, - totalEntries: 1, - runTime: { total: 2000 }, -} - -const addCacacheKey = (key, content) => { - contentId++ - cacacheEntries[key] = { integrity: `${contentId}` } - cacacheContent[`${contentId}`] = {} -} -const addCacachePkg = (spec, registry, publicURL) => { - const parts = npa(spec) - const ver = parts.rawSpec || '1.0.0' - let url = `${registry}/${parts.name}/-/${parts.name}-${ver}.tgz` - if (!publicURL) - url = `${registry}/aabbcc/${contentId}` - const key = `make-fetch-happen:request-cache:${url}` - const pkey = `make-fetch-happen:request-cache:${registry}/${parts.escapedName}` - if (!packuments[parts.escapedName]) { - packuments[parts.escapedName] = { - versions: {}, - } - addCacacheKey(pkey) - } - packuments[parts.escapedName].versions[ver] = { - dist: { - tarball: url, - }, - } - addCacacheKey(key) - cacacheContent[cacacheEntries[pkey].integrity] = { - data: Buffer.from(JSON.stringify(packuments[parts.escapedName])), - } -} - -const cacache = { - verify: (path) => { - return cacacheVerifyStats - }, - get: (path, key) => { - if (cacacheEntries[key] === undefined - || cacacheContent[cacacheEntries[key].integrity] === undefined) - throw new Error() - return cacacheContent[cacacheEntries[key].integrity] - }, - rm: { - entry: (path, key) => { - if (cacacheEntries[key] === undefined) - throw new Error() - delete cacacheEntries[key] - }, - content: (path, sha) => { - delete cacacheContent[sha] - }, - }, - ls: (path) => { - return cacacheEntries - }, -} - -const Cache = t.mock('../../lib/cache.js', { - cacache, - npmlog, - pacote, - rimraf, - '../../lib/utils/usage.js': usageUtil, -}) - -const npm = mockNpm({ - cache: '/fake/path', - flatOptions: { force: false }, - config: { force: false }, - output: (msg) => { - outputOutput.push(msg) - }, - log: { - warn: (...args) => { - logOutput.push(['warn', ...args]) - }, - }, -}) -const cache = new Cache(npm) - -t.test('cache no args', t => { - cache.exec([], err => { - t.match(err.message, 'usage instructions', 'should throw usage instructions') - t.end() - }) -}) - -t.test('cache clean', t => { - cache.exec(['clean'], err => { - t.match(err.message, 'the npm cache self-heals', 'should throw warning') - t.end() - }) -}) - -t.test('cache clean (force)', t => { - npm.config.set('force', true) - npm.flatOptions.force = true - t.teardown(() => { - rimrafPath = '' - npm.config.force = false - npm.flatOptions.force = false - }) - - cache.exec(['clear'], err => { - t.error(err) - t.equal(rimrafPath, path.join(npm.cache, '_cacache')) - t.end() - }) -}) - -t.test('cache add no arg', t => { - t.teardown(() => { - logOutput = [] - }) - - cache.exec(['add'], err => { - t.strictSame(logOutput, [ - ['silly', 'cache add', 'args', []], - ], 'logs correctly') - t.equal(err.code, 'EUSAGE', 'throws usage error') - t.end() - }) -}) - -t.test('cache add pkg only', t => { - t.teardown(() => { - logOutput = [] - tarballStreamSpec = '' - tarballStreamOpts = {} - }) - - cache.exec(['add', 'mypkg'], err => { - t.error(err) - t.strictSame(logOutput, [ - ['silly', 'cache add', 'args', ['mypkg']], - ['silly', 'cache add', 'spec', 'mypkg'], - ], 'logs correctly') - t.equal(tarballStreamSpec, 'mypkg', 'passes the correct spec to pacote') - t.same(tarballStreamOpts, npm.flatOptions, 'passes the correct options to pacote') - t.end() - }) -}) - -t.test('cache add multiple pkgs', t => { - t.teardown(() => { - outputOutput = [] - tarballStreamSpec = '' - tarballStreamOpts = {} - }) - - cache.exec(['add', 'mypkg', 'anotherpkg'], err => { - t.error(err) - t.strictSame(logOutput, [ - ['silly', 'cache add', 'args', ['mypkg', 'anotherpkg']], - ['silly', 'cache add', 'spec', 'mypkg'], - ['silly', 'cache add', 'spec', 'anotherpkg'], - ], 'logs correctly') - t.equal(tarballStreamSpec, 'anotherpkg', 'passes the correct spec to pacote') - t.same(tarballStreamOpts, npm.flatOptions, 'passes the correct options to pacote') - t.end() - }) -}) - -t.test('cache ls', t => { - t.teardown(() => { - outputOutput = [] - logOutput = [] - }) - setupCacacheFixture() - cache.exec(['ls'], err => { - t.error(err) - t.strictSame(outputOutput, [ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@fritzy/staydown/-/@fritzy/staydown-3.1.1.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@fritzy%2fstaydown', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar/npm-expansion/-/@gar/npm-expansion-2.1.0.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar/npm-expansion/-/@gar/npm-expansion-3.0.0-beta.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar%2fnpm-expansion', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/ape-ecs', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/ape-ecs/-/ape-ecs-2.1.7.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted/-/corrupted-3.1.0.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/foo', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/foo/-/foo-1.2.3-beta.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist/-/missing-dist-23.0.0.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version/-/missing-version-16.2.0.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/npm', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/npm/-/npm-1.2.0.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz', - 'make-fetch-happen:request-cache:https://somerepo.github.org/aabbcc/14', - 'make-fetch-happen:request-cache:https://somerepo.github.org/extemporaneously', - ]) - t.end() - }) -}) - -t.test('cache ls pkgs', t => { - t.teardown(() => { - outputOutput = [] - }) - cache.exec(['ls', 'webpack@>4.44.1', 'npm'], err => { - t.error(err) - t.strictSame(outputOutput, [ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/npm', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/npm/-/npm-1.2.0.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz', - ]) - t.end() - }) -}) - -t.test('cache ls special', t => { - t.teardown(() => { - outputOutput = [] - }) - cache.exec(['ls', 'foo@1.2.3-beta'], err => { - t.error(err) - t.strictSame(outputOutput, [ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/foo', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/foo/-/foo-1.2.3-beta.tgz', - ]) - t.end() - }) -}) - -t.test('cache ls nonpublic registry', t => { - t.teardown(() => { - outputOutput = [] - }) - cache.exec(['ls', 'extemporaneously'], err => { - t.error(err) - t.strictSame(outputOutput, [ - 'make-fetch-happen:request-cache:https://somerepo.github.org/aabbcc/14', - 'make-fetch-happen:request-cache:https://somerepo.github.org/extemporaneously', - ]) - t.end() - }) -}) - -t.test('cache ls tagged', t => { - t.teardown(() => { - outputOutput = [] - }) - cache.exec(['ls', 'webpack@latest'], err => { - t.match(err.message, 'tagged package', 'should throw warning') - t.end() - }) -}) - -t.test('cache ls scoped and scoped slash', t => { - t.teardown(() => { - outputOutput = [] - }) - cache.exec(['ls', '@fritzy/staydown', '@gar/npm-expansion'], err => { - t.error(err) - t.strictSame(outputOutput, [ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@fritzy/staydown/-/@fritzy/staydown-3.1.1.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@fritzy%2fstaydown', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar/npm-expansion/-/@gar/npm-expansion-2.1.0.tgz', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar%2fnpm-expansion', - ]) - t.end() - }) -}) - -t.test('cache ls corrupted', t => { - t.teardown(() => { - outputOutput = [] - }) - cache.exec(['ls', 'corrupted'], err => { - t.error(err) - t.strictSame(outputOutput, [ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted/-/corrupted-3.1.0.tgz', - ]) - t.end() - }) -}) - -t.test('cache ls missing packument dist', t => { - t.teardown(() => { - outputOutput = [] - }) - cache.exec(['ls', 'missing-dist'], err => { - t.error(err) - t.strictSame(outputOutput, [ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist/-/missing-dist-23.0.0.tgz', - ]) - t.end() - }) -}) - -t.test('cache ls missing packument version not an object', t => { - t.teardown(() => { - outputOutput = [] - }) - cache.exec(['ls', 'missing-version'], err => { - t.error(err) - t.strictSame(outputOutput, [ - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version/-/missing-version-16.2.0.tgz', - ]) - t.end() - }) -}) - -t.test('cache rm', t => { - t.teardown(() => { - outputOutput = [] - }) - cache.exec(['rm', - 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz'], err => { - t.error(err) - t.strictSame(outputOutput, [ - 'Deleted: make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz', - ]) - t.end() - }) -}) - -t.test('cache rm unfound', t => { - t.teardown(() => { - outputOutput = [] - logOutput = [] - }) - cache.exec(['rm', 'made-up-key'], err => { - t.error(err) - t.strictSame(logOutput, [ - ['warn', 'Not Found: made-up-key'], - ], 'logs correctly') - t.end() - }) -}) - -t.test('cache verify', t => { - t.teardown(() => { - outputOutput = [] - }) - - cache.exec(['verify'], err => { - t.error(err) - t.match(outputOutput, [ - `Cache verified and compressed (${path.join(npm.cache, '_cacache')})`, - 'Content verified: 1 (100 bytes)', - 'Index entries: 1', - 'Finished in 2s', - ], 'prints correct output') - t.end() - }) -}) - -t.test('cache verify w/ extra output', t => { - npm.cache = `${process.env.HOME}/fake/path` - cacacheVerifyStats.badContentCount = 1 - cacacheVerifyStats.reclaimedCount = 2 - cacacheVerifyStats.reclaimedSize = 200 - cacacheVerifyStats.missingContent = 3 - t.teardown(() => { - npm.cache = '/fake/path' - outputOutput = [] - delete cacacheVerifyStats.badContentCount - delete cacacheVerifyStats.reclaimedCount - delete cacacheVerifyStats.reclaimedSize - delete cacacheVerifyStats.missingContent - }) - - cache.exec(['check'], err => { - t.error(err) - t.match(outputOutput, [ - `Cache verified and compressed (~${path.join('/fake/path', '_cacache')})`, - 'Content verified: 1 (100 bytes)', - 'Corrupted content removed: 1', - 'Content garbage-collected: 2 (200 bytes)', - 'Missing content: 3', - 'Index entries: 1', - 'Finished in 2s', - ], 'prints correct output') - t.end() - }) -}) - -t.test('cache completion', t => { - const { completion } = cache - - const testComp = (argv, expect) => { - t.resolveMatch(completion({ conf: { argv: { remain: argv } } }), expect, argv.join(' ')) - } - - testComp(['npm', 'cache'], ['add', 'clean', 'verify']) - testComp(['npm', 'cache', 'add'], []) - testComp(['npm', 'cache', 'clean'], []) - testComp(['npm', 'cache', 'verify'], []) - - t.end() -}) diff --git a/deps/npm/test/lib/cli.js b/deps/npm/test/lib/cli.js index 2c0b6c0ba727e8..4e24dcd78b73ff 100644 --- a/deps/npm/test/lib/cli.js +++ b/deps/npm/test/lib/cli.js @@ -26,8 +26,8 @@ const npmlogMock = { info: (...msg) => logs.push(['info', ...msg]), } -const cliMock = (npm) => t.mock('../../lib/cli.js', { - '../../lib/npm.js': npm, +const cliMock = (Npm) => t.mock('../../lib/cli.js', { + '../../lib/npm.js': Npm, '../../lib/utils/update-notifier.js': async () => null, '../../lib/utils/unsupported.js': unsupportedMock, '../../lib/utils/exit-handler.js': exitHandlerMock, @@ -60,8 +60,8 @@ t.test('print the version, and treat npm_g as npm -g', async t => { version: process.version, }) - const { npm, outputs } = mockNpm(t) - const cli = cliMock(npm) + const { Npm, outputs } = mockNpm(t) + const cli = cliMock(Npm) await cli(proc) t.strictSame(proc.argv, ['node', 'npm', '-g', '-v'], 'npm process.argv was rewritten') @@ -69,34 +69,32 @@ t.test('print the version, and treat npm_g as npm -g', async t => { t.strictSame(logs, [ 'pause', ['verbose', 'cli', proc.argv], - ['info', 'using', 'npm@%s', npm.version], + ['info', 'using', 'npm@%s', Npm.version], ['info', 'using', 'node@%s', process.version], ]) - t.strictSame(outputs, [[npm.version]]) + t.strictSame(outputs, [[Npm.version]]) t.strictSame(exitHandlerCalled, []) }) t.test('calling with --versions calls npm version with no args', async t => { + t.plan(5) const proc = processMock({ argv: ['node', 'npm', 'install', 'or', 'whatever', '--versions'], }) - const { npm, outputs } = mockNpm(t) - const cli = cliMock(npm) - - let versionArgs - npm.commands.version = (args, cb) => { - versionArgs = args - cb() - } - + const { Npm, outputs } = mockNpm(t, { + '../../lib/commands/version.js': class Version { + async exec (args) { + t.strictSame(args, []) + } + }, + }) + const cli = cliMock(Npm) await cli(proc) - t.strictSame(versionArgs, []) t.equal(proc.title, 'npm') - t.strictSame(npm.argv, []) t.strictSame(logs, [ 'pause', ['verbose', 'cli', proc.argv], - ['info', 'using', 'npm@%s', npm.version], + ['info', 'using', 'npm@%s', Npm.version], ['info', 'using', 'node@%s', process.version], ]) @@ -106,14 +104,17 @@ t.test('calling with --versions calls npm version with no args', async t => { t.test('logged argv is sanitized', async t => { const proc = processMock({ - argv: ['node', 'npm', 'testcommand', 'https://username:password@npmjs.org/test_url_with_a_password'], + argv: ['node', 'npm', 'version', 'https://username:password@npmjs.org/test_url_with_a_password'], }) - const { npm } = mockNpm(t) - const cli = cliMock(npm) + const { Npm } = mockNpm(t, { + '../../lib/commands/version.js': class Version { + async exec (args) { - npm.commands.testcommand = (args, cb) => { - cb() - } + } + }, + }) + + const cli = cliMock(Npm) await cli(proc) t.equal(proc.title, 'npm') @@ -122,10 +123,10 @@ t.test('logged argv is sanitized', async t => { ['verbose', 'cli', [ 'node', 'npm', - 'testcommand', + 'version', 'https://username:***@npmjs.org/test_url_with_a_password', ]], - ['info', 'using', 'npm@%s', npm.version], + ['info', 'using', 'npm@%s', Npm.version], ['info', 'using', 'node@%s', process.version], ]) }) @@ -135,8 +136,8 @@ t.test('print usage if no params provided', async t => { argv: ['node', 'npm'], }) - const { npm, outputs } = mockNpm(t) - const cli = cliMock(npm) + const { Npm, outputs } = mockNpm(t) + const cli = cliMock(Npm) await cli(proc) t.match(outputs[0][0], 'Usage:', 'outputs npm usage') t.match(exitHandlerCalled, [], 'should call exitHandler with no args') @@ -149,8 +150,8 @@ t.test('print usage if non-command param provided', async t => { argv: ['node', 'npm', 'tset'], }) - const { npm, outputs } = mockNpm(t) - const cli = cliMock(npm) + const { Npm, outputs } = mockNpm(t) + const cli = cliMock(Npm) await cli(proc) t.match(outputs[0][0], 'Unknown command: "tset"') t.match(outputs[0][0], 'Did you mean this?') @@ -164,10 +165,20 @@ t.test('load error calls error handler', async t => { argv: ['node', 'npm', 'asdf'], }) - const { npm } = mockNpm(t) - const cli = cliMock(npm) - const er = new Error('test load error') - npm.load = () => Promise.reject(er) + const err = new Error('test load error') + const { Npm } = mockNpm(t, { + '../../lib/utils/config/index.js': { + definitions: null, + flatten: null, + shorthands: null, + }, + '@npmcli/config': class BadConfig { + async load () { + throw err + } + }, + }) + const cli = cliMock(Npm) await cli(proc) - t.strictSame(exitHandlerCalled, [er]) + t.strictSame(exitHandlerCalled, [err]) }) diff --git a/deps/npm/test/lib/commands/access.js b/deps/npm/test/lib/commands/access.js new file mode 100644 index 00000000000000..6ddd21428a781f --- /dev/null +++ b/deps/npm/test/lib/commands/access.js @@ -0,0 +1,439 @@ +const t = require('tap') + +const { real: mockNpm } = require('../../fixtures/mock-npm.js') + +const { Npm } = mockNpm(t) +const npm = new Npm() + +const prefix = t.testdir({}) + +t.before(async () => { + await npm.load() + npm.prefix = prefix +}) + +t.test('completion', async t => { + const access = await npm.cmd('access') + const testComp = (argv, expect) => { + const res = access.completion({ conf: { argv: { remain: argv } } }) + t.resolves(res, expect, argv.join(' ')) + } + + testComp(['npm', 'access'], [ + 'public', 'restricted', 'grant', 'revoke', 'ls-packages', + 'ls-collaborators', 'edit', '2fa-required', '2fa-not-required', + ]) + testComp(['npm', 'access', 'grant'], ['read-only', 'read-write']) + testComp(['npm', 'access', 'grant', 'read-only'], []) + testComp(['npm', 'access', 'public'], []) + testComp(['npm', 'access', 'restricted'], []) + testComp(['npm', 'access', 'revoke'], []) + testComp(['npm', 'access', 'ls-packages'], []) + testComp(['npm', 'access', 'ls-collaborators'], []) + testComp(['npm', 'access', 'edit'], []) + testComp(['npm', 'access', '2fa-required'], []) + testComp(['npm', 'access', '2fa-not-required'], []) + testComp(['npm', 'access', 'revoke'], []) + + await t.rejects( + access.completion({conf: {argv: {remain: ['npm', 'access', 'foobar']}}}), + { message: 'foobar not recognized' } + ) +}) + +t.test('subcommand required', async t => { + const access = await npm.cmd('access') + await t.rejects( + npm.exec('access', []), + access.usageError('Subcommand is required.') + ) +}) + +t.test('unrecognized subcommand', async t => { + await t.rejects( + npm.exec('access', ['blerg']), + /Usage: blerg is not a recognized subcommand/, + 'should throw EUSAGE on missing subcommand' + ) +}) + +t.test('edit', async t => { + await t.rejects( + npm.exec('access', ['edit', '@scoped/another']), + /edit subcommand is not implemented yet/, + 'should throw not implemented yet error' + ) +}) + +t.test('access public on unscoped package', async t => { + t.teardown(() => { + npm.prefix = prefix + }) + const testdir = t.testdir({ + 'package.json': JSON.stringify({ + name: 'npm-access-public-pkg', + }), + }) + npm.prefix = testdir + await t.rejects( + npm.exec('access', ['public']), + /Usage: This command is only available for scoped packages/, + 'should throw scoped-restricted error' + ) +}) + +t.test('access public on scoped package', async t => { + t.plan(2) + const { Npm } = mockNpm(t, { + libnpmaccess: { + public: (pkg, { registry }) => { + t.equal(pkg, name, 'should use pkg name ref') + t.equal( + registry, + 'https://registry.npmjs.org/', + 'should forward correct options' + ) + return true + }, + }, + }) + const npm = new Npm() + await npm.load() + const name = '@scoped/npm-access-public-pkg' + const testdir = t.testdir({ + 'package.json': JSON.stringify({ name }), + }) + npm.prefix = testdir + await npm.exec('access', ['public']) +}) + +t.test('access public on missing package.json', async t => { + await t.rejects( + npm.exec('access', ['public']), + /no package name passed to command and no package.json found/, + 'should throw no package.json found error' + ) +}) + +t.test('access public on invalid package.json', async t => { + t.teardown(() => { + npm.prefix = prefix + }) + const testdir = t.testdir({ + 'package.json': '{\n', + node_modules: {}, + }) + npm.prefix = testdir + await t.rejects( + npm.exec('access', ['public']), + { code: 'EJSONPARSE' }, + 'should throw failed to parse package.json' + ) +}) + +t.test('access restricted on unscoped package', async t => { + t.teardown(() => { + npm.prefix = prefix + }) + const testdir = t.testdir({ + 'package.json': JSON.stringify({ + name: 'npm-access-restricted-pkg', + }), + }) + npm.prefix = testdir + await t.rejects( + npm.exec('access', ['public']), + /Usage: This command is only available for scoped packages/, + 'should throw scoped-restricted error' + ) +}) + +t.test('access restricted on scoped package', async t => { + t.plan(2) + const { Npm } = mockNpm(t, { + libnpmaccess: { + restricted: (pkg, { registry }) => { + t.equal(pkg, name, 'should use pkg name ref') + t.equal( + registry, + 'https://registry.npmjs.org/', + 'should forward correct options' + ) + return true + }, + }, + }) + const npm = new Npm() + await npm.load() + const name = '@scoped/npm-access-restricted-pkg' + const testdir = t.testdir({ + 'package.json': JSON.stringify({ name }), + }) + npm.prefix = testdir + await npm.exec('access', ['restricted']) +}) + +t.test('access restricted on missing package.json', async t => { + await t.rejects( + npm.exec('access', ['restricted']), + /no package name passed to command and no package.json found/, + 'should throw no package.json found error' + ) +}) + +t.test('access restricted on invalid package.json', async t => { + t.teardown(() => { + npm.prefix = prefix + }) + const testdir = t.testdir({ + 'package.json': '{\n', + node_modules: {}, + }) + npm.prefix = testdir + await t.rejects( + npm.exec('access', ['restricted']), + { code: 'EJSONPARSE' }, + 'should throw failed to parse package.json' + ) +}) + +t.test('access grant read-only', async t => { + t.plan(3) + const { Npm } = mockNpm(t, { + libnpmaccess: { + grant: (spec, team, permissions) => { + t.equal(spec, '@scoped/another', 'should use expected spec') + t.equal(team, 'myorg:myteam', 'should use expected team') + t.equal(permissions, 'read-only', 'should forward permissions') + return true + }, + }, + }) + const npm = new Npm() + await npm.exec('access', [ + 'grant', + 'read-only', + 'myorg:myteam', + '@scoped/another', + ]) +}) + +t.test('access grant read-write', async t => { + t.plan(3) + const { Npm } = mockNpm(t, { + libnpmaccess: { + grant: (spec, team, permissions) => { + t.equal(spec, '@scoped/another', 'should use expected spec') + t.equal(team, 'myorg:myteam', 'should use expected team') + t.equal(permissions, 'read-write', 'should forward permissions') + return true + }, + }, + }) + const npm = new Npm() + await npm.exec('access', [ + 'grant', + 'read-write', + 'myorg:myteam', + '@scoped/another', + ]) +}) + +t.test('access grant current cwd', async t => { + t.plan(3) + const testdir = t.testdir({ + 'package.json': JSON.stringify({ + name: 'yargs', + }), + }) + const { Npm } = mockNpm(t, { + libnpmaccess: { + grant: (spec, team, permissions) => { + t.equal(spec, 'yargs', 'should use expected spec') + t.equal(team, 'myorg:myteam', 'should use expected team') + t.equal(permissions, 'read-write', 'should forward permissions') + return true + }, + }, + }) + const npm = new Npm() + await npm.load() + npm.prefix = testdir + await npm.exec('access', [ + 'grant', + 'read-write', + 'myorg:myteam', + ]) +}) + +t.test('access grant others', async t => { + await t.rejects( + npm.exec('access', [ + 'grant', + 'rerere', + 'myorg:myteam', + '@scoped/another', + ]), + /Usage: First argument must be either `read-only` or `read-write`./, + 'should throw unrecognized argument error' + ) +}) + +t.test('access grant missing team args', async t => { + await t.rejects( + npm.exec('access', [ + 'grant', + 'read-only', + undefined, + '@scoped/another', + ]), + /Usage: `` argument is required./, + 'should throw missing argument error' + ) +}) + +t.test('access grant malformed team arg', async t => { + await t.rejects( + npm.exec('access', [ + 'grant', + 'read-only', + 'foo', + '@scoped/another', + ]), + /Usage: Second argument used incorrect format.\n/, + 'should throw malformed arg error' + ) +}) + +t.test('access 2fa-required/2fa-not-required', async t => { + t.plan(2) + const { Npm } = mockNpm(t, { + libnpmaccess: { + tfaRequired: (spec) => { + t.equal(spec, '@scope/pkg', 'should use expected spec') + return true + }, + tfaNotRequired: (spec) => { + t.equal(spec, 'unscoped-pkg', 'should use expected spec') + return true + }, + }, + }) + const npm = new Npm() + + await npm.exec('access', ['2fa-required', '@scope/pkg']) + await npm.exec('access', ['2fa-not-required', 'unscoped-pkg']) +}) + +t.test('access revoke', async t => { + t.plan(2) + const { Npm } = mockNpm(t, { + libnpmaccess: { + revoke: (spec, team) => { + t.equal(spec, '@scoped/another', 'should use expected spec') + t.equal(team, 'myorg:myteam', 'should use expected team') + return true + }, + }, + }) + const npm = new Npm() + await npm.exec('access', [ + 'revoke', + 'myorg:myteam', + '@scoped/another', + ]) +}) + +t.test('access revoke missing team args', async t => { + await t.rejects( + npm.exec('access', [ + 'revoke', + undefined, + '@scoped/another', + ]), + /Usage: `` argument is required./, + 'should throw missing argument error' + ) +}) + +t.test('access revoke malformed team arg', async t => { + await t.rejects( + npm.exec('access', [ + 'revoke', + 'foo', + '@scoped/another', + ]), + /Usage: First argument used incorrect format.\n/, + 'should throw malformed arg error' + ) +}) + +t.test('npm access ls-packages with no team', async t => { + t.plan(1) + const { Npm } = mockNpm(t, { + libnpmaccess: { + lsPackages: (entity) => { + t.equal(entity, 'foo', 'should use expected entity') + return {} + }, + }, + '../../lib/utils/get-identity.js': () => Promise.resolve('foo'), + }) + const npm = new Npm() + await npm.exec('access', ['ls-packages']) +}) + +t.test('access ls-packages on team', async t => { + t.plan(1) + const { Npm } = mockNpm(t, { + libnpmaccess: { + lsPackages: (entity) => { + t.equal(entity, 'myorg:myteam', 'should use expected entity') + return {} + }, + }, + }) + const npm = new Npm() + await npm.exec('access', [ + 'ls-packages', + 'myorg:myteam', + ]) +}) + +t.test('access ls-collaborators on current', async t => { + t.plan(1) + const testdir = t.testdir({ + 'package.json': JSON.stringify({ + name: 'yargs', + }), + }) + const { Npm } = mockNpm(t, { + libnpmaccess: { + lsCollaborators: (spec) => { + t.equal(spec, 'yargs', 'should use expected spec') + return {} + }, + }, + }) + const npm = new Npm() + await npm.load() + npm.prefix = testdir + await npm.exec('access', ['ls-collaborators']) +}) + +t.test('access ls-collaborators on spec', async t => { + t.plan(1) + const { Npm } = mockNpm(t, { + libnpmaccess: { + lsCollaborators: (spec) => { + t.equal(spec, 'yargs', 'should use expected spec') + return {} + }, + }, + }) + const npm = new Npm() + await npm.exec('access', [ + 'ls-collaborators', + 'yargs', + ]) +}) diff --git a/deps/npm/test/lib/commands/adduser.js b/deps/npm/test/lib/commands/adduser.js new file mode 100644 index 00000000000000..368d5d68a72271 --- /dev/null +++ b/deps/npm/test/lib/commands/adduser.js @@ -0,0 +1,185 @@ +const t = require('tap') +const { getCredentialsByURI, setCredentialsByURI } = + require('@npmcli/config').prototype + +let result = '' + +const _flatOptions = { + authType: 'legacy', + registry: 'https://registry.npmjs.org/', + scope: '', + fromFlatOptions: true, +} + +let failSave = false +let deletedConfig = {} +let registryOutput = '' +let setConfig = {} +const authDummy = (npm, options) => { + if (!options.fromFlatOptions) + throw new Error('did not pass full flatOptions to auth function') + + return Promise.resolve({ + message: 'success', + newCreds: { + username: 'u', + password: 'p', + email: 'u@npmjs.org', + }, + }) +} + +const deleteMock = (key, where) => { + deletedConfig = { + ...deletedConfig, + [key]: where, + } +} +const npm = { + flatOptions: _flatOptions, + config: { + delete: deleteMock, + get (key, where) { + if (!where || where === 'user') + return _flatOptions[key] + }, + getCredentialsByURI, + async save () { + if (failSave) + throw new Error('error saving user config') + }, + set (key, value, where) { + setConfig = { + ...setConfig, + [key]: { + value, + where, + }, + } + }, + setCredentialsByURI, + }, + output: msg => { + result = msg + }, +} + +const AddUser = t.mock('../../../lib/commands/adduser.js', { + npmlog: { + clearProgress: () => null, + disableProgress: () => null, + notice: (_, msg) => { + registryOutput = msg + }, + }, + '../../../lib/auth/legacy.js': authDummy, +}) + +const adduser = new AddUser(npm) + +t.afterEach(() => { + _flatOptions.authType = 'legacy' + _flatOptions.scope = '' + registryOutput = '' + deletedConfig = {} + setConfig = {} + result = '' + failSave = false +}) + +t.test('usage', async t => { + t.match(adduser.usage, 'adduser', 'usage has command name in it') +}) + +t.test('simple login', async t => { + await adduser.exec([]) + t.equal( + registryOutput, + 'Log in on https://registry.npmjs.org/', + 'should have correct message result' + ) + + t.same( + deletedConfig, + { + _token: 'user', + _password: 'user', + username: 'user', + _auth: 'user', + _authtoken: 'user', + '-authtoken': 'user', + _authToken: 'user', + '//registry.npmjs.org/:-authtoken': 'user', + '//registry.npmjs.org/:_authToken': 'user', + '//registry.npmjs.org/:_authtoken': 'user', + '//registry.npmjs.org/:always-auth': 'user', + '//registry.npmjs.org/:email': 'user', + }, + 'should delete token in user config' + ) + + t.same( + setConfig, + { + '//registry.npmjs.org/:_password': { value: 'cA==', where: 'user' }, + '//registry.npmjs.org/:username': { value: 'u', where: 'user' }, + email: { value: 'u@npmjs.org', where: 'user' }, + }, + 'should set expected user configs' + ) + + t.equal( + result, + 'success', + 'should output auth success msg' + ) +}) + +t.test('bad auth type', async t => { + _flatOptions.authType = 'foo' + + await t.rejects( + adduser.exec([]), + /no such auth module/, + 'should throw bad auth type error' + ) +}) + +t.test('scoped login', async t => { + _flatOptions.scope = '@myscope' + + await adduser.exec([]) + + t.same( + setConfig['@myscope:registry'], + { value: 'https://registry.npmjs.org/', where: 'user' }, + 'should set scoped registry config' + ) +}) + +t.test('scoped login with valid scoped registry config', async t => { + _flatOptions['@myscope:registry'] = 'https://diff-registry.npmjs.com/' + _flatOptions.scope = '@myscope' + + t.teardown(() => { + delete _flatOptions['@myscope:registry'] + }) + + await adduser.exec([]) + + t.same( + setConfig['@myscope:registry'], + { value: 'https://diff-registry.npmjs.com/', where: 'user' }, + 'should keep scoped registry config' + ) +}) + +t.test('save config failure', async t => { + failSave = true + + await t.rejects( + adduser.exec([]), + /error saving user config/, + 'should throw config.save error' + ) +}) diff --git a/deps/npm/test/lib/audit.js b/deps/npm/test/lib/commands/audit.js similarity index 63% rename from deps/npm/test/lib/audit.js rename to deps/npm/test/lib/commands/audit.js index 561765a0270b55..cf6d36d4710b7d 100644 --- a/deps/npm/test/lib/audit.js +++ b/deps/npm/test/lib/commands/audit.js @@ -1,5 +1,5 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') t.test('should audit using Arborist', t => { let ARB_ARGS = null @@ -18,7 +18,7 @@ t.test('should audit using Arborist', t => { OUTPUT_CALLED = true }, }) - const Audit = t.mock('../../lib/audit.js', { + const Audit = t.mock('../../../lib/commands/audit.js', { 'npm-audit-report': () => { AUDIT_REPORT_CALLED = true return { @@ -34,7 +34,7 @@ t.test('should audit using Arborist', t => { this.auditReport = {} } }, - '../../lib/utils/reify-finish.js': (npm, arb) => { + '../../../lib/utils/reify-finish.js': (npm, arb) => { if (arb !== ARB_OBJ) throw new Error('got wrong object passed to reify-output') @@ -44,27 +44,23 @@ t.test('should audit using Arborist', t => { const audit = new Audit(npm) - t.test('audit', t => { - audit.exec([], () => { - t.match(ARB_ARGS, { audit: true, path: 'foo' }) - t.equal(AUDIT_CALLED, true, 'called audit') - t.equal(AUDIT_REPORT_CALLED, true, 'called audit report') - t.equal(OUTPUT_CALLED, true, 'called audit report') - t.end() - }) + t.test('audit', async t => { + await audit.exec([]) + t.match(ARB_ARGS, { audit: true, path: 'foo' }) + t.equal(AUDIT_CALLED, true, 'called audit') + t.equal(AUDIT_REPORT_CALLED, true, 'called audit report') + t.equal(OUTPUT_CALLED, true, 'called audit report') }) - t.test('audit fix', t => { - audit.exec(['fix'], () => { - t.equal(REIFY_FINISH_CALLED, true, 'called reify output') - t.end() - }) + t.test('audit fix', async t => { + await audit.exec(['fix']) + t.equal(REIFY_FINISH_CALLED, true, 'called reify output') }) t.end() }) -t.test('should audit - json', t => { +t.test('should audit - json', async t => { const npm = mockNpm({ prefix: 'foo', config: { @@ -73,7 +69,7 @@ t.test('should audit - json', t => { output: () => {}, }) - const Audit = t.mock('../../lib/audit.js', { + const Audit = t.mock('../../../lib/commands/audit.js', { 'npm-audit-report': () => ({ report: 'there are vulnerabilities', exitCode: 0, @@ -83,19 +79,16 @@ t.test('should audit - json', t => { this.auditReport = {} } }, - '../../lib/utils/reify-output.js': () => {}, + '../../../lib/utils/reify-output.js': () => {}, }) const audit = new Audit(npm) - audit.exec([], (err) => { - t.notOk(err, 'no errors') - t.end() - }) + await audit.exec([]) }) t.test('report endpoint error', t => { for (const json of [true, false]) { - t.test(`json=${json}`, t => { + t.test(`json=${json}`, async t => { const OUTPUT = [] const LOGS = [] const npm = mockNpm({ @@ -114,7 +107,7 @@ t.test('report endpoint error', t => { OUTPUT.push(msg) }, }) - const Audit = t.mock('../../lib/audit.js', { + const Audit = t.mock('../../../lib/commands/audit.js', { 'npm-audit-report': () => { throw new Error('should not call audit report when there are errors') }, @@ -135,41 +128,41 @@ t.test('report endpoint error', t => { } } }, - '../../lib/utils/reify-output.js': () => {}, + '../../../lib/utils/reify-output.js': () => {}, }) const audit = new Audit(npm) - audit.exec([], (err) => { - t.equal(err, 'audit endpoint returned an error') - t.strictSame(OUTPUT, [ - [ - json ? '{\n' + - ' "message": "hello, this didnt work",\n' + - ' "method": "POST",\n' + - ' "uri": "https://example.com/",\n' + - ' "headers": {\n' + - ' "head": [\n' + - ' "ers"\n' + - ' ]\n' + - ' },\n' + - ' "statusCode": 420,\n' + - ' "body": {\n' + - ' "nope": "lol"\n' + - ' }\n' + - '}' - : 'i had a vuln but i eated it lol', - ], - ]) - t.strictSame(LOGS, [['audit', 'hello, this didnt work']]) - t.end() - }) + await t.rejects( + audit.exec([]), + 'audit endpoint returned an error' + ) + t.strictSame(OUTPUT, [ + [ + json ? '{\n' + + ' "message": "hello, this didnt work",\n' + + ' "method": "POST",\n' + + ' "uri": "https://example.com/",\n' + + ' "headers": {\n' + + ' "head": [\n' + + ' "ers"\n' + + ' ]\n' + + ' },\n' + + ' "statusCode": 420,\n' + + ' "body": {\n' + + ' "nope": "lol"\n' + + ' }\n' + + '}' + : 'i had a vuln but i eated it lol', + ], + ]) + t.strictSame(LOGS, [['audit', 'hello, this didnt work']]) }) } t.end() }) t.test('completion', t => { - const Audit = require('../../lib/audit.js') + const Audit = require('../../../lib/commands/audit.js') const audit = new Audit({}) t.test('fix', async t => { t.resolveMatch(audit.completion({ conf: { argv: { remain: ['npm', 'audit'] } } }), ['fix'], 'completes to fix') diff --git a/deps/npm/test/lib/bin.js b/deps/npm/test/lib/commands/bin.js similarity index 62% rename from deps/npm/test/lib/bin.js rename to deps/npm/test/lib/commands/bin.js index 8ceca8280f52d4..4de5a923b3eb63 100644 --- a/deps/npm/test/lib/bin.js +++ b/deps/npm/test/lib/commands/bin.js @@ -1,11 +1,11 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') -t.test('bin', (t) => { - t.plan(4) +t.test('bin', async t => { + t.plan(2) const dir = '/bin/dir' - const Bin = require('../../lib/bin.js') + const Bin = require('../../../lib/commands/bin.js') const npm = mockNpm({ bin: dir, @@ -17,14 +17,11 @@ t.test('bin', (t) => { const bin = new Bin(npm) t.match(bin.usage, 'bin', 'usage has command name in it') - bin.exec([], (err) => { - t.error(err, 'npm bin') - t.ok('should have printed directory') - }) + await bin.exec([]) }) -t.test('bin -g', (t) => { - t.plan(3) +t.test('bin -g', async t => { + t.plan(1) const consoleError = console.error t.teardown(() => { console.error = consoleError @@ -35,8 +32,8 @@ t.test('bin -g', (t) => { } const dir = '/bin/dir' - const Bin = t.mock('../../lib/bin.js', { - '../../lib/utils/path.js': [dir], + const Bin = t.mock('../../../lib/commands/bin.js', { + '../../../lib/utils/path.js': [dir], }) const npm = mockNpm({ @@ -48,14 +45,11 @@ t.test('bin -g', (t) => { }) const bin = new Bin(npm) - bin.exec([], (err) => { - t.error(err, 'npm bin') - t.ok('should have printed directory') - }) + await bin.exec([]) }) -t.test('bin -g (not in path)', (t) => { - t.plan(4) +t.test('bin -g (not in path)', async t => { + t.plan(2) const consoleError = console.error t.teardown(() => { console.error = consoleError @@ -66,8 +60,8 @@ t.test('bin -g (not in path)', (t) => { } const dir = '/bin/dir' - const Bin = t.mock('../../lib/bin.js', { - '../../lib/utils/path.js': ['/not/my/dir'], + const Bin = t.mock('../../../lib/commands/bin.js', { + '../../../lib/utils/path.js': ['/not/my/dir'], }) const npm = mockNpm({ bin: dir, @@ -78,8 +72,5 @@ t.test('bin -g (not in path)', (t) => { }) const bin = new Bin(npm) - bin.exec([], (err) => { - t.error(err, 'npm bin') - t.ok('should have printed directory') - }) + await bin.exec([]) }) diff --git a/deps/npm/test/lib/commands/birthday.js b/deps/npm/test/lib/commands/birthday.js new file mode 100644 index 00000000000000..c92f197c5f3f1c --- /dev/null +++ b/deps/npm/test/lib/commands/birthday.js @@ -0,0 +1,28 @@ +const t = require('tap') +const { fake: mockNpm } = require('../../fixtures/mock-npm') + +t.test('birthday', async t => { + t.plan(4) + const config = { + yes: false, + package: [], + } + const npm = mockNpm({ + config, + cmd: async (cmd) => { + t.ok(cmd, 'exec', 'calls out to exec command') + return { + exec: async (args) => { + t.equal(npm.config.get('yes'), true, 'should say yes') + t.strictSame(npm.config.get('package'), ['@npmcli/npm-birthday'], + 'uses correct package') + t.strictSame(args, ['npm-birthday'], 'called with correct args') + }, + } + }, + }) + const Birthday = require('../../../lib/commands/birthday.js') + const birthday = new Birthday(npm) + + await birthday.exec([]) +}) diff --git a/deps/npm/test/lib/bugs.js b/deps/npm/test/lib/commands/bugs.js similarity index 81% rename from deps/npm/test/lib/bugs.js rename to deps/npm/test/lib/commands/bugs.js index e5b238ffcea131..dcb36af393a61c 100644 --- a/deps/npm/test/lib/bugs.js +++ b/deps/npm/test/lib/commands/bugs.js @@ -51,15 +51,15 @@ const pacote = { } // keep a tally of which urls got opened -const opened = {} +let opened = {} const openUrl = async (npm, url, errMsg) => { opened[url] = opened[url] || 0 opened[url]++ } -const Bugs = t.mock('../../lib/bugs.js', { +const Bugs = t.mock('../../../lib/commands/bugs.js', { pacote, - '../../lib/utils/open-url.js': openUrl, + '../../../lib/utils/open-url.js': openUrl, }) const bugs = new Bugs({ flatOptions: {} }) @@ -69,6 +69,9 @@ t.test('usage', (t) => { t.end() }) +t.afterEach(() => { + opened = {} +}) t.test('open bugs urls & emails', t => { const expect = { nobugs: 'https://www.npmjs.com/package/nobugs', @@ -84,22 +87,14 @@ t.test('open bugs urls & emails', t => { const keys = Object.keys(expect) t.plan(keys.length) keys.forEach(pkg => { - t.test(pkg, t => { - bugs.exec([pkg], (er) => { - if (er) - throw er - t.equal(opened[expect[pkg]], 1, 'opened expected url', {opened}) - t.end() - }) + t.test(pkg, async t => { + await bugs.exec([pkg]) + t.equal(opened[expect[pkg]], 1, 'opened expected url', {opened}) }) }) }) -t.test('open default package if none specified', t => { - bugs.exec([], (er) => { - if (er) - throw er - t.equal(opened['https://example.com'], 2, 'opened expected url', {opened}) - t.end() - }) +t.test('open default package if none specified', async t => { + await bugs.exec([]) + t.equal(opened['https://example.com'], 1, 'opened expected url', {opened}) }) diff --git a/deps/npm/test/lib/commands/cache.js b/deps/npm/test/lib/commands/cache.js new file mode 100644 index 00000000000000..168cfce6db3e72 --- /dev/null +++ b/deps/npm/test/lib/commands/cache.js @@ -0,0 +1,439 @@ +const t = require('tap') +const { fake: mockNpm } = require('../../fixtures/mock-npm.js') +const path = require('path') +const npa = require('npm-package-arg') + +let outputOutput = [] + +let rimrafPath = '' +const rimraf = (path, cb) => { + rimrafPath = path + return cb() +} + +let logOutput = [] +const npmlog = { + silly: (...args) => { + logOutput.push(['silly', ...args]) + }, +} + +let tarballStreamSpec = '' +let tarballStreamOpts = {} +const pacote = { + tarball: { + stream: (spec, handler, opts) => { + tarballStreamSpec = spec + tarballStreamOpts = opts + return handler({ + resume: () => {}, + promise: () => Promise.resolve(), + }) + }, + }, +} + +let cacacheEntries = {} +let cacacheContent = {} + +const setupCacacheFixture = () => { + cacacheEntries = {} + cacacheContent = {} + const pkgs = [ + ['webpack@4.44.1', 'https://registry.npmjs.org', true], + ['npm@1.2.0', 'https://registry.npmjs.org', true], + ['webpack@4.47.0', 'https://registry.npmjs.org', true], + ['foo@1.2.3-beta', 'https://registry.npmjs.org', true], + ['ape-ecs@2.1.7', 'https://registry.npmjs.org', true], + ['@fritzy/staydown@3.1.1', 'https://registry.npmjs.org', true], + ['@gar/npm-expansion@2.1.0', 'https://registry.npmjs.org', true], + ['@gar/npm-expansion@3.0.0-beta', 'https://registry.npmjs.org', true], + ['extemporaneously@44.2.2', 'https://somerepo.github.org', false], + ['corrupted@3.1.0', 'https://registry.npmjs.org', true], + ['missing-dist@23.0.0', 'https://registry.npmjs.org', true], + ['missing-version@16.2.0', 'https://registry.npmjs.org', true], + ] + pkgs.forEach(pkg => addCacachePkg(...pkg)) + // corrupt the packument + cacacheContent[ + [cacacheEntries['make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted'].integrity] + ].data = Buffer.from('<>>>}"') + // nuke the version dist + cacacheContent[ + [cacacheEntries['make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist'].integrity] + ].data = Buffer.from(JSON.stringify({ versions: { '23.0.0': {} } })) + // make the version a non-object + cacacheContent[ + [cacacheEntries['make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version'].integrity] + ].data = Buffer.from(JSON.stringify({ versions: 'hello' })) +} + +const packuments = {} + +let contentId = 0 +const cacacheVerifyStats = { + keptSize: 100, + verifiedContent: 1, + totalEntries: 1, + runTime: { total: 2000 }, +} + +const addCacacheKey = (key, content) => { + contentId++ + cacacheEntries[key] = { integrity: `${contentId}` } + cacacheContent[`${contentId}`] = {} +} +const addCacachePkg = (spec, registry, publicURL) => { + const parts = npa(spec) + const ver = parts.rawSpec || '1.0.0' + let url = `${registry}/${parts.name}/-/${parts.name}-${ver}.tgz` + if (!publicURL) + url = `${registry}/aabbcc/${contentId}` + const key = `make-fetch-happen:request-cache:${url}` + const pkey = `make-fetch-happen:request-cache:${registry}/${parts.escapedName}` + if (!packuments[parts.escapedName]) { + packuments[parts.escapedName] = { + versions: {}, + } + addCacacheKey(pkey) + } + packuments[parts.escapedName].versions[ver] = { + dist: { + tarball: url, + }, + } + addCacacheKey(key) + cacacheContent[cacacheEntries[pkey].integrity] = { + data: Buffer.from(JSON.stringify(packuments[parts.escapedName])), + } +} + +const cacache = { + verify: (path) => { + return cacacheVerifyStats + }, + get: (path, key) => { + if (cacacheEntries[key] === undefined + || cacacheContent[cacacheEntries[key].integrity] === undefined) + throw new Error() + return cacacheContent[cacacheEntries[key].integrity] + }, + rm: { + entry: (path, key) => { + if (cacacheEntries[key] === undefined) + throw new Error() + delete cacacheEntries[key] + }, + content: (path, sha) => { + delete cacacheContent[sha] + }, + }, + ls: (path) => { + return cacacheEntries + }, +} + +const Cache = t.mock('../../../lib/commands/cache.js', { + cacache, + npmlog, + pacote, + rimraf, +}) + +const npm = mockNpm({ + cache: '/fake/path', + flatOptions: { force: false }, + config: { force: false }, + output: (msg) => { + outputOutput.push(msg) + }, + log: { + warn: (...args) => { + logOutput.push(['warn', ...args]) + }, + }, +}) +const cache = new Cache(npm) + +t.test('cache no args', async t => { + await t.rejects( + cache.exec([]), + { code: 'EUSAGE' }, + 'should throw usage instructions' + ) +}) + +t.test('cache clean', async t => { + await t.rejects( + cache.exec(['clean']), + 'the npm cache self-heals', + 'should throw warning' + ) +}) + +t.test('cache clean (force)', async t => { + npm.config.set('force', true) + npm.flatOptions.force = true + t.teardown(() => { + rimrafPath = '' + npm.config.force = false + npm.flatOptions.force = false + }) + + await cache.exec(['clear']) + t.equal(rimrafPath, path.join(npm.cache, '_cacache')) +}) + +t.test('cache add no arg', async t => { + t.teardown(() => { + logOutput = [] + }) + + await t.rejects( + cache.exec(['add']), + { + code: 'EUSAGE', + message: 'Usage: First argument to `add` is required', + }, + 'throws usage error' + ) + t.strictSame(logOutput, [ + ['silly', 'cache add', 'args', []], + ], 'logs correctly') +}) + +t.test('cache add pkg only', async t => { + t.teardown(() => { + logOutput = [] + tarballStreamSpec = '' + tarballStreamOpts = {} + }) + + await cache.exec(['add', 'mypkg']) + t.strictSame(logOutput, [ + ['silly', 'cache add', 'args', ['mypkg']], + ['silly', 'cache add', 'spec', 'mypkg'], + ], 'logs correctly') + t.equal(tarballStreamSpec, 'mypkg', 'passes the correct spec to pacote') + t.same(tarballStreamOpts, npm.flatOptions, 'passes the correct options to pacote') +}) + +t.test('cache add multiple pkgs', async t => { + t.teardown(() => { + outputOutput = [] + tarballStreamSpec = '' + tarballStreamOpts = {} + }) + + await cache.exec(['add', 'mypkg', 'anotherpkg']) + t.strictSame(logOutput, [ + ['silly', 'cache add', 'args', ['mypkg', 'anotherpkg']], + ['silly', 'cache add', 'spec', 'mypkg'], + ['silly', 'cache add', 'spec', 'anotherpkg'], + ], 'logs correctly') + t.equal(tarballStreamSpec, 'anotherpkg', 'passes the correct spec to pacote') + t.same(tarballStreamOpts, npm.flatOptions, 'passes the correct options to pacote') +}) + +t.test('cache ls', async t => { + t.teardown(() => { + outputOutput = [] + logOutput = [] + }) + setupCacacheFixture() + await cache.exec(['ls']) + t.strictSame(outputOutput, [ + 'make-fetch-happen:request-cache:https://registry.npmjs.org/@fritzy/staydown/-/@fritzy/staydown-3.1.1.tgz', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/@fritzy%2fstaydown', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar/npm-expansion/-/@gar/npm-expansion-2.1.0.tgz', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar/npm-expansion/-/@gar/npm-expansion-3.0.0-beta.tgz', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar%2fnpm-expansion', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/ape-ecs', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/ape-ecs/-/ape-ecs-2.1.7.tgz', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted/-/corrupted-3.1.0.tgz', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/foo', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/foo/-/foo-1.2.3-beta.tgz', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist/-/missing-dist-23.0.0.tgz', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version/-/missing-version-16.2.0.tgz', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/npm', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/npm/-/npm-1.2.0.tgz', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz', + 'make-fetch-happen:request-cache:https://somerepo.github.org/aabbcc/14', + 'make-fetch-happen:request-cache:https://somerepo.github.org/extemporaneously', + ]) +}) + +t.test('cache ls pkgs', async t => { + t.teardown(() => { + outputOutput = [] + }) + await cache.exec(['ls', 'webpack@>4.44.1', 'npm']) + t.strictSame(outputOutput, [ + 'make-fetch-happen:request-cache:https://registry.npmjs.org/npm', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/npm/-/npm-1.2.0.tgz', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz', + ]) +}) + +t.test('cache ls special', async t => { + t.teardown(() => { + outputOutput = [] + }) + await cache.exec(['ls', 'foo@1.2.3-beta']) + t.strictSame(outputOutput, [ + 'make-fetch-happen:request-cache:https://registry.npmjs.org/foo', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/foo/-/foo-1.2.3-beta.tgz', + ]) +}) + +t.test('cache ls nonpublic registry', async t => { + t.teardown(() => { + outputOutput = [] + }) + await cache.exec(['ls', 'extemporaneously']) + t.strictSame(outputOutput, [ + 'make-fetch-happen:request-cache:https://somerepo.github.org/aabbcc/14', + 'make-fetch-happen:request-cache:https://somerepo.github.org/extemporaneously', + ]) +}) + +t.test('cache ls tagged', async t => { + t.teardown(() => { + outputOutput = [] + }) + await t.rejects( + cache.exec(['ls', 'webpack@latest']), + 'tagged package', + 'should throw warning' + ) +}) + +t.test('cache ls scoped and scoped slash', async t => { + t.teardown(() => { + outputOutput = [] + }) + await cache.exec(['ls', '@fritzy/staydown', '@gar/npm-expansion']) + t.strictSame(outputOutput, [ + 'make-fetch-happen:request-cache:https://registry.npmjs.org/@fritzy/staydown/-/@fritzy/staydown-3.1.1.tgz', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/@fritzy%2fstaydown', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar/npm-expansion/-/@gar/npm-expansion-2.1.0.tgz', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/@gar%2fnpm-expansion', + ]) +}) + +t.test('cache ls corrupted', async t => { + t.teardown(() => { + outputOutput = [] + }) + await cache.exec(['ls', 'corrupted']) + t.strictSame(outputOutput, [ + 'make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/corrupted/-/corrupted-3.1.0.tgz', + ]) +}) + +t.test('cache ls missing packument dist', async t => { + t.teardown(() => { + outputOutput = [] + }) + await cache.exec(['ls', 'missing-dist']) + t.strictSame(outputOutput, [ + 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-dist/-/missing-dist-23.0.0.tgz', + ]) +}) + +t.test('cache ls missing packument version not an object', async t => { + t.teardown(() => { + outputOutput = [] + }) + await cache.exec(['ls', 'missing-version']) + t.strictSame(outputOutput, [ + 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/missing-version/-/missing-version-16.2.0.tgz', + ]) +}) + +t.test('cache rm', async t => { + t.teardown(() => { + outputOutput = [] + }) + await cache.exec(['rm', + 'make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz']) + t.strictSame(outputOutput, [ + 'Deleted: make-fetch-happen:request-cache:https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz', + ]) +}) + +t.test('cache rm unfound', async t => { + t.teardown(() => { + outputOutput = [] + logOutput = [] + }) + await cache.exec(['rm', 'made-up-key']) + t.strictSame(logOutput, [ + ['warn', 'Not Found: made-up-key'], + ], 'logs correctly') +}) + +t.test('cache verify', async t => { + t.teardown(() => { + outputOutput = [] + }) + + await cache.exec(['verify']) + t.match(outputOutput, [ + `Cache verified and compressed (${path.join(npm.cache, '_cacache')})`, + 'Content verified: 1 (100 bytes)', + 'Index entries: 1', + 'Finished in 2s', + ], 'prints correct output') +}) + +t.test('cache verify w/ extra output', async t => { + npm.cache = `${process.env.HOME}/fake/path` + cacacheVerifyStats.badContentCount = 1 + cacacheVerifyStats.reclaimedCount = 2 + cacacheVerifyStats.reclaimedSize = 200 + cacacheVerifyStats.missingContent = 3 + t.teardown(() => { + npm.cache = '/fake/path' + outputOutput = [] + delete cacacheVerifyStats.badContentCount + delete cacacheVerifyStats.reclaimedCount + delete cacacheVerifyStats.reclaimedSize + delete cacacheVerifyStats.missingContent + }) + + await cache.exec(['check']) + t.match(outputOutput, [ + `Cache verified and compressed (~${path.join('/fake/path', '_cacache')})`, + 'Content verified: 1 (100 bytes)', + 'Corrupted content removed: 1', + 'Content garbage-collected: 2 (200 bytes)', + 'Missing content: 3', + 'Index entries: 1', + 'Finished in 2s', + ], 'prints correct output') +}) + +t.test('cache completion', async t => { + const { completion } = cache + + const testComp = (argv, expect) => { + return t.resolveMatch(completion({ conf: { argv: { remain: argv } } }), expect, argv.join(' ')) + } + + await Promise.all([ + testComp(['npm', 'cache'], ['add', 'clean', 'verify']), + testComp(['npm', 'cache', 'add'], []), + testComp(['npm', 'cache', 'clean'], []), + testComp(['npm', 'cache', 'verify'], []), + ]) +}) diff --git a/deps/npm/test/lib/ci.js b/deps/npm/test/lib/commands/ci.js similarity index 68% rename from deps/npm/test/lib/ci.js rename to deps/npm/test/lib/commands/ci.js index b6b2af9c111db6..8573b585a5f47b 100644 --- a/deps/npm/test/lib/ci.js +++ b/deps/npm/test/lib/commands/ci.js @@ -4,13 +4,13 @@ const readdir = util.promisify(fs.readdir) const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') -t.test('should ignore scripts with --ignore-scripts', (t) => { +t.test('should ignore scripts with --ignore-scripts', async t => { const SCRIPTS = [] let REIFY_CALLED = false - const CI = t.mock('../../lib/ci.js', { - '../../lib/utils/reify-finish.js': async () => {}, + const CI = t.mock('../../../lib/commands/ci.js', { + '../../../lib/utils/reify-finish.js': async () => {}, '@npmcli/run-script': ({ event }) => { SCRIPTS.push(event) }, @@ -32,16 +32,12 @@ t.test('should ignore scripts with --ignore-scripts', (t) => { }) const ci = new CI(npm) - ci.exec([], er => { - if (er) - throw er - t.equal(REIFY_CALLED, true, 'called reify') - t.strictSame(SCRIPTS, [], 'no scripts when running ci') - t.end() - }) + await ci.exec([]) + t.equal(REIFY_CALLED, true, 'called reify') + t.strictSame(SCRIPTS, [], 'no scripts when running ci') }) -t.test('should use Arborist and run-script', (t) => { +t.test('should use Arborist and run-script', async t => { const scripts = [ 'preinstall', 'install', @@ -87,8 +83,8 @@ t.test('should use Arborist and run-script', (t) => { const expectRimrafs = 3 let actualRimrafs = 0 - const CI = t.mock('../../lib/ci.js', { - '../../lib/utils/reify-finish.js': async () => {}, + const CI = t.mock('../../../lib/commands/ci.js', { + '../../../lib/utils/reify-finish.js': async () => {}, '@npmcli/run-script': opts => { t.match(opts, { event: scripts.shift() }) }, @@ -108,7 +104,7 @@ t.test('should use Arborist and run-script', (t) => { // callback is always last arg args.pop()() }, - '../../lib/utils/reify-output.js': function (arb) { + '../../../lib/utils/reify-output.js': function (arb) { t.ok(arb, 'gets arborist tree') }, }) @@ -121,27 +117,23 @@ t.test('should use Arborist and run-script', (t) => { }) const ci = new CI(npm) - ci.exec(null, er => { - if (er) - throw er - for (const [msg, result] of Object.entries(timers)) - t.notOk(result, `properly resolved ${msg} timer`) - t.match(timers, { 'npm-ci:rm': false }, 'saw the rimraf timer') - t.equal(actualRimrafs, expectRimrafs, 'removed the right number of things') - t.strictSame(scripts, [], 'called all scripts') - t.end() - }) + await ci.exec(null) + for (const [msg, result] of Object.entries(timers)) + t.notOk(result, `properly resolved ${msg} timer`) + t.match(timers, { 'npm-ci:rm': false }, 'saw the rimraf timer') + t.equal(actualRimrafs, expectRimrafs, 'removed the right number of things') + t.strictSame(scripts, [], 'called all scripts') }) -t.test('should pass flatOptions to Arborist.reify', (t) => { - const CI = t.mock('../../lib/ci.js', { - '../../lib/utils/reify-finish.js': async () => {}, +t.test('should pass flatOptions to Arborist.reify', async t => { + t.plan(1) + const CI = t.mock('../../../lib/commands/ci.js', { + '../../../lib/utils/reify-finish.js': async () => {}, '@npmcli/run-script': opts => {}, '@npmcli/arborist': function () { this.loadVirtual = () => Promise.resolve(true) this.reify = async (options) => { t.equal(options.production, true, 'should pass flatOptions to Arborist.reify') - t.end() } }, }) @@ -152,21 +144,18 @@ t.test('should pass flatOptions to Arborist.reify', (t) => { }, }) const ci = new CI(npm) - ci.exec(null, er => { - if (er) - throw er - }) + await ci.exec(null) }) -t.test('should throw if package-lock.json or npm-shrinkwrap missing', (t) => { +t.test('should throw if package-lock.json or npm-shrinkwrap missing', async t => { const testDir = t.testdir({ 'index.js': 'some contents', 'package.json': 'some info', }) - const CI = t.mock('../../lib/ci.js', { + const CI = t.mock('../../../lib/commands/ci.js', { '@npmcli/run-script': opts => {}, - '../../lib/utils/reify-finish.js': async () => {}, + '../../../lib/utils/reify-finish.js': async () => {}, npmlog: { verbose: () => { t.ok(true, 'log fn called') @@ -180,17 +169,17 @@ t.test('should throw if package-lock.json or npm-shrinkwrap missing', (t) => { }, }) const ci = new CI(npm) - ci.exec(null, (err, res) => { - t.match(err, /package-lock.json/, 'throws error when there is no package-lock') - t.notOk(res) - t.end() - }) + await t.rejects( + ci.exec(null), + /package-lock.json/, + 'throws error when there is no package-lock' + ) }) -t.test('should throw ECIGLOBAL', (t) => { - const CI = t.mock('../../lib/ci.js', { +t.test('should throw ECIGLOBAL', async t => { + const CI = t.mock('../../../lib/commands/ci.js', { '@npmcli/run-script': opts => {}, - '../../lib/utils/reify-finish.js': async () => {}, + '../../../lib/utils/reify-finish.js': async () => {}, }) const npm = mockNpm({ prefix: 'foo', @@ -199,23 +188,24 @@ t.test('should throw ECIGLOBAL', (t) => { }, }) const ci = new CI(npm) - ci.exec(null, (err, res) => { - t.equal(err.code, 'ECIGLOBAL', 'throws error with global packages') - t.notOk(res) - t.end() - }) + await t.rejects( + ci.exec(null), + { code: 'ECIGLOBAL' }, + 'throws error with global packages' + ) }) -t.test('should remove existing node_modules before installing', (t) => { +t.test('should remove existing node_modules before installing', async t => { + t.plan(2) const testDir = t.testdir({ node_modules: { 'some-file': 'some contents', }, }) - const CI = t.mock('../../lib/ci.js', { + const CI = t.mock('../../../lib/commands/ci.js', { '@npmcli/run-script': opts => {}, - '../../lib/utils/reify-finish.js': async () => {}, + '../../../lib/utils/reify-finish.js': async () => {}, '@npmcli/arborist': function () { this.loadVirtual = () => Promise.resolve(true) this.reify = async (options) => { @@ -224,7 +214,6 @@ t.test('should remove existing node_modules before installing', (t) => { const contents = await readdir(testDir) const nodeModules = contents.filter((path) => path.startsWith('node_modules')) t.same(nodeModules, ['node_modules'], 'should only have the node_modules directory') - t.end() } }, }) @@ -237,8 +226,5 @@ t.test('should remove existing node_modules before installing', (t) => { }) const ci = new CI(npm) - ci.exec(null, er => { - if (er) - throw er - }) + await ci.exec(null) }) diff --git a/deps/npm/test/lib/completion.js b/deps/npm/test/lib/commands/completion.js similarity index 52% rename from deps/npm/test/lib/completion.js rename to deps/npm/test/lib/commands/completion.js index 4f7d4a5fd6e388..7fdee0627273e1 100644 --- a/deps/npm/test/lib/completion.js +++ b/deps/npm/test/lib/commands/completion.js @@ -2,7 +2,7 @@ const t = require('tap') const fs = require('fs') const path = require('path') -const completionScript = fs.readFileSync(path.resolve(__dirname, '../../lib/utils/completion.sh'), { encoding: 'utf8' }).replace(/^#!.*?\n/, '') +const completionScript = fs.readFileSync(path.resolve(__dirname, '../../../lib/utils/completion.sh'), { encoding: 'utf8' }).replace(/^#!.*?\n/, '') const output = [] const npmConfig = {} @@ -18,32 +18,34 @@ const npm = { delete npmConfig[key] }, }, - commands: { - completion: { - completion: () => [['>>', '~/.bashrc']], - }, - adduser: {}, - access: { - completion: () => { - if (accessCompletionError) - throw new Error('access completion failed') - - return ['public', 'restricted'] + cmd: (cmd) => { + return ({ + completion: { + completion: () => [['>>', '~/.bashrc']], }, - }, - promise: { - completion: () => Promise.resolve(['resolved_completion_promise']), - }, - donothing: { - completion: () => { - return null + adduser: {}, + access: { + completion: () => { + if (accessCompletionError) + throw new Error('access completion failed') + + return ['public', 'restricted'] + }, }, - }, - driveaboat: { - completion: () => { - return ' fast' + promise: { + completion: () => Promise.resolve(['resolved_completion_promise']), }, - }, + donothing: { + completion: () => { + return null + }, + }, + driveaboat: { + completion: () => { + return ' fast' + }, + }, + }[cmd]) }, output: (line) => { output.push(line) @@ -64,7 +66,7 @@ const cmdList = { // only include a subset so that the snapshots aren't huge and // don't change when we add/remove config definitions. -const definitions = require('../../lib/utils/config/definitions.js') +const definitions = require('../../../lib/utils/config/definitions.js') const config = { definitions: { global: definitions.global, @@ -80,11 +82,11 @@ const deref = (cmd) => { return cmd } -const Completion = t.mock('../../lib/completion.js', { - '../../lib/utils/cmd-list.js': cmdList, - '../../lib/utils/config/index.js': config, - '../../lib/utils/deref-command.js': deref, - '../../lib/utils/is-windows-shell.js': false, +const Completion = t.mock('../../../lib/commands/completion.js', { + '../../../lib/utils/cmd-list.js': cmdList, + '../../../lib/utils/config/index.js': config, + '../../../lib/utils/deref-command.js': deref, + '../../../lib/utils/is-windows-shell.js': false, }) const completion = new Completion(npm) @@ -126,23 +128,22 @@ t.test('completion completion wrong word count', async t => { t.end() }) -t.test('completion errors in windows without bash', t => { - const Compl = t.mock('../../lib/completion.js', { - '../../lib/utils/is-windows-shell.js': true, +t.test('completion errors in windows without bash', async t => { + const Compl = t.mock('../../../lib/commands/completion.js', { + '../../../lib/utils/is-windows-shell.js': true, }) const compl = new Compl() - compl.exec({}, (err) => { - t.match(err, { - code: 'ENOTSUP', + await t.rejects( + compl.exec({}), + { code: 'ENOTSUP', message: /completion supported only in MINGW/, + }, 'returns the correct error') - t.end() - }) }) -t.test('dump script when completion is not being attempted', t => { +t.test('dump script when completion is not being attempted', async t => { const _write = process.stdout.write const _on = process.stdout.on t.teardown(() => { @@ -166,16 +167,12 @@ t.test('dump script when completion is not being attempted', t => { }) } - completion.exec({}, (err) => { - if (err) - throw err + await completion.exec({}) - t.equal(data, completionScript, 'wrote the completion script') - t.end() - }) + t.equal(data, completionScript, 'wrote the completion script') }) -t.test('dump script exits correctly when EPIPE is emitted on stdout', t => { +t.test('dump script exits correctly when EPIPE is emitted on stdout', async t => { const _write = process.stdout.write const _on = process.stdout.on t.teardown(() => { @@ -199,47 +196,47 @@ t.test('dump script exits correctly when EPIPE is emitted on stdout', t => { }) } - completion.exec({}, (err) => { - if (err) - throw err - - t.equal(data, completionScript, 'wrote the completion script') - t.end() - }) + await completion.exec({}) + t.equal(data, completionScript, 'wrote the completion script') }) -t.test('non EPIPE errors cause failures', t => { - const _write = process.stdout.write - const _on = process.stdout.on - t.teardown(() => { - process.stdout.write = _write - process.stdout.on = _on - }) - - let errorHandler - process.stdout.on = (event, handler) => { - errorHandler = handler - process.stdout.on = _on - } - - let data - process.stdout.write = (chunk, callback) => { - data = chunk - process.stdout.write = _write - process.nextTick(() => { - errorHandler({ errno: 'ESOMETHINGELSE' }) - callback() - }) - } - - completion.exec({}, (err) => { - t.equal(err.errno, 'ESOMETHINGELSE', 'propagated error') - t.equal(data, completionScript, 'wrote the completion script') - t.end() - }) -}) - -t.test('completion completes single command name', t => { +// This test was only working by coincidence before, when we switch to full +// async/await the race condition now makes it impossible to test. The root of +// the problem is that if we override stdout.write then other things interfere +// during testing. +// t.test('non EPIPE errors cause failures', async t => { +// const _write = process.stdout.write +// const _on = process.stdout.on +// t.teardown(() => { +// process.stdout.write = _write +// process.stdout.on = _on +// }) + +// let errorHandler +// process.stdout.on = (event, handler) => { +// errorHandler = handler +// process.stdout.on = _on +// } + +// let data +// process.stdout.write = (chunk, callback) => { +// data = chunk +// process.stdout.write = _write +// process.nextTick(() => { +// errorHandler({ errno: 'ESOMETHINGELSE' }) +// callback() +// }) +// } + +// await t.rejects( +// completion.exec([]), +// { errno: 'ESOMETHINGELSE' }, +// 'propagated error' +// ) +// t.equal(data, completionScript, 'wrote the completion script') +// }) + +t.test('completion completes single command name', async t => { process.env.COMP_CWORD = 1 process.env.COMP_LINE = 'npm c' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -252,16 +249,11 @@ t.test('completion completes single command name', t => { output.length = 0 }) - completion.exec(['npm', 'c'], (err, res) => { - if (err) - throw err - - t.strictSame(output, ['completion'], 'correctly completed a command name') - t.end() - }) + await completion.exec(['npm', 'c']) + t.strictSame(output, ['completion'], 'correctly completed a command name') }) -t.test('completion completes command names', t => { +t.test('completion completes command names', async t => { process.env.COMP_CWORD = 1 process.env.COMP_LINE = 'npm a' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -274,16 +266,11 @@ t.test('completion completes command names', t => { output.length = 0 }) - completion.exec(['npm', 'a'], (err, res) => { - if (err) - throw err - - t.strictSame(output, [['access', 'adduser'].join('\n')], 'correctly completed a command name') - t.end() - }) + await completion.exec(['npm', 'a']) + t.strictSame(output, [['access', 'adduser'].join('\n')], 'correctly completed a command name') }) -t.test('completion of invalid command name does nothing', t => { +t.test('completion of invalid command name does nothing', async t => { process.env.COMP_CWORD = 1 process.env.COMP_LINE = 'npm compute' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -296,16 +283,11 @@ t.test('completion of invalid command name does nothing', t => { output.length = 0 }) - completion.exec(['npm', 'compute'], (err, res) => { - if (err) - throw err - - t.strictSame(output, [], 'returns no results') - t.end() - }) + await completion.exec(['npm', 'compute']) + t.strictSame(output, [], 'returns no results') }) -t.test('handles async completion function', t => { +t.test('handles async completion function', async t => { process.env.COMP_CWORD = 2 process.env.COMP_LINE = 'npm promise' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -318,23 +300,19 @@ t.test('handles async completion function', t => { output.length = 0 }) - completion.exec(['npm', 'promise', ''], (err, res) => { - if (err) - throw err + await completion.exec(['npm', 'promise', '']) - t.strictSame(npmConfig, { - argv: { - remain: ['npm', 'promise'], - cooked: ['npm', 'promise'], - original: ['npm', 'promise'], - }, - }, 'applies command config appropriately') - t.strictSame(output, ['resolved_completion_promise'], 'resolves async completion results') - t.end() - }) + t.strictSame(npmConfig, { + argv: { + remain: ['npm', 'promise'], + cooked: ['npm', 'promise'], + original: ['npm', 'promise'], + }, + }, 'applies command config appropriately') + t.strictSame(output, ['resolved_completion_promise'], 'resolves async completion results') }) -t.test('completion triggers command completions', t => { +t.test('completion triggers command completions', async t => { process.env.COMP_CWORD = 2 process.env.COMP_LINE = 'npm access ' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -347,23 +325,19 @@ t.test('completion triggers command completions', t => { output.length = 0 }) - completion.exec(['npm', 'access', ''], (err, res) => { - if (err) - throw err + await completion.exec(['npm', 'access', '']) - t.strictSame(npmConfig, { - argv: { - remain: ['npm', 'access'], - cooked: ['npm', 'access'], - original: ['npm', 'access'], - }, - }, 'applies command config appropriately') - t.strictSame(output, [['public', 'restricted'].join('\n')], 'correctly completed a subcommand name') - t.end() - }) + t.strictSame(npmConfig, { + argv: { + remain: ['npm', 'access'], + cooked: ['npm', 'access'], + original: ['npm', 'access'], + }, + }, 'applies command config appropriately') + t.strictSame(output, [['public', 'restricted'].join('\n')], 'correctly completed a subcommand name') }) -t.test('completion triggers filtered command completions', t => { +t.test('completion triggers filtered command completions', async t => { process.env.COMP_CWORD = 2 process.env.COMP_LINE = 'npm access p' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -376,23 +350,19 @@ t.test('completion triggers filtered command completions', t => { output.length = 0 }) - completion.exec(['npm', 'access', 'p'], (err, res) => { - if (err) - throw err + await completion.exec(['npm', 'access', 'p']) - t.strictSame(npmConfig, { - argv: { - remain: ['npm', 'access'], - cooked: ['npm', 'access'], - original: ['npm', 'access'], - }, - }, 'applies command config appropriately') - t.strictSame(output, ['public'], 'correctly completed a subcommand name') - t.end() - }) + t.strictSame(npmConfig, { + argv: { + remain: ['npm', 'access'], + cooked: ['npm', 'access'], + original: ['npm', 'access'], + }, + }, 'applies command config appropriately') + t.strictSame(output, ['public'], 'correctly completed a subcommand name') }) -t.test('completions for commands that return nested arrays are joined', t => { +t.test('completions for commands that return nested arrays are joined', async t => { process.env.COMP_CWORD = 2 process.env.COMP_LINE = 'npm completion ' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -405,23 +375,19 @@ t.test('completions for commands that return nested arrays are joined', t => { output.length = 0 }) - completion.exec(['npm', 'completion', ''], (err, res) => { - if (err) - throw err + await completion.exec(['npm', 'completion', '']) - t.strictSame(npmConfig, { - argv: { - remain: ['npm', 'completion'], - cooked: ['npm', 'completion'], - original: ['npm', 'completion'], - }, - }, 'applies command config appropriately') - t.strictSame(output, ['>> ~/.bashrc'], 'joins nested arrays') - t.end() - }) + t.strictSame(npmConfig, { + argv: { + remain: ['npm', 'completion'], + cooked: ['npm', 'completion'], + original: ['npm', 'completion'], + }, + }, 'applies command config appropriately') + t.strictSame(output, ['>> ~/.bashrc'], 'joins nested arrays') }) -t.test('completions for commands that return nothing work correctly', t => { +t.test('completions for commands that return nothing work correctly', async t => { process.env.COMP_CWORD = 2 process.env.COMP_LINE = 'npm donothing ' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -434,23 +400,19 @@ t.test('completions for commands that return nothing work correctly', t => { output.length = 0 }) - completion.exec(['npm', 'donothing', ''], (err, res) => { - if (err) - throw err + await completion.exec(['npm', 'donothing', '']) - t.strictSame(npmConfig, { - argv: { - remain: ['npm', 'donothing'], - cooked: ['npm', 'donothing'], - original: ['npm', 'donothing'], - }, - }, 'applies command config appropriately') - t.strictSame(output, [], 'returns nothing') - t.end() - }) + t.strictSame(npmConfig, { + argv: { + remain: ['npm', 'donothing'], + cooked: ['npm', 'donothing'], + original: ['npm', 'donothing'], + }, + }, 'applies command config appropriately') + t.strictSame(output, [], 'returns nothing') }) -t.test('completions for commands that return a single item work correctly', t => { +t.test('completions for commands that return a single item work correctly', async t => { process.env.COMP_CWORD = 2 process.env.COMP_LINE = 'npm driveaboat ' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -463,23 +425,18 @@ t.test('completions for commands that return a single item work correctly', t => output.length = 0 }) - completion.exec(['npm', 'driveaboat', ''], (err, res) => { - if (err) - throw err - - t.strictSame(npmConfig, { - argv: { - remain: ['npm', 'driveaboat'], - cooked: ['npm', 'driveaboat'], - original: ['npm', 'driveaboat'], - }, - }, 'applies command config appropriately') - t.strictSame(output, ['\' fast\''], 'returns the correctly escaped string') - t.end() - }) + await completion.exec(['npm', 'driveaboat', '']) + t.strictSame(npmConfig, { + argv: { + remain: ['npm', 'driveaboat'], + cooked: ['npm', 'driveaboat'], + original: ['npm', 'driveaboat'], + }, + }, 'applies command config appropriately') + t.strictSame(output, ['\' fast\''], 'returns the correctly escaped string') }) -t.test('command completion for commands with no completion return no results', t => { +t.test('command completion for commands with no completion return no results', async t => { process.env.COMP_CWORD = 2 process.env.COMP_LINE = 'npm adduser ' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -493,23 +450,18 @@ t.test('command completion for commands with no completion return no results', t }) // quotes around adduser are to ensure coverage when unescaping commands - completion.exec(['npm', '\'adduser\'', ''], (err, res) => { - if (err) - throw err - - t.strictSame(npmConfig, { - argv: { - remain: ['npm', 'adduser'], - cooked: ['npm', 'adduser'], - original: ['npm', 'adduser'], - }, - }, 'applies command config appropriately') - t.strictSame(output, [], 'correctly completed a subcommand name') - t.end() - }) + await completion.exec(['npm', '\'adduser\'', '']) + t.strictSame(npmConfig, { + argv: { + remain: ['npm', 'adduser'], + cooked: ['npm', 'adduser'], + original: ['npm', 'adduser'], + }, + }, 'applies command config appropriately') + t.strictSame(output, [], 'correctly completed a subcommand name') }) -t.test('command completion errors propagate', t => { +t.test('command completion errors propagate', async t => { process.env.COMP_CWORD = 2 process.env.COMP_LINE = 'npm access ' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -524,21 +476,22 @@ t.test('command completion errors propagate', t => { accessCompletionError = false }) - completion.exec(['npm', 'access', ''], (err, res) => { - t.match(err, /access completion failed/, 'catches the appropriate error') - t.strictSame(npmConfig, { - argv: { - remain: ['npm', 'access'], - cooked: ['npm', 'access'], - original: ['npm', 'access'], - }, - }, 'applies command config appropriately') - t.strictSame(output, [], 'returns no results') - t.end() - }) + await t.rejects( + completion.exec(['npm', 'access', '']), + /access completion failed/, + 'catches the appropriate error' + ) + t.strictSame(npmConfig, { + argv: { + remain: ['npm', 'access'], + cooked: ['npm', 'access'], + original: ['npm', 'access'], + }, + }, 'applies command config appropriately') + t.strictSame(output, [], 'returns no results') }) -t.test('completion can complete flags', t => { +t.test('completion can complete flags', async t => { process.env.COMP_CWORD = 2 process.env.COMP_LINE = 'npm install --' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -551,17 +504,13 @@ t.test('completion can complete flags', t => { output.length = 0 }) - completion.exec(['npm', 'install', '--'], (err, res) => { - if (err) - throw err + await completion.exec(['npm', 'install', '--']) - t.strictSame(npmConfig, {}, 'does not apply command config') - t.strictSame(output, [['--global', '--browser', '--registry', '--reg', '--no-global', '--no-browser'].join('\n')], 'correctly completes flag names') - t.end() - }) + t.strictSame(npmConfig, {}, 'does not apply command config') + t.strictSame(output, [['--global', '--browser', '--registry', '--reg', '--no-global', '--no-browser'].join('\n')], 'correctly completes flag names') }) -t.test('double dashes escape from flag completion', t => { +t.test('double dashes escape from flag completion', async t => { process.env.COMP_CWORD = 2 process.env.COMP_LINE = 'npm -- install --' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -574,17 +523,13 @@ t.test('double dashes escape from flag completion', t => { output.length = 0 }) - completion.exec(['npm', '--', 'install', '--'], (err, res) => { - if (err) - throw err + await completion.exec(['npm', '--', 'install', '--']) - t.strictSame(npmConfig, {}, 'does not apply command config') - t.strictSame(output, [['access', 'adduser', 'completion', 'login'].join('\n')], 'correctly completes flag names') - t.end() - }) + t.strictSame(npmConfig, {}, 'does not apply command config') + t.strictSame(output, [['access', 'adduser', 'completion', 'login'].join('\n')], 'correctly completes flag names') }) -t.test('completion cannot complete options that take a value in mid-command', t => { +t.test('completion cannot complete options that take a value in mid-command', async t => { process.env.COMP_CWORD = 2 process.env.COMP_LINE = 'npm --registry install' process.env.COMP_POINT = process.env.COMP_LINE.length @@ -597,12 +542,7 @@ t.test('completion cannot complete options that take a value in mid-command', t output.length = 0 }) - completion.exec(['npm', '--registry', 'install'], (err, res) => { - if (err) - throw err - - t.strictSame(npmConfig, {}, 'does not apply command config') - t.strictSame(output, [], 'does not try to complete option arguments in the middle of a command') - t.end() - }) + await completion.exec(['npm', '--registry', 'install']) + t.strictSame(npmConfig, {}, 'does not apply command config') + t.strictSame(output, [], 'does not try to complete option arguments in the middle of a command') }) diff --git a/deps/npm/test/lib/config.js b/deps/npm/test/lib/commands/config.js similarity index 99% rename from deps/npm/test/lib/config.js rename to deps/npm/test/lib/commands/config.js index ba47fa11d0bbc7..56ec7fd91630e0 100644 --- a/deps/npm/test/lib/config.js +++ b/deps/npm/test/lib/commands/config.js @@ -8,7 +8,7 @@ spawk.preventUnmatched() const readFile = promisify(fs.readFile) -const Sandbox = require('../fixtures/sandbox.js') +const Sandbox = require('../../fixtures/sandbox.js') t.test('config no args', async (t) => { const sandbox = new Sandbox(t) diff --git a/deps/npm/test/lib/dedupe.js b/deps/npm/test/lib/commands/dedupe.js similarity index 78% rename from deps/npm/test/lib/dedupe.js rename to deps/npm/test/lib/commands/dedupe.js index 30f8a380e8ea35..8fc0be06181e0b 100644 --- a/deps/npm/test/lib/dedupe.js +++ b/deps/npm/test/lib/commands/dedupe.js @@ -1,12 +1,13 @@ const t = require('tap') -const { real: mockNpm } = require('../fixtures/mock-npm') +const { real: mockNpm } = require('../../fixtures/mock-npm') t.test('should throw in global mode', async (t) => { - const { npm, command } = mockNpm(t) + const { Npm } = mockNpm(t) + const npm = new Npm() await npm.load() npm.config.set('global', true) t.rejects( - command('dedupe'), + npm.exec('dedupe', []), { code: 'EDEDUPEGLOBAL' }, 'throws EDEDUPEGLOBALE' ) @@ -14,7 +15,7 @@ t.test('should throw in global mode', async (t) => { t.test('should remove dupes using Arborist', async (t) => { t.plan(5) - const { npm, command } = mockNpm(t, { + const { Npm } = mockNpm(t, { '@npmcli/arborist': function (args) { t.ok(args, 'gets options object') t.ok(args.path, 'gets path option') @@ -27,15 +28,16 @@ t.test('should remove dupes using Arborist', async (t) => { t.ok(arb, 'gets arborist tree') }, }) + const npm = new Npm() await npm.load() npm.config.set('prefix', 'foo') npm.config.set('dry-run', 'true') - await command('dedupe') + await npm.exec('dedupe', []) }) t.test('should remove dupes using Arborist - no arguments', async (t) => { t.plan(1) - const { npm, command } = mockNpm(t, { + const { Npm } = mockNpm(t, { '@npmcli/arborist': function (args) { t.ok(args.dryRun, 'gets dryRun from config') this.dedupe = () => {} @@ -43,8 +45,9 @@ t.test('should remove dupes using Arborist - no arguments', async (t) => { '../../lib/utils/reify-output.js': () => {}, '../../lib/utils/reify-finish.js': () => {}, }) + const npm = new Npm() await npm.load() npm.config.set('prefix', 'foo') npm.config.set('dry-run', true) - await command('dedupe') + await npm.exec('dedupe', []) }) diff --git a/deps/npm/test/lib/commands/deprecate.js b/deps/npm/test/lib/commands/deprecate.js new file mode 100644 index 00000000000000..02256d08edb847 --- /dev/null +++ b/deps/npm/test/lib/commands/deprecate.js @@ -0,0 +1,135 @@ +const t = require('tap') + +let getIdentityImpl = () => 'someperson' +let npmFetchBody = null + +const npmFetch = async (uri, opts) => { + npmFetchBody = opts.body +} + +npmFetch.json = async (uri, opts) => { + return { + versions: { + '1.0.0': {}, + '1.0.1': {}, + '1.0.1-pre': {}, + }, + } +} + +const Deprecate = t.mock('../../../lib/commands/deprecate.js', { + '../../../lib/utils/get-identity.js': async () => getIdentityImpl(), + '../../../lib/utils/otplease.js': async (opts, fn) => fn(opts), + libnpmaccess: { + lsPackages: async () => ({ foo: 'write', bar: 'write', baz: 'write', buzz: 'read' }), + }, + 'npm-registry-fetch': npmFetch, +}) + +const deprecate = new Deprecate({ + flatOptions: { registry: 'https://registry.npmjs.org' }, +}) + +t.test('completion', async t => { + const defaultIdentityImpl = getIdentityImpl + t.teardown(() => { + getIdentityImpl = defaultIdentityImpl + }) + + const testComp = async (argv, expect) => { + const res = + await deprecate.completion({ conf: { argv: { remain: argv } } }) + t.strictSame(res, expect, `completion: ${argv}`) + } + + await Promise.all([ + testComp([], ['foo', 'bar', 'baz']), + testComp(['b'], ['bar', 'baz']), + testComp(['fo'], ['foo']), + testComp(['g'], []), + testComp(['foo', 'something'], []), + ]) + + getIdentityImpl = () => { + throw new Error('deprecate test failure') + } + + t.rejects(testComp([], []), { message: 'deprecate test failure' }) +}) + +t.test('no args', async t => { + await t.rejects( + deprecate.exec([]), + /Usage:/, + 'logs usage' + ) +}) + +t.test('only one arg', async t => { + await t.rejects( + deprecate.exec(['foo']), + /Usage:/, + 'logs usage' + ) +}) + +t.test('invalid semver range', async t => { + await t.rejects( + deprecate.exec(['foo@notaversion', 'this will fail']), + /invalid version range/, + 'logs semver error' + ) +}) + +t.test('undeprecate', async t => { + await deprecate.exec(['foo', '']) + t.match(npmFetchBody, { + versions: { + '1.0.0': { deprecated: '' }, + '1.0.1': { deprecated: '' }, + '1.0.1-pre': { deprecated: '' }, + }, + }, 'undeprecates everything') +}) + +t.test('deprecates given range', async t => { + t.teardown(() => { + npmFetchBody = null + }) + + await deprecate.exec(['foo@1.0.0', 'this version is deprecated']) + t.match(npmFetchBody, { + versions: { + '1.0.0': { + deprecated: 'this version is deprecated', + }, + '1.0.1': { + // the undefined here is necessary to ensure that we absolutely + // did not assign this property + deprecated: undefined, + }, + }, + }) +}) + +t.test('deprecates all versions when no range is specified', async t => { + t.teardown(() => { + npmFetchBody = null + }) + + await deprecate.exec(['foo', 'this version is deprecated']) + + t.match(npmFetchBody, { + versions: { + '1.0.0': { + deprecated: 'this version is deprecated', + }, + '1.0.1': { + deprecated: 'this version is deprecated', + }, + '1.0.1-pre': { + deprecated: 'this version is deprecated', + }, + }, + }) +}) diff --git a/deps/npm/test/lib/diff.js b/deps/npm/test/lib/commands/diff.js similarity index 76% rename from deps/npm/test/lib/diff.js rename to deps/npm/test/lib/commands/diff.js index fcba802d93b87e..9b3e2aca513293 100644 --- a/deps/npm/test/lib/diff.js +++ b/deps/npm/test/lib/commands/diff.js @@ -1,6 +1,6 @@ const t = require('tap') const { resolve, join } = require('path') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') const noop = () => null let libnpmdiff = noop @@ -34,7 +34,7 @@ const mocks = { npmlog: { info: noop, verbose: noop }, libnpmdiff: (...args) => libnpmdiff(...args), 'npm-registry-fetch': async () => ({}), - '../../lib/utils/usage.js': () => 'usage instructions', + '../../../lib/utils/usage.js': () => 'usage instructions', } t.afterEach(() => { @@ -56,11 +56,11 @@ t.afterEach(() => { diff.top = undefined }) -const Diff = t.mock('../../lib/diff.js', mocks) +const Diff = t.mock('../../../lib/commands/diff.js', mocks) const diff = new Diff(npm) t.test('no args', t => { - t.test('in a project dir', t => { + t.test('in a project dir', async t => { t.plan(3) libnpmdiff = async ([a, b], opts) => { @@ -70,47 +70,37 @@ t.test('no args', t => { } npm.prefix = fooPath - diff.exec([], err => { - if (err) - throw err - t.end() - }) + await diff.exec([]) }) - t.test('no args, missing package.json name in cwd', t => { + t.test('no args, missing package.json name in cwd', async t => { const path = t.testdir({}) npm.prefix = path - diff.exec([], err => { - t.match( - err, - /Needs multiple arguments to compare or run from a project dir./, - 'should throw EDIFF error msg' - ) - t.end() - }) + await t.rejects( + diff.exec([]), + /Needs multiple arguments to compare or run from a project dir./, + 'should throw EDIFF error msg' + ) }) - t.test('no args, bad package.json in cwd', t => { + t.test('no args, bad package.json in cwd', async t => { const path = t.testdir({ 'package.json': '{invalid"json', }) npm.prefix = path - diff.exec([], err => { - t.match( - err, - /Needs multiple arguments to compare or run from a project dir./, - 'should throw EDIFF error msg' - ) - t.end() - }) + await t.rejects( + diff.exec([]), + /Needs multiple arguments to compare or run from a project dir./, + 'should throw EDIFF error msg' + ) }) t.end() }) t.test('single arg', t => { - t.test('spec using cwd package name', t => { + t.test('spec using cwd package name', async t => { t.plan(3) libnpmdiff = async ([a, b], opts) => { @@ -121,29 +111,22 @@ t.test('single arg', t => { config.diff = ['foo@1.0.0'] npm.prefix = fooPath - diff.exec([], err => { - if (err) - throw err - t.end() - }) + await diff.exec([]) }) - t.test('unknown spec, no package.json', t => { + t.test('unknown spec, no package.json', async t => { const path = t.testdir({}) config.diff = ['foo@1.0.0'] npm.prefix = path - diff.exec([], err => { - t.match( - err, - /Needs multiple arguments to compare or run from a project dir./, - 'should throw usage error' - ) - t.end() - }) + await t.rejects( + diff.exec([]), + /Needs multiple arguments to compare or run from a project dir./, + 'should throw usage error' + ) }) - t.test('spec using semver range', t => { + t.test('spec using semver range', async t => { t.plan(3) libnpmdiff = async ([a, b], opts) => { @@ -153,13 +136,10 @@ t.test('single arg', t => { } config.diff = ['foo@~1.0.0'] - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('version', t => { + t.test('version', async t => { t.plan(3) libnpmdiff = async ([a, b], opts) => { @@ -169,27 +149,21 @@ t.test('single arg', t => { } config.diff = ['2.1.4'] - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('version, no package.json', t => { + t.test('version, no package.json', async t => { const path = t.testdir({}) npm.prefix = path config.diff = ['2.1.4'] - diff.exec([], err => { - t.match( - err, - /Needs multiple arguments to compare or run from a project dir./, - 'should throw an error message explaining usage' - ) - t.end() - }) + await t.rejects( + diff.exec([]), + /Needs multiple arguments to compare or run from a project dir./, + 'should throw an error message explaining usage' + ) }) - t.test('version, filtering by files', t => { + t.test('version, filtering by files', async t => { t.plan(3) libnpmdiff = async ([a, b], opts) => { @@ -205,13 +179,10 @@ t.test('single arg', t => { } config.diff = ['2.1.4'] - diff.exec(['./foo.js', './bar.js'], err => { - if (err) - throw err - }) + await diff.exec(['./foo.js', './bar.js']) }) - t.test('spec is not a dep', t => { + t.test('spec is not a dep', async t => { t.plan(2) const path = t.testdir({ @@ -229,13 +200,10 @@ t.test('single arg', t => { config.diff = ['bar@1.0.0'] npm.prefix = path - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('unknown package name', t => { + t.test('unknown package name', async t => { t.plan(3) const path = t.testdir({ @@ -255,28 +223,22 @@ t.test('single arg', t => { config.diff = ['simple-output'] npm.prefix = path - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('unknown package name, no package.json', t => { + t.test('unknown package name, no package.json', async t => { const path = t.testdir({}) config.diff = ['bar'] npm.prefix = path - diff.exec([], err => { - t.match( - err, - /Needs multiple arguments to compare or run from a project dir./, - 'should throw usage error' - ) - t.end() - }) + await t.rejects( + diff.exec([]), + /Needs multiple arguments to compare or run from a project dir./, + 'should throw usage error' + ) }) - t.test('transform single direct dep name into spec comparison', t => { + t.test('transform single direct dep name into spec comparison', async t => { t.plan(4) const path = t.testdir({ @@ -299,7 +261,7 @@ t.test('single arg', t => { config.diff = ['bar'] npm.prefix = path - const Diff = t.mock('../../lib/diff.js', { + const Diff = t.mock('../../../lib/commands/diff.js', { ...mocks, pacote: { packument: (spec) => { @@ -317,13 +279,10 @@ t.test('single arg', t => { }) const diff = new Diff(npm) - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('global space, transform single direct dep name', t => { + t.test('global space, transform single direct dep name', async t => { t.plan(4) const path = t.testdir({ @@ -363,7 +322,7 @@ t.test('single arg', t => { npm.prefix = resolve(path, 'project') npm.globalDir = resolve(path, 'globalDir/lib/node_modules') - const Diff = t.mock('../../lib/diff.js', { + const Diff = t.mock('../../../lib/commands/diff.js', { ...mocks, pacote: { packument: (spec) => { @@ -381,13 +340,10 @@ t.test('single arg', t => { }) const diff = new Diff(npm) - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('transform single spec into spec comparison', t => { + t.test('transform single spec into spec comparison', async t => { t.plan(2) const path = t.testdir({ @@ -415,13 +371,10 @@ t.test('single arg', t => { config.diff = ['bar@2.0.0'] npm.prefix = path - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('transform single spec from transitive deps', t => { + t.test('transform single spec from transitive deps', async t => { t.plan(4) const path = t.testdir({ @@ -450,9 +403,9 @@ t.test('single arg', t => { }), }) - const Diff = t.mock('../../lib/diff.js', { + const Diff = t.mock('../../../lib/commands/diff.js', { ...mocks, - '../../lib/utils/read-package-name.js': async () => 'my-project', + '../../../lib/utils/read-package-name.js': async () => 'my-project', pacote: { packument: (spec) => { t.equal(spec.name, 'lorem', 'should have expected spec name') @@ -472,13 +425,10 @@ t.test('single arg', t => { config.diff = ['lorem'] npm.prefix = path - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('missing actual tree', t => { + t.test('missing actual tree', async t => { t.plan(2) const path = t.testdir({ @@ -487,9 +437,9 @@ t.test('single arg', t => { }), }) - const Diff = t.mock('../../lib/diff.js', { + const Diff = t.mock('../../../lib/commands/diff.js', { ...mocks, - '../../lib/utils/read-package-name.js': async () => 'my-project', + '../../../lib/utils/read-package-name.js': async () => 'my-project', '@npmcli/arborist': class { constructor () { throw new Error('ERR') @@ -505,13 +455,10 @@ t.test('single arg', t => { config.diff = ['lorem'] npm.prefix = path - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('unknown package name', t => { + t.test('unknown package name', async t => { t.plan(2) const path = t.testdir({ @@ -525,13 +472,10 @@ t.test('single arg', t => { config.diff = ['bar'] npm.prefix = path - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('use project name in project dir', t => { + t.test('use project name in project dir', async t => { t.plan(2) libnpmdiff = async ([a, b], opts) => { @@ -540,13 +484,10 @@ t.test('single arg', t => { } config.diff = ['foo'] - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('dir spec type', t => { + t.test('dir spec type', async t => { t.plan(2) const otherPath = resolve('/path/to/other-dir') @@ -556,29 +497,23 @@ t.test('single arg', t => { } config.diff = [otherPath] - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('unsupported spec type', t => { + t.test('unsupported spec type', async t => { config.diff = ['git+https://github.com/user/foo'] - diff.exec([], err => { - t.match( - err, - /Spec type git not supported./, - 'should throw spec type not supported error.' - ) - t.end() - }) + await t.rejects( + diff.exec([]), + /Spec type git not supported./, + 'should throw spec type not supported error.' + ) }) t.end() }) t.test('first arg is a qualified spec', t => { - t.test('second arg is ALSO a qualified spec', t => { + t.test('second arg is ALSO a qualified spec', async t => { t.plan(3) libnpmdiff = async ([a, b], opts) => { @@ -588,13 +523,10 @@ t.test('first arg is a qualified spec', t => { } config.diff = ['bar@1.0.0', 'bar@^2.0.0'] - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('second arg is a known dependency name', t => { + t.test('second arg is a known dependency name', async t => { t.plan(2) const path = t.testdir({ @@ -621,13 +553,10 @@ t.test('first arg is a qualified spec', t => { npm.prefix = path config.diff = ['bar@2.0.0', 'bar'] - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('second arg is a valid semver version', t => { + t.test('second arg is a valid semver version', async t => { t.plan(2) config.diff = ['bar@1.0.0', '2.0.0'] @@ -637,13 +566,10 @@ t.test('first arg is a qualified spec', t => { t.equal(b, 'bar@2.0.0', 'should use name from first arg') } - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('second arg is an unknown dependency name', t => { + t.test('second arg is an unknown dependency name', async t => { t.plan(2) libnpmdiff = async ([a, b], opts) => { @@ -652,16 +578,13 @@ t.test('first arg is a qualified spec', t => { } config.diff = ['bar@1.0.0', 'bar-fork'] - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) t.end() }) -t.test('first arg is a known dependency name', t => { +t.test('first arg is a known dependency name', async t => { t.test('second arg is a qualified spec', t => { t.plan(2) @@ -767,7 +690,7 @@ t.test('first arg is a known dependency name', t => { }) }) - t.test('second arg is an unknown dependency name', t => { + t.test('second arg is an unknown dependency name', async t => { t.plan(2) const path = t.testdir({ @@ -794,17 +717,14 @@ t.test('first arg is a known dependency name', t => { npm.prefix = path config.diff = ['bar', 'bar-fork'] - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) t.end() }) t.test('first arg is a valid semver range', t => { - t.test('second arg is a qualified spec', t => { + t.test('second arg is a qualified spec', async t => { t.plan(2) config.diff = ['1.0.0', 'bar@2.0.0'] @@ -814,13 +734,10 @@ t.test('first arg is a valid semver range', t => { t.equal(b, 'bar@2.0.0', 'should use expected spec') } - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('second arg is a known dependency', t => { + t.test('second arg is a known dependency', async t => { t.plan(2) const path = t.testdir({ @@ -847,13 +764,10 @@ t.test('first arg is a valid semver range', t => { npm.prefix = path config.diff = ['1.0.0', 'bar'] - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('second arg is ALSO a semver version', t => { + t.test('second arg is ALSO a semver version', async t => { t.plan(2) libnpmdiff = async ([a, b], opts) => { @@ -862,27 +776,21 @@ t.test('first arg is a valid semver range', t => { } config.diff = ['1.0.0', '2.0.0'] - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('second arg is ALSO a semver version BUT cwd not a project dir', t => { + t.test('second arg is ALSO a semver version BUT cwd not a project dir', async t => { const path = t.testdir({}) config.diff = ['1.0.0', '2.0.0'] npm.prefix = path - diff.exec([], err => { - t.match( - err, - /Needs to be run from a project dir in order to diff two versions./, - 'should throw two versions need project dir error usage msg' - ) - t.end() - }) + await t.rejects( + diff.exec([]), + /Needs to be run from a project dir in order to diff two versions./, + 'should throw two versions need project dir error usage msg' + ) }) - t.test('second arg is an unknown dependency name', t => { + t.test('second arg is an unknown dependency name', async t => { t.plan(2) libnpmdiff = async ([a, b], opts) => { @@ -891,13 +799,10 @@ t.test('first arg is a valid semver range', t => { } config.diff = ['1.0.0', 'bar'] - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('second arg is a qualified spec, missing actual tree', t => { + t.test('second arg is a qualified spec, missing actual tree', async t => { t.plan(2) const path = t.testdir({ @@ -906,7 +811,7 @@ t.test('first arg is a valid semver range', t => { }), }) - const Diff = t.mock('../../lib/diff.js', { + const Diff = t.mock('../../../lib/commands/diff.js', { ...mocks, '@npmcli/arborist': class { constructor () { @@ -923,10 +828,7 @@ t.test('first arg is a valid semver range', t => { config.diff = ['1.0.0', 'lorem@2.0.0'] npm.prefix = path - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) t.end() @@ -1035,7 +937,7 @@ t.test('first arg is an unknown dependency name', t => { }) t.test('various options', t => { - t.test('using --name-only option', t => { + t.test('using --name-only option', async t => { t.plan(1) flatOptions.diffNameOnly = true @@ -1047,13 +949,10 @@ t.test('various options', t => { }, 'should forward nameOnly=true option') } - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) - t.test('set files after both versions', t => { + t.test('set files after both versions', async t => { t.plan(3) config.diff = ['2.1.4', '3.0.0'] @@ -1070,13 +969,10 @@ t.test('various options', t => { }, 'should forward diffFiles values') } - diff.exec(['./foo.js', './bar.js'], err => { - if (err) - throw err - }) + await diff.exec(['./foo.js', './bar.js']) }) - t.test('set files no diff args', t => { + t.test('set files no diff args', async t => { t.plan(3) libnpmdiff = async ([a, b], opts) => { @@ -1091,13 +987,10 @@ t.test('various options', t => { }, 'should forward all remaining items as filenames') } - diff.exec(['./foo.js', './bar.js'], err => { - if (err) - throw err - }) + await diff.exec(['./foo.js', './bar.js']) }) - t.test('using diff option', t => { + t.test('using diff option', async t => { t.plan(1) flatOptions.diffContext = 5 @@ -1119,25 +1012,19 @@ t.test('various options', t => { }, 'should forward diff options') } - diff.exec([], err => { - if (err) - throw err - }) + await diff.exec([]) }) t.end() }) -t.test('too many args', t => { +t.test('too many args', async t => { config.diff = ['a', 'b', 'c'] - diff.exec([], err => { - t.match( - err, - /Can't use more than two --diff arguments./, - 'should throw usage error' - ) - t.end() - }) + await t.rejects( + diff.exec([]), + /Can't use more than two --diff arguments./, + 'should throw usage error' + ) }) t.test('workspaces', t => { @@ -1167,52 +1054,47 @@ t.test('workspaces', t => { }), }) - t.test('all workspaces', t => { + t.test('all workspaces', async t => { const diffCalls = [] libnpmdiff = async ([a, b]) => { diffCalls.push([a, b]) } npm.prefix = path npm.localPrefix = path - diff.execWorkspaces([], [], (err) => { - if (err) - throw err - t.same(diffCalls, [ - ['workspace-a@latest', join(`file:${path}`, 'workspace-a')], - ['workspace-b@latest', join(`file:${path}`, 'workspace-b')], - ], 'should call libnpmdiff with workspaces params') - t.end() - }) + await diff.execWorkspaces([], []) + t.same(diffCalls, [ + ['workspace-a@latest', join(`file:${path}`, 'workspace-a')], + ['workspace-b@latest', join(`file:${path}`, 'workspace-b')], + ], 'should call libnpmdiff with workspaces params') }) - t.test('one workspace', t => { + t.test('one workspace', async t => { const diffCalls = [] libnpmdiff = async ([a, b]) => { diffCalls.push([a, b]) } npm.prefix = path npm.localPrefix = path - diff.execWorkspaces([], ['workspace-a'], (err) => { - if (err) - throw err - t.same(diffCalls, [ - ['workspace-a@latest', join(`file:${path}`, 'workspace-a')], - ], 'should call libnpmdiff with workspaces params') - t.end() - }) + await diff.execWorkspaces([], ['workspace-a']) + t.same(diffCalls, [ + ['workspace-a@latest', join(`file:${path}`, 'workspace-a')], + ], 'should call libnpmdiff with workspaces params') }) - t.test('invalid workspace', t => { + t.test('invalid workspace', async t => { libnpmdiff = () => { t.fail('should not call libnpmdiff') } npm.prefix = path npm.localPrefix = path - diff.execWorkspaces([], ['workspace-x'], (err) => { - t.match(err, /No workspaces found/) - t.match(err, /workspace-x/) - t.end() - }) + await t.rejects( + diff.execWorkspaces([], ['workspace-x']), + /No workspaces found/ + ) + await t.rejects( + diff.execWorkspaces([], ['workspace-x']), + /workspace-x/ + ) }) t.end() }) diff --git a/deps/npm/test/lib/commands/dist-tag.js b/deps/npm/test/lib/commands/dist-tag.js new file mode 100644 index 00000000000000..be66366f84337e --- /dev/null +++ b/deps/npm/test/lib/commands/dist-tag.js @@ -0,0 +1,390 @@ +const t = require('tap') +const { fake: mockNpm } = require('../../fixtures/mock-npm') + +let result = '' +let log = '' + +t.afterEach(() => { + result = '' + log = '' +}) + +const routeMap = { + '/-/package/@scoped%2fpkg/dist-tags': { + latest: '1.0.0', + a: '0.0.1', + b: '0.5.0', + }, + '/-/package/@scoped%2fanother/dist-tags': { + latest: '2.0.0', + a: '0.0.2', + b: '0.6.0', + }, + '/-/package/@scoped%2fanother/dist-tags/c': { + latest: '7.7.7', + a: '0.0.2', + b: '0.6.0', + c: '7.7.7', + }, + '/-/package/workspace-a/dist-tags': { + latest: '1.0.0', + 'latest-a': '1.0.0', + }, + '/-/package/workspace-b/dist-tags': { + latest: '2.0.0', + 'latest-b': '2.0.0', + }, + '/-/package/workspace-c/dist-tags': { + latest: '3.0.0', + 'latest-c': '3.0.0', + }, +} + +// XXX overriding this does not appear to do anything, adding t.plan to things +// that use it fails the test +let npmRegistryFetchMock = (url, opts) => { + if (url === '/-/package/foo/dist-tags') + throw new Error('no package found') + + return routeMap[url] +} + +npmRegistryFetchMock.json = async (url, opts) => routeMap[url] + +const logger = (...msgs) => { + for (const msg of [...msgs]) + log += msg + ' ' + + log += '\n' +} + +const DistTag = t.mock('../../../lib/commands/dist-tag.js', { + npmlog: { + error: logger, + info: logger, + verbose: logger, + warn: logger, + }, + get 'npm-registry-fetch' () { + return npmRegistryFetchMock + }, +}) + +const config = {} +const npm = mockNpm({ + config, + output: msg => { + result = result ? [result, msg].join('\n') : msg + }, +}) +const distTag = new DistTag(npm) + +t.test('ls in current package', async t => { + npm.prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: '@scoped/pkg', + }), + }) + await distTag.exec(['ls']) + t.matchSnapshot( + result, + 'should list available tags for current package' + ) +}) + +t.test('ls global', async t => { + t.teardown(() => { + config.global = false + }) + config.global = true + await t.rejects( + distTag.exec(['ls']), + distTag.usage, + 'should throw basic usage' + ) +}) + +t.test('no args in current package', async t => { + npm.prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: '@scoped/pkg', + }), + }) + await distTag.exec([]) + t.matchSnapshot( + result, + 'should default to listing available tags for current package' + ) +}) + +t.test('borked cmd usage', async t => { + npm.prefix = t.testdir({}) + await t.rejects( + distTag.exec(['borked', '@scoped/pkg']), + distTag.usage, + 'should show usage error' + ) +}) + +t.test('ls on named package', async t => { + npm.prefix = t.testdir({}) + await distTag.exec(['ls', '@scoped/another']) + t.matchSnapshot( + result, + 'should list tags for the specified package' + ) +}) + +t.test('ls on missing package', async t => { + npm.prefix = t.testdir({}) + await t.rejects( + distTag.exec(['ls', 'foo']), + distTag.usage + ) + t.matchSnapshot( + log, + 'should log no dist-tag found msg' + ) +}) + +t.test('ls on missing name in current package', async t => { + npm.prefix = t.testdir({ + 'package.json': JSON.stringify({ + version: '1.0.0', + }), + }) + await t.rejects( + distTag.exec(['ls']), + distTag.usage, + 'should throw usage error message' + ) +}) + +t.test('only named package arg', async t => { + npm.prefix = t.testdir({}) + await distTag.exec(['@scoped/another']) + t.matchSnapshot( + result, + 'should default to listing tags for the specified package' + ) +}) + +t.test('workspaces', t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'root', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], + }), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.0.0', + }), + }, + 'workspace-c': { + 'package.json': JSON.stringify({ + name: 'workspace-c', + version: '1.0.0', + }), + }, + }) + + t.test('no args', async t => { + await distTag.execWorkspaces([], []) + t.matchSnapshot(result, 'printed the expected output') + }) + + t.test('no args, one workspace', async t => { + await distTag.execWorkspaces([], ['workspace-a']) + t.matchSnapshot(result, 'printed the expected output') + }) + + t.test('one arg -- .', async t => { + await distTag.execWorkspaces(['.'], []) + t.matchSnapshot(result, 'printed the expected output') + }) + + t.test('one arg -- .@1, ignores version spec', async t => { + await distTag.execWorkspaces(['.@'], []) + t.matchSnapshot(result, 'printed the expected output') + }) + + t.test('one arg -- list', async t => { + await distTag.execWorkspaces(['list'], []) + t.matchSnapshot(result, 'printed the expected output') + }) + + t.test('two args -- list, .', async t => { + await distTag.execWorkspaces(['list', '.'], []) + t.matchSnapshot(result, 'printed the expected output') + }) + + t.test('two args -- list, .@1, ignores version spec', async t => { + await distTag.execWorkspaces(['list', '.@'], []) + t.matchSnapshot(result, 'printed the expected output') + }) + + t.test('two args -- list, @scoped/pkg, logs a warning and ignores workspaces', async t => { + await distTag.execWorkspaces(['list', '@scoped/pkg'], []) + t.match(log, 'Ignoring workspaces for specified package', 'logs a warning') + t.matchSnapshot(result, 'printed the expected output') + }) + + t.test('no args, one failing workspace sets exitCode to 1', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'root', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b', 'workspace-c', 'workspace-d'], + }), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.0.0', + }), + }, + 'workspace-c': { + 'package.json': JSON.stringify({ + name: 'workspace-c', + version: '1.0.0', + }), + }, + 'workspace-d': { + 'package.json': JSON.stringify({ + name: 'workspace-d', + version: '1.0.0', + }), + }, + }) + + await distTag.execWorkspaces([], []) + t.equal(process.exitCode, 1, 'set the error status') + process.exitCode = 0 + t.match(log, 'dist-tag ls Couldn\'t get dist-tag data for workspace-d@latest', 'logs the error') + t.matchSnapshot(result, 'printed the expected output') + }) + + t.end() +}) + +t.test('add new tag', async t => { + const _nrf = npmRegistryFetchMock + t.teardown(() => { + npmRegistryFetchMock = _nrf + }) + + npmRegistryFetchMock = async (url, opts) => { + t.equal(opts.method, 'PUT', 'should trigger request to add new tag') + t.equal(opts.body, '7.7.7', 'should point to expected version') + } + npm.prefix = t.testdir({}) + await distTag.exec(['add', '@scoped/another@7.7.7', 'c']) + t.matchSnapshot( + result, + 'should return success msg' + ) +}) + +t.test('add using valid semver range as name', async t => { + npm.prefix = t.testdir({}) + await t.rejects( + distTag.exec(['add', '@scoped/another@7.7.7', '1.0.0']), + /Tag name must not be a valid SemVer range: 1.0.0/, + 'should exit with semver range error' + ) + t.matchSnapshot( + log, + 'should return success msg' + ) +}) + +t.test('add missing args', async t => { + npm.prefix = t.testdir({}) + config.tag = '' + t.teardown(() => { + delete config.tag + }) + await t.rejects( + distTag.exec(['add', '@scoped/another@7.7.7']), + distTag.usage, + 'should exit usage error message' + ) +}) + +t.test('add missing pkg name', async t => { + npm.prefix = t.testdir({}) + await t.rejects( + distTag.exec(['add', null]), + distTag.usage, + 'should exit usage error message' + ) +}) + +t.test('set existing version', async t => { + npm.prefix = t.testdir({}) + await distTag.exec(['set', '@scoped/another@0.6.0', 'b']) + t.matchSnapshot( + log, + 'should log warn msg' + ) +}) + +t.test('remove existing tag', async t => { + const _nrf = npmRegistryFetchMock + t.teardown(() => { + npmRegistryFetchMock = _nrf + }) + + npmRegistryFetchMock = async (url, opts) => { + t.equal(opts.method, 'DELETE', 'should trigger request to remove tag') + } + npm.prefix = t.testdir({}) + await distTag.exec(['rm', '@scoped/another', 'c']) + t.matchSnapshot(log, 'should log remove info') + t.matchSnapshot(result, 'should return success msg') +}) + +t.test('remove non-existing tag', async t => { + npm.prefix = t.testdir({}) + await t.rejects( + distTag.exec(['rm', '@scoped/another', 'nonexistent']), + /nonexistent is not a dist-tag on @scoped\/another/, + 'should exit with error' + ) + t.matchSnapshot(log, 'should log error msg') +}) + +t.test('remove missing pkg name', async t => { + npm.prefix = t.testdir({}) + await t.rejects( + distTag.exec(['rm', null]), + distTag.usage, + 'should exit usage error message' + ) +}) + +t.test('completion', async t => { + const { completion } = distTag + t.plan(2) + + const match = completion({ conf: { argv: { remain: ['npm', 'dist-tag'] } } }) + t.resolveMatch(match, ['add', 'rm', 'ls'], + 'should list npm dist-tag commands for completion') + + const noMatch = completion({ conf: { argv: { remain: ['npm', 'dist-tag', 'foobar'] } } }) + t.resolveMatch(noMatch, []) + t.end() +}) diff --git a/deps/npm/test/lib/docs.js b/deps/npm/test/lib/commands/docs.js similarity index 65% rename from deps/npm/test/lib/docs.js rename to deps/npm/test/lib/commands/docs.js index fbd75842012473..4853a7960c5e57 100644 --- a/deps/npm/test/lib/docs.js +++ b/deps/npm/test/lib/commands/docs.js @@ -1,5 +1,5 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm.js') +const { fake: mockNpm } = require('../../fixtures/mock-npm.js') const { join, sep } = require('path') const pkgDirs = t.testdir({ @@ -71,8 +71,8 @@ const openUrl = async (npm, url, errMsg) => { opened[url]++ } -const Docs = t.mock('../../lib/docs.js', { - '../../lib/utils/open-url.js': openUrl, +const Docs = t.mock('../../../lib/commands/docs.js', { + '../../../lib/utils/open-url.js': openUrl, }) const flatOptions = {} const npm = mockNpm({ flatOptions }) @@ -94,60 +94,49 @@ t.test('open docs urls', t => { const keys = Object.keys(expect) t.plan(keys.length) keys.forEach(pkg => { - t.test(pkg, t => { - docs.exec([['.', pkg].join(sep)], (err) => { - if (err) - throw err - const url = expect[pkg] - t.match({ - [url]: 1, - }, opened, `opened ${url}`, {opened}) - t.end() - }) + t.test(pkg, async t => { + await docs.exec([['.', pkg].join(sep)]) + const url = expect[pkg] + t.match({ + [url]: 1, + }, opened, `opened ${url}`, {opened}) }) }) }) -t.test('open default package if none specified', t => { - docs.exec([], (er) => { - if (er) - throw er - t.equal(opened['https://example.com'], 1, 'opened expected url', {opened}) - t.end() - }) +t.test('open default package if none specified', async t => { + await docs.exec([]) + t.equal(opened['https://example.com'], 1, 'opened expected url', {opened}) }) t.test('workspaces', (t) => { flatOptions.where = undefined npm.localPrefix = join(pkgDirs, 'workspaces') - t.test('all workspaces', (t) => { - docs.execWorkspaces([], [], (err) => { - t.notOk(err) - t.match({ - 'http://docs.workspace-a/': 1, - 'https://github.com/npm/workspace-b#readme': 1, - }, opened, 'opened two valid docs urls') - t.end() - }) + t.test('all workspaces', async t => { + await docs.execWorkspaces([], []) + t.match({ + 'http://docs.workspace-a/': 1, + 'https://github.com/npm/workspace-b#readme': 1, + }, opened, 'opened two valid docs urls') }) - t.test('one workspace', (t) => { - docs.execWorkspaces([], ['workspace-a'], (err) => { - t.notOk(err) - t.match({ - 'http://docs.workspace-a/': 1, - }, opened, 'opened one requested docs urls') - t.end() - }) + t.test('one workspace', async t => { + await docs.execWorkspaces([], ['workspace-a']) + t.match({ + 'http://docs.workspace-a/': 1, + }, opened, 'opened one requested docs urls') }) - t.test('invalid workspace', (t) => { - docs.execWorkspaces([], ['workspace-x'], (err) => { - t.match(err, /No workspaces found/) - t.match(err, /workspace-x/) - t.match({}, opened, 'opened no docs urls') - t.end() - }) + t.test('invalid workspace', async t => { + await t.rejects( + docs.execWorkspaces([], ['workspace-x']), + /No workspaces found/ + ) + await t.rejects( + docs.execWorkspaces([], ['workspace-x']), + /workspace-x/ + ) + t.match({}, opened, 'opened no docs urls') }) t.end() }) diff --git a/deps/npm/test/lib/commands/doctor.js b/deps/npm/test/lib/commands/doctor.js new file mode 100644 index 00000000000000..9db622878c6208 --- /dev/null +++ b/deps/npm/test/lib/commands/doctor.js @@ -0,0 +1,929 @@ +const t = require('tap') + +const { join } = require('path') +const fs = require('fs') +const ansiTrim = require('../../../lib/utils/ansi-trim.js') +const isWindows = require('../../../lib/utils/is-windows.js') + +// getuid and getgid do not exist in windows, so we shim them +// to return 0, as that is the value that lstat will assign the +// gid and uid properties for fs.Stats objects +if (isWindows) { + process.getuid = () => 0 + process.getgid = () => 0 +} + +const output = [] + +let pingError +const ping = async () => { + if (pingError) + throw pingError +} + +let whichError = null +const which = async () => { + if (whichError) + throw whichError + return '/path/to/git' +} + +const nodeVersions = [ + { version: 'v14.0.0', lts: false }, + { version: 'v13.0.0', lts: false }, + // it's necessary to allow tests in node 10.x to not mark 12.x as lts + { version: 'v12.0.0', lts: false }, + { version: 'v10.13.0', lts: 'Dubnium' }, +] + +const fetch = async () => { + return { + json: async () => { + return nodeVersions + }, + } +} + +const logs = { + info: [], +} + +const clearLogs = (obj = logs) => { + output.length = 0 + for (const key in obj) { + if (Array.isArray(obj[key])) + obj[key].length = 0 + else + delete obj[key] + } +} + +const npm = { + flatOptions: { + registry: 'https://registry.npmjs.org/', + }, + log: { + info: (msg) => { + logs.info.push(msg) + }, + newItem: (name) => { + logs[name] = {} + + return { + info: (_, msg) => { + if (!logs[name].info) + logs[name].info = [] + logs[name].info.push(msg) + }, + warn: (_, msg) => { + if (!logs[name].warn) + logs[name].warn = [] + logs[name].warn.push(msg) + }, + error: (_, msg) => { + if (!logs[name].error) + logs[name].error = [] + logs[name].error.push(msg) + }, + silly: (_, msg) => { + if (!logs[name].silly) + logs[name].silly = [] + logs[name].silly.push(msg) + }, + completeWork: () => {}, + finish: () => { + logs[name].finished = true + }, + } + }, + level: 'error', + levels: { + info: 1, + error: 0, + }, + }, + version: '7.1.0', + output: (data) => { + output.push(data) + }, +} + +let latestNpm = npm.version +const pacote = { + manifest: async () => { + return { version: latestNpm } + }, +} + +let verifyResponse = { verifiedCount: 1, verifiedContent: 1 } +const cacache = { + verify: async () => { + return verifyResponse + }, +} + +const Doctor = t.mock('../../../lib/commands/doctor.js', { + '../../../lib/utils/is-windows.js': false, + '../../../lib/utils/ping.js': ping, + cacache, + pacote, + 'make-fetch-happen': fetch, + which, +}) +const doctor = new Doctor(npm) + +const origVersion = process.version +t.test('node versions', t => { + t.plan(nodeVersions.length) + + nodeVersions.forEach(({ version }) => { + t.test(`${version}:`, vt => { + Object.defineProperty(process, 'version', { value: version }) + vt.teardown(() => { + Object.defineProperty(process, 'version', { value: origVersion }) + }) + + vt.test(`${version}: npm doctor checks ok`, async st => { + const dir = st.testdir() + npm.cache = npm.flatOptions.cache = dir + npm.localDir = dir + npm.globalDir = dir + npm.localBin = dir + npm.globalBin = dir + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + clearLogs() + }) + + await doctor.exec([]) + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [dir]: { finished: true }, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.match(output, /npm ping\s*ok/, 'ping output is ok') + st.match(output, /npm -v\s*ok/, 'npm -v output is ok') + st.match(output, /node -v\s*ok/, 'node -v output is ok') + st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') + st.match(output, /which git\s*ok/, 'which git output is ok') + st.match(output, /cached files\s*ok/, 'cached files are ok') + st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') + st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') + st.match(output, /local bin folder\s*ok/, 'local bin is ok') + st.match(output, /global bin folder\s*ok/, 'global bin is ok') + st.match(output, /cache contents\s*ok/, 'cache contents is ok') + }) + + vt.test('npm doctor supports silent', async st => { + const dir = st.testdir() + npm.cache = npm.flatOptions.cache = dir + npm.localDir = dir + npm.globalDir = dir + npm.localBin = dir + npm.globalBin = dir + npm.log.level = 'info' + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + npm.log.level = 'error' + clearLogs() + }) + + await doctor.exec([]) + + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [dir]: { finished: true }, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.strictSame(output, [], 'did not print output') + }) + + vt.test('npm doctor supports color', async st => { + const dir = st.testdir() + npm.cache = npm.flatOptions.cache = dir + npm.localDir = dir + npm.globalDir = dir + npm.localBin = dir + npm.globalBin = dir + npm.color = true + pingError = { message: 'generic error' } + const _consoleError = console.error + console.error = () => {} + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + delete npm.color + pingError = null + console.error = _consoleError + clearLogs() + }) + + await st.rejects( + doctor.exec([]), + /Some problems found/, + 'detected the ping error' + ) + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [dir]: { finished: true }, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.match(output, /npm ping.*not ok/, 'ping output is ok') + st.match(output, /npm -v.*ok/, 'npm -v output is ok') + st.match(output, /node -v.*ok/, 'node -v output is ok') + st.match(output, /npm config get registry.*ok.*using default/, 'npm config get registry output is ok') + st.match(output, /which git.*ok/, 'which git output is ok') + st.match(output, /cached files.*ok/, 'cached files are ok') + st.match(output, /local node_modules.*ok/, 'local node_modules are ok') + st.match(output, /global node_modules.*ok/, 'global node_modules are ok') + st.match(output, /local bin folder.*ok/, 'local bin is ok') + st.match(output, /global bin folder.*ok/, 'global bin is ok') + st.match(output, /cache contents.*ok/, 'cache contents is ok') + st.not(output[0], ansiTrim(output[0]), 'output should contain color codes') + }) + + vt.test('npm doctor skips some tests in windows', async st => { + const WinDoctor = t.mock('../../../lib/commands/doctor.js', { + '../../../lib/utils/is-windows.js': true, + '../../../lib/utils/ping.js': ping, + cacache, + pacote, + 'make-fetch-happen': fetch, + which, + }) + const winDoctor = new WinDoctor(npm) + + const dir = st.testdir() + npm.cache = npm.flatOptions.cache = dir + npm.localDir = dir + npm.globalDir = dir + npm.localBin = dir + npm.globalBin = dir + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + clearLogs() + }) + + await winDoctor.exec([]) + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [dir]: undefined, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.match(output, /npm ping\s*ok/, 'ping output is ok') + st.match(output, /npm -v\s*ok/, 'npm -v output is ok') + st.match(output, /node -v\s*ok/, 'node -v output is ok') + st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') + st.match(output, /which git\s*ok/, 'which git output is ok') + st.match(output, /cache contents\s*ok/, 'cache contents is ok') + }) + + vt.test('npm doctor ping error E{3}', async st => { + const dir = st.testdir() + npm.cache = npm.flatOptions.cache = dir + npm.localDir = dir + npm.globalDir = dir + npm.localBin = dir + npm.globalBin = dir + pingError = { code: 'E111', message: 'this error is 111' } + const consoleError = console.error + // we just print an empty line here, so swallow it and ignore + console.error = () => {} + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + pingError = null + console.error = consoleError + clearLogs() + }) + + await st.rejects( + doctor.exec([]), + /Some problems found/, + 'detected the ping error' + ) + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [dir]: { finished: true }, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.match(output, /npm ping\s*not ok\s*111 this error is 111/, 'ping output contains trimmed error') + st.match(output, /npm -v\s*ok/, 'npm -v output is ok') + st.match(output, /node -v\s*ok/, 'node -v output is ok') + st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') + st.match(output, /which git\s*ok/, 'which git output is ok') + st.match(output, /cached files\s*ok/, 'cached files are ok') + st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') + st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') + st.match(output, /local bin folder\s*ok/, 'local bin is ok') + st.match(output, /global bin folder\s*ok/, 'global bin is ok') + st.match(output, /cache contents\s*ok/, 'cache contents is ok') + }) + + vt.test('npm doctor generic ping error', async st => { + const dir = st.testdir() + npm.cache = npm.flatOptions.cache = dir + npm.localDir = dir + npm.globalDir = dir + npm.localBin = dir + npm.globalBin = dir + pingError = { message: 'generic error' } + const consoleError = console.error + // we just print an empty line here, so swallow it and ignore + console.error = () => {} + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + pingError = null + console.error = consoleError + clearLogs() + }) + + await st.rejects( + doctor.exec([]), + /Some problems found/, + 'detected the ping error' + ) + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [dir]: { finished: true }, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.match(output, /npm ping\s*not ok\s*generic error/, 'ping output contains trimmed error') + st.match(output, /npm -v\s*ok/, 'npm -v output is ok') + st.match(output, /node -v\s*ok/, 'node -v output is ok') + st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') + st.match(output, /which git\s*ok/, 'which git output is ok') + st.match(output, /cached files\s*ok/, 'cached files are ok') + st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') + st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') + st.match(output, /local bin folder\s*ok/, 'local bin is ok') + st.match(output, /global bin folder\s*ok/, 'global bin is ok') + st.match(output, /cache contents\s*ok/, 'cache contents is ok') + }) + + vt.test('npm doctor outdated npm version', async st => { + const dir = st.testdir() + npm.cache = npm.flatOptions.cache = dir + npm.localDir = dir + npm.globalDir = dir + npm.localBin = dir + npm.globalBin = dir + latestNpm = '7.1.1' + const consoleError = console.error + // we just print an empty line here, so swallow it and ignore + console.error = () => {} + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + latestNpm = npm.version + console.error = consoleError + clearLogs() + }) + + await st.rejects( + doctor.exec([]), + /Some problems found/, + 'detected the out of date npm' + ) + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [dir]: { finished: true }, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.match(output, /npm ping\s*ok/, 'ping output is ok') + st.match(output, /npm -v\s*not ok/, 'npm -v output is not ok') + st.match(output, /node -v\s*ok/, 'node -v output is ok') + st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') + st.match(output, /which git\s*ok/, 'which git output is ok') + st.match(output, /cached files\s*ok/, 'cached files are ok') + st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') + st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') + st.match(output, /local bin folder\s*ok/, 'local bin is ok') + st.match(output, /global bin folder\s*ok/, 'global bin is ok') + st.match(output, /cache contents\s*ok/, 'cache contents is ok') + }) + + vt.test('npm doctor file permission checks', async st => { + const dir = st.testdir({ + cache: { + one: 'one', + link: st.fixture('symlink', './baddir'), + unreadable: 'unreadable', + baddir: {}, + }, + local: { + two: 'two', + notmine: 'notmine', + }, + global: { + three: 'three', + broken: 'broken', + }, + localBin: { + four: 'four', + five: 'five', + }, + globalBin: { + six: 'six', + seven: 'seven', + }, + }) + + const _fsLstat = fs.lstat + fs.lstat = (p, cb) => { + let err = null + let stat = null + + try { + stat = fs.lstatSync(p) + } catch (err) { + return cb(err) + } + + switch (p) { + case join(dir, 'local', 'notmine'): + stat.uid += 1 + stat.gid += 1 + break + case join(dir, 'global', 'broken'): + err = new Error('broken') + break + } + + return cb(err, stat) + } + + const _fsReaddir = fs.readdir + fs.readdir = (p, cb) => { + let err = null + let result = null + + try { + result = fs.readdirSync(p) + } catch (err) { + return cb(err) + } + + if (p === join(dir, 'cache', 'baddir')) + err = new Error('broken') + + return cb(err, result) + } + + const _fsAccess = fs.access + fs.access = (p, mask, cb) => { + const err = new Error('failed') + switch (p) { + case join(dir, 'cache', 'unreadable'): + case join(dir, 'localBin', 'four'): + case join(dir, 'globalBin', 'six'): + return cb(err) + default: + return cb(null) + } + } + + const Doctor = t.mock('../../../lib/commands/doctor.js', { + '../../../lib/utils/is-windows.js': false, + '../../../lib/utils/ping.js': ping, + cacache, + pacote, + 'make-fetch-happen': fetch, + which, + fs, + }) + const doctor = new Doctor(npm) + // it's necessary to allow tests in node 10.x to not mark 12.x as lted + + npm.cache = npm.flatOptions.cache = join(dir, 'cache') + npm.localDir = join(dir, 'local') + npm.globalDir = join(dir, 'global') + npm.localBin = join(dir, 'localBin') + npm.globalBin = join(dir, 'globalBin') + const _consoleError = console.error + console.error = () => {} + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + console.error = _consoleError + fs.lstat = _fsLstat + fs.readdir = _fsReaddir + fs.access = _fsAccess + clearLogs() + }) + + await st.rejects( + doctor.exec([]), + /Some problems found/, + 'identified problems' + ) + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [join(dir, 'cache')]: { finished: true }, + [join(dir, 'local')]: { finished: true }, + [join(dir, 'global')]: { finished: true }, + [join(dir, 'localBin')]: { finished: true }, + [join(dir, 'globalBin')]: { finished: true }, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.match(output, /npm ping\s*ok/, 'ping output is ok') + st.match(output, /npm -v\s*ok/, 'npm -v output is ok') + st.match(output, /node -v\s*ok/, 'node -v output is ok') + st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') + st.match(output, /which git\s*ok/, 'which git output is ok') + st.match(output, /cached files\s*not ok/, 'cached files are not ok') + st.match(output, /local node_modules\s*not ok/, 'local node_modules are not ok') + st.match(output, /global node_modules\s*not ok/, 'global node_modules are not ok') + st.match(output, /local bin folder\s*not ok/, 'local bin is not ok') + st.match(output, /global bin folder\s*not ok/, 'global bin is not ok') + st.match(output, /cache contents\s*ok/, 'cache contents is ok') + }) + + vt.test('npm doctor missing git', async st => { + const dir = st.testdir() + npm.cache = npm.flatOptions.cache = dir + npm.localDir = dir + npm.globalDir = dir + npm.localBin = dir + npm.globalBin = dir + whichError = new Error('boom') + const consoleError = console.error + // we just print an empty line here, so swallow it and ignore + console.error = () => {} + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + whichError = null + console.error = consoleError + clearLogs() + }) + + await st.rejects( + doctor.exec([]), + /Some problems found/, + 'detected the missing git' + ) + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [dir]: { finished: true }, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.match(output, /npm ping\s*ok/, 'ping output is ok') + st.match(output, /npm -v\s*ok/, 'npm -v output is ok') + st.match(output, /node -v\s*ok/, 'node -v output is ok') + st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') + st.match(output, /which git\s*not ok/, 'which git output is not ok') + st.match(output, /cached files\s*ok/, 'cached files are ok') + st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') + st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') + st.match(output, /local bin folder\s*ok/, 'local bin is ok') + st.match(output, /global bin folder\s*ok/, 'global bin is ok') + st.match(output, /cache contents\s*ok/, 'cache contents is ok') + }) + + vt.test('npm doctor cache verification showed bad content', async st => { + const dir = st.testdir() + npm.cache = npm.flatOptions.cache = dir + npm.localDir = dir + npm.globalDir = dir + npm.localBin = dir + npm.globalBin = dir + const _verifyResponse = verifyResponse + verifyResponse = { + ...verifyResponse, + badContentCount: 1, + } + const consoleError = console.error + // we just print an empty line here, so swallow it and ignore + console.error = () => {} + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + verifyResponse = _verifyResponse + console.error = consoleError + clearLogs() + }) + + // cache verification problems get fixed and so do not throw an error + await doctor.exec([]) + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [dir]: { finished: true }, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.match(output, /npm ping\s*ok/, 'ping output is ok') + st.match(output, /npm -v\s*ok/, 'npm -v output is ok') + st.match(output, /node -v\s*ok/, 'node -v output is ok') + st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') + st.match(output, /which git\s*ok/, 'which git output is ok') + st.match(output, /cached files\s*ok/, 'cached files are ok') + st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') + st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') + st.match(output, /local bin folder\s*ok/, 'local bin is ok') + st.match(output, /global bin folder\s*ok/, 'global bin is ok') + st.match(output, /cache contents\s*ok/, 'cache contents is not ok') + }) + + vt.test('npm doctor cache verification showed reclaimed content', async st => { + const dir = st.testdir() + npm.cache = npm.flatOptions.cache = dir + npm.localDir = dir + npm.globalDir = dir + npm.localBin = dir + npm.globalBin = dir + const _verifyResponse = verifyResponse + verifyResponse = { + ...verifyResponse, + reclaimedCount: 1, + reclaimedSize: 100, + } + const consoleError = console.error + // we just print an empty line here, so swallow it and ignore + console.error = () => {} + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + verifyResponse = _verifyResponse + console.error = consoleError + clearLogs() + }) + + // cache verification problems get fixed and so do not throw an error + await doctor.exec([]) + + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [dir]: { finished: true }, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.match(output, /npm ping\s*ok/, 'ping output is ok') + st.match(output, /npm -v\s*ok/, 'npm -v output is ok') + st.match(output, /node -v\s*ok/, 'node -v output is ok') + st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') + st.match(output, /which git\s*ok/, 'which git output is ok') + st.match(output, /cached files\s*ok/, 'cached files are ok') + st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') + st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') + st.match(output, /local bin folder\s*ok/, 'local bin is ok') + st.match(output, /global bin folder\s*ok/, 'global bin is ok') + st.match(output, /cache contents\s*ok/, 'cache contents is not ok') + }) + + vt.test('npm doctor cache verification showed missing content', async st => { + const dir = t.testdir() + npm.cache = npm.flatOptions.cache = dir + npm.localDir = dir + npm.globalDir = dir + npm.localBin = dir + npm.globalBin = dir + const _verifyResponse = verifyResponse + verifyResponse = { + ...verifyResponse, + missingContent: 1, + } + const consoleError = console.error + // we just print an empty line here, so swallow it and ignore + console.error = () => {} + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + verifyResponse = _verifyResponse + console.error = consoleError + clearLogs() + }) + + // cache verification problems get fixed and so do not throw an error + await doctor.exec([]) + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [dir]: { finished: true }, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.match(output, /npm ping\s*ok/, 'ping output is ok') + st.match(output, /npm -v\s*ok/, 'npm -v output is ok') + st.match(output, /node -v\s*ok/, 'node -v output is ok') + st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') + st.match(output, /which git\s*ok/, 'which git output is ok') + st.match(output, /cached files\s*ok/, 'cached files are ok') + st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') + st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') + st.match(output, /local bin folder\s*ok/, 'local bin is ok') + st.match(output, /global bin folder\s*ok/, 'global bin is ok') + st.match(output, /cache contents\s*ok/, 'cache contents is not ok') + }) + + vt.test('npm doctor not using default registry', async st => { + const dir = st.testdir() + npm.cache = npm.flatOptions.cache = dir + npm.localDir = dir + npm.globalDir = dir + npm.localBin = dir + npm.globalBin = dir + const _currentRegistry = npm.flatOptions.registry + npm.flatOptions.registry = 'https://google.com' + const consoleError = console.error + // we just print an empty line here, so swallow it and ignore + console.error = () => {} + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + npm.flatOptions.registry = _currentRegistry + console.error = consoleError + clearLogs() + }) + + await st.rejects( + doctor.exec([]), + /Some problems found/, + 'detected the non-default registry' + ) + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [dir]: { finished: true }, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.match(output, /npm ping\s*ok/, 'ping output is ok') + st.match(output, /npm -v\s*ok/, 'npm -v output is ok') + st.match(output, /node -v\s*ok/, 'node -v output is ok') + st.match(output, /npm config get registry\s*not ok/, 'npm config get registry output is not ok') + st.match(output, /which git\s*ok/, 'which git output is ok') + st.match(output, /cached files\s*ok/, 'cached files are ok') + st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') + st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') + st.match(output, /local bin folder\s*ok/, 'local bin is ok') + st.match(output, /global bin folder\s*ok/, 'global bin is ok') + st.match(output, /cache contents\s*ok/, 'cache contents is ok') + }) + + vt.end() + }) + }) +}) + +t.test('outdated node version', vt => { + vt.plan(1) + const version = 'v10.0.0' + + Object.defineProperty(process, 'version', { value: version }) + vt.teardown(() => { + Object.defineProperty(process, 'version', { value: origVersion }) + }) + + vt.test('npm doctor outdated nodejs version', async st => { + const dir = st.testdir() + npm.cache = npm.flatOptions.cache = dir + npm.localDir = dir + npm.globalDir = dir + npm.localBin = dir + npm.globalBin = dir + nodeVersions.push({ version: process.version.replace(/\d+(-.*)?$/, '999'), lts: false }) + const consoleError = console.error + // we just print an empty line here, so swallow it and ignore + console.error = () => {} + + st.teardown(() => { + delete npm.cache + delete npm.flatOptions.cache + delete npm.localDir + delete npm.globalDir + delete npm.localBin + delete npm.globalBin + nodeVersions.pop() + console.error = consoleError + clearLogs() + }) + + await st.rejects( + doctor.exec([]), + /Some problems found/, + 'detected the out of date nodejs' + ) + st.match(logs, { + checkPing: { finished: true }, + getLatestNpmVersion: { finished: true }, + getLatestNodejsVersion: { finished: true }, + getGitPath: { finished: true }, + [dir]: { finished: true }, + verifyCachedFiles: { finished: true }, + }, 'trackers all finished') + st.match(output, /npm ping\s*ok/, 'ping output is ok') + st.match(output, /npm -v\s*ok/, 'npm -v output is ok') + st.match(output, /node -v\s*not ok/, 'node -v output is not ok') + st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') + st.match(output, /which git\s*ok/, 'which git output is ok') + st.match(output, /cached files\s*ok/, 'cached files are ok') + st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') + st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') + st.match(output, /local bin folder\s*ok/, 'local bin is ok') + st.match(output, /global bin folder\s*ok/, 'global bin is ok') + st.match(output, /cache contents\s*ok/, 'cache contents is ok') + }) +}) diff --git a/deps/npm/test/lib/commands/edit.js b/deps/npm/test/lib/commands/edit.js new file mode 100644 index 00000000000000..39e1697b71c1ef --- /dev/null +++ b/deps/npm/test/lib/commands/edit.js @@ -0,0 +1,137 @@ +const t = require('tap') +const { resolve } = require('path') +const { EventEmitter } = require('events') + +let editorBin = null +let editorArgs = null +let editorOpts = null +let EDITOR_CODE = 0 +const childProcess = { + spawn: (bin, args, opts) => { + // save for assertions + editorBin = bin + editorArgs = args + editorOpts = opts + + const editorEvents = new EventEmitter() + process.nextTick(() => { + editorEvents.emit('exit', EDITOR_CODE) + }) + return editorEvents + }, +} + +let rebuildArgs = null +let rebuildFail = null +let EDITOR = 'vim' +const npm = { + config: { + get: () => EDITOR, + }, + dir: resolve(__dirname, '../../../node_modules'), + exec: async (cmd, args) => { + rebuildArgs = args + if (rebuildFail) + throw rebuildFail + }, +} + +const gracefulFs = require('graceful-fs') +const Edit = t.mock('../../../lib/commands/edit.js', { + child_process: childProcess, + 'graceful-fs': gracefulFs, +}) +const edit = new Edit(npm) + +t.test('npm edit', async t => { + t.teardown(() => { + rebuildArgs = null + editorBin = null + editorArgs = null + editorOpts = null + }) + + await edit.exec(['semver']) + const path = resolve(__dirname, '../../../node_modules/semver') + t.strictSame(editorBin, EDITOR, 'used the correct editor') + t.strictSame(editorArgs, [path], 'edited the correct directory') + t.strictSame(editorOpts, { stdio: 'inherit' }, 'passed the correct opts') + t.strictSame(rebuildArgs, [path], 'passed the correct path to rebuild') +}) + +t.test('rebuild fails', async t => { + t.teardown(() => { + rebuildFail = null + rebuildArgs = null + editorBin = null + editorArgs = null + editorOpts = null + }) + + rebuildFail = new Error('test error') + await t.rejects( + edit.exec(['semver']), + { message: 'test error' } + ) + const path = resolve(__dirname, '../../../node_modules/semver') + t.strictSame(editorBin, EDITOR, 'used the correct editor') + t.strictSame(editorArgs, [path], 'edited the correct directory') + t.strictSame(editorOpts, { stdio: 'inherit' }, 'passed the correct opts') + t.strictSame(rebuildArgs, [path], 'passed the correct path to rebuild') +}) + +t.test('npm edit editor has flags', async t => { + EDITOR = 'code -w' + t.teardown(() => { + rebuildArgs = null + editorBin = null + editorArgs = null + editorOpts = null + EDITOR = 'vim' + }) + + await edit.exec(['semver']) + + const path = resolve(__dirname, '../../../node_modules/semver') + t.strictSame(editorBin, 'code', 'used the correct editor') + t.strictSame(editorArgs, ['-w', path], 'edited the correct directory, keeping flags') + t.strictSame(editorOpts, { stdio: 'inherit' }, 'passed the correct opts') + t.strictSame(rebuildArgs, [path], 'passed the correct path to rebuild') +}) + +t.test('npm edit no args', async t => { + await t.rejects( + edit.exec([]), + /npm edit/, + 'throws usage error' + ) +}) + +t.test('npm edit lstat error propagates', async t => { + const _lstat = gracefulFs.lstat + gracefulFs.lstat = (dir, cb) => { + return cb(new Error('lstat failed')) + } + t.teardown(() => { + gracefulFs.lstat = _lstat + }) + + await t.rejects( + edit.exec(['semver']), + /lstat failed/, + 'user received correct error' + ) +}) + +t.test('npm edit editor exit code error propagates', async t => { + EDITOR_CODE = 137 + t.teardown(() => { + EDITOR_CODE = 0 + }) + + await t.rejects( + edit.exec(['semver']), + /exited with code: 137/, + 'user received correct error' + ) +}) diff --git a/deps/npm/test/lib/exec.js b/deps/npm/test/lib/commands/exec.js similarity index 52% rename from deps/npm/test/lib/exec.js rename to deps/npm/test/lib/commands/exec.js index 03a1bedf97e506..25c1f789a97ad9 100644 --- a/deps/npm/test/lib/exec.js +++ b/deps/npm/test/lib/commands/exec.js @@ -1,5 +1,5 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') const { resolve, delimiter } = require('path') const ARB_CTOR = [] @@ -82,7 +82,7 @@ const read = (options, cb) => { process.nextTick(() => cb(READ_ERROR, READ_RESULT)) } -const PATH = require('../../lib/utils/path.js') +const PATH = require('../../../lib/utils/path.js') let CI_NAME = 'travis-ci' @@ -96,7 +96,7 @@ const mocks = { 'mkdirp-infer-owner': mkdirp, }), } -const Exec = t.mock('../../lib/exec.js', mocks) +const Exec = t.mock('../../../lib/commands/exec.js', mocks) const exec = new Exec(npm) t.afterEach(() => { @@ -121,7 +121,7 @@ t.afterEach(() => { npm.globalBin = 'global-bin' }) -t.test('npx foo, bin already exists locally', t => { +t.test('npx foo, bin already exists locally', async t => { const path = t.testdir({ node_modules: { '.bin': { @@ -133,27 +133,24 @@ t.test('npx foo, bin already exists locally', t => { PROGRESS_IGNORED = true npm.localBin = resolve(path, 'node_modules', '.bin') - exec.exec(['foo', 'one arg', 'two arg'], er => { - t.error(er, 'npm exec') - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foo' }}, - args: ['one arg', 'two arg'], - cache: flatOptions.cache, - npxCache: flatOptions.npxCache, - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { - PATH: [npm.localBin, ...PATH].join(delimiter), - }, - stdio: 'inherit', - }]) - t.end() - }) + await exec.exec(['foo', 'one arg', 'two arg']) + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foo' }}, + args: ['one arg', 'two arg'], + cache: flatOptions.cache, + npxCache: flatOptions.npxCache, + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { + PATH: [npm.localBin, ...PATH].join(delimiter), + }, + stdio: 'inherit', + }]) }) -t.test('npx foo, bin already exists globally', t => { +t.test('npx foo, bin already exists globally', async t => { const path = t.testdir({ node_modules: { '.bin': { @@ -165,25 +162,22 @@ t.test('npx foo, bin already exists globally', t => { PROGRESS_IGNORED = true npm.globalBin = resolve(path, 'node_modules', '.bin') - exec.exec(['foo', 'one arg', 'two arg'], er => { - t.error(er, 'npm exec') - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foo' }}, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { - PATH: [npm.globalBin, ...PATH].join(delimiter), - }, - stdio: 'inherit', - }]) - t.end() - }) + await exec.exec(['foo', 'one arg', 'two arg']) + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foo' }}, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { + PATH: [npm.globalBin, ...PATH].join(delimiter), + }, + stdio: 'inherit', + }]) }) -t.test('npm exec foo, already present locally', t => { +t.test('npm exec foo, already present locally', async t => { const path = t.testdir() npm.localPrefix = path ARB_ACTUAL_TREE[path] = { @@ -197,25 +191,21 @@ t.test('npm exec foo, already present locally', t => { }, _from: 'foo@', } - exec.exec(['foo', 'one arg', 'two arg'], er => { - if (er) - throw er - t.strictSame(MKDIRPS, [], 'no need to make any dirs') - t.match(ARB_CTOR, [{ path }]) - t.strictSame(ARB_REIFY, [], 'no need to reify anything') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foo' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH: process.env.PATH }, - stdio: 'inherit', - }]) - t.end() - }) + await exec.exec(['foo', 'one arg', 'two arg']) + t.strictSame(MKDIRPS, [], 'no need to make any dirs') + t.match(ARB_CTOR, [{ path }]) + t.strictSame(ARB_REIFY, [], 'no need to reify anything') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foo' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH: process.env.PATH }, + stdio: 'inherit', + }]) }) t.test('npm exec , run interactive shell', t => { @@ -224,113 +214,97 @@ t.test('npm exec , run interactive shell', t => { process.stdin.isTTY = true t.teardown(() => process.stdin.isTTY = isTTY) - const run = (t, doRun, cb) => { + const run = async (t, doRun) => { LOG_WARN.length = 0 ARB_CTOR.length = 0 MKDIRPS.length = 0 ARB_REIFY.length = 0 npm._mockOutputs.length = 0 - exec.exec([], er => { - if (er) - throw er - t.strictSame(MKDIRPS, [], 'no need to make any dirs') - t.strictSame(ARB_CTOR, [], 'no need to instantiate arborist') - t.strictSame(ARB_REIFY, [], 'no need to reify anything') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - if (doRun) { - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'shell-cmd' } }, - args: [], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH: process.env.PATH }, - stdio: 'inherit', - }]) - } else - t.strictSame(RUN_SCRIPTS, []) - - RUN_SCRIPTS.length = 0 - cb() - }) + await exec.exec([]) + t.strictSame(MKDIRPS, [], 'no need to make any dirs') + t.strictSame(ARB_CTOR, [], 'no need to instantiate arborist') + t.strictSame(ARB_REIFY, [], 'no need to reify anything') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + if (doRun) { + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'shell-cmd' } }, + args: [], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH: process.env.PATH }, + stdio: 'inherit', + }]) + } else + t.strictSame(RUN_SCRIPTS, []) + + RUN_SCRIPTS.length = 0 } - t.test('print message when tty and not in CI', t => { + t.test('print message when tty and not in CI', async t => { CI_NAME = null process.stdin.isTTY = true - run(t, true, () => { - t.strictSame(LOG_WARN, []) - t.strictSame(npm._mockOutputs, [ - [`\nEntering npm script environment at location:\n${process.cwd()}\nType 'exit' or ^D when finished\n`], - ], 'printed message about interactive shell') - t.end() - }) + await run(t, true) + t.strictSame(LOG_WARN, []) + t.strictSame(npm._mockOutputs, [ + [`\nEntering npm script environment at location:\n${process.cwd()}\nType 'exit' or ^D when finished\n`], + ], 'printed message about interactive shell') }) - t.test('print message with color when tty and not in CI', t => { + t.test('print message with color when tty and not in CI', async t => { CI_NAME = null process.stdin.isTTY = true npm.color = true flatOptions.color = true - run(t, true, () => { - t.strictSame(LOG_WARN, []) - t.strictSame(npm._mockOutputs, [ - [`\u001b[0m\u001b[0m\n\u001b[0mEntering npm script environment\u001b[0m\u001b[0m at location:\u001b[0m\n\u001b[0m\u001b[2m${process.cwd()}\u001b[22m\u001b[0m\u001b[1m\u001b[22m\n\u001b[1mType 'exit' or ^D when finished\u001b[22m\n\u001b[1m\u001b[22m`], - ], 'printed message about interactive shell') - t.end() - }) + await run(t, true) + t.strictSame(LOG_WARN, []) + t.strictSame(npm._mockOutputs, [ + [`\u001b[0m\u001b[0m\n\u001b[0mEntering npm script environment\u001b[0m\u001b[0m at location:\u001b[0m\n\u001b[0m\u001b[2m${process.cwd()}\u001b[22m\u001b[0m\u001b[1m\u001b[22m\n\u001b[1mType 'exit' or ^D when finished\u001b[22m\n\u001b[1m\u001b[22m`], + ], 'printed message about interactive shell') }) - t.test('no message when not TTY', t => { + t.test('no message when not TTY', async t => { CI_NAME = null process.stdin.isTTY = false - run(t, true, () => { - t.strictSame(LOG_WARN, []) - t.strictSame(npm._mockOutputs, [], 'no message about interactive shell') - t.end() - }) + await run(t, true) + t.strictSame(LOG_WARN, []) + t.strictSame(npm._mockOutputs, [], 'no message about interactive shell') }) - t.test('print warning when in CI and interactive', t => { + t.test('print warning when in CI and interactive', async t => { CI_NAME = 'travis-ci' process.stdin.isTTY = true - run(t, false, () => { - t.strictSame(LOG_WARN, [ - ['exec', 'Interactive mode disabled in CI environment'], - ]) - t.strictSame(npm._mockOutputs, [], 'no message about interactive shell') - t.end() - }) + await run(t, false) + t.strictSame(LOG_WARN, [ + ['exec', 'Interactive mode disabled in CI environment'], + ]) + t.strictSame(npm._mockOutputs, [], 'no message about interactive shell') }) - t.test('not defined script-shell config value', t => { + t.test('not defined script-shell config value', async t => { CI_NAME = null process.stdin.isTTY = true config['script-shell'] = undefined - exec.exec([], er => { - if (er) - throw er + await exec.exec([]) - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: /sh|cmd/ } }, - }]) + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: /sh|cmd/ } }, + }]) - LOG_WARN.length = 0 - ARB_CTOR.length = 0 - MKDIRPS.length = 0 - ARB_REIFY.length = 0 - npm._mockOutputs.length = 0 - RUN_SCRIPTS.length = 0 - t.end() - }) + LOG_WARN.length = 0 + ARB_CTOR.length = 0 + MKDIRPS.length = 0 + ARB_REIFY.length = 0 + npm._mockOutputs.length = 0 + RUN_SCRIPTS.length = 0 }) t.end() }) -t.test('npm exec foo, not present locally or in central loc', t => { +t.test('npm exec foo, not present locally or in central loc', async t => { const path = t.testdir() const installDir = resolve('npx-cache-dir/f7fbba6e0636f890') npm.localPrefix = path @@ -348,29 +322,25 @@ t.test('npm exec foo, not present locally or in central loc', t => { }, _from: 'foo@', } - exec.exec(['foo', 'one arg', 'two arg'], er => { - if (er) - throw er - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ path }]) - t.match(ARB_REIFY, [{add: ['foo@'], legacyPeerDeps: false}], 'need to install foo@') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foo' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) - t.end() - }) + await exec.exec(['foo', 'one arg', 'two arg']) + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ path }]) + t.match(ARB_REIFY, [{add: ['foo@'], legacyPeerDeps: false}], 'need to install foo@') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foo' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) }) -t.test('npm exec foo, not present locally but in central loc', t => { +t.test('npm exec foo, not present locally but in central loc', async t => { const path = t.testdir() const installDir = resolve('npx-cache-dir/f7fbba6e0636f890') npm.localPrefix = path @@ -388,29 +358,25 @@ t.test('npm exec foo, not present locally but in central loc', t => { }, _from: 'foo@', } - exec.exec(['foo', 'one arg', 'two arg'], er => { - if (er) - throw er - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ path }]) - t.match(ARB_REIFY, [], 'no need to install again, already there') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foo' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) - t.end() - }) + await exec.exec(['foo', 'one arg', 'two arg']) + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ path }]) + t.match(ARB_REIFY, [], 'no need to install again, already there') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foo' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) }) -t.test('npm exec foo, present locally but wrong version', t => { +t.test('npm exec foo, present locally but wrong version', async t => { const path = t.testdir() const installDir = resolve('npx-cache-dir/2badf4630f1cfaad') npm.localPrefix = path @@ -428,29 +394,25 @@ t.test('npm exec foo, present locally but wrong version', t => { }, _from: 'foo@2.x', } - exec.exec(['foo@2.x', 'one arg', 'two arg'], er => { - if (er) - throw er - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ path }]) - t.match(ARB_REIFY, [{ add: ['foo@2.x'], legacyPeerDeps: false }], 'need to add foo@2.x') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foo' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) - t.end() - }) + await exec.exec(['foo@2.x', 'one arg', 'two arg']) + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ path }]) + t.match(ARB_REIFY, [{ add: ['foo@2.x'], legacyPeerDeps: false }], 'need to add foo@2.x') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foo' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) }) -t.test('npm exec --package=foo bar', t => { +t.test('npm exec --package=foo bar', async t => { const path = t.testdir() npm.localPrefix = path ARB_ACTUAL_TREE[path] = { @@ -466,28 +428,24 @@ t.test('npm exec --package=foo bar', t => { } config.package = ['foo'] flatOptions.package = ['foo'] - exec.exec(['bar', 'one arg', 'two arg'], er => { - if (er) - throw er - t.strictSame(MKDIRPS, [], 'no need to make any dirs') - t.match(ARB_CTOR, [{ path }]) - t.strictSame(ARB_REIFY, [], 'no need to reify anything') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'bar' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH: process.env.PATH }, - stdio: 'inherit', - }]) - t.end() - }) + await exec.exec(['bar', 'one arg', 'two arg']) + t.strictSame(MKDIRPS, [], 'no need to make any dirs') + t.match(ARB_CTOR, [{ path }]) + t.strictSame(ARB_REIFY, [], 'no need to reify anything') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'bar' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH: process.env.PATH }, + stdio: 'inherit', + }]) }) -t.test('npm exec @foo/bar -- --some=arg, locally installed', t => { +t.test('npm exec @foo/bar -- --some=arg, locally installed', async t => { const foobarManifest = { name: '@foo/bar', version: '1.2.3', @@ -508,28 +466,24 @@ t.test('npm exec @foo/bar -- --some=arg, locally installed', t => { children: new Map([['@foo/bar', { name: '@foo/bar', version: '1.2.3' }]]), } MANIFESTS['@foo/bar'] = foobarManifest - exec.exec(['@foo/bar', '--some=arg'], er => { - if (er) - throw er - t.strictSame(MKDIRPS, [], 'no need to make any dirs') - t.match(ARB_CTOR, [{ path }]) - t.strictSame(ARB_REIFY, [], 'no need to reify anything') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'bar' } }, - args: ['--some=arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH: process.env.PATH }, - stdio: 'inherit', - }]) - t.end() - }) + await exec.exec(['@foo/bar', '--some=arg']) + t.strictSame(MKDIRPS, [], 'no need to make any dirs') + t.match(ARB_CTOR, [{ path }]) + t.strictSame(ARB_REIFY, [], 'no need to reify anything') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'bar' } }, + args: ['--some=arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH: process.env.PATH }, + stdio: 'inherit', + }]) }) -t.test('npm exec @foo/bar, with same bin alias and no unscoped named bin, locally installed', t => { +t.test('npm exec @foo/bar, with same bin alias and no unscoped named bin, locally installed', async t => { const foobarManifest = { name: '@foo/bar', version: '1.2.3', @@ -551,28 +505,24 @@ t.test('npm exec @foo/bar, with same bin alias and no unscoped named bin, locall children: new Map([['@foo/bar', { name: '@foo/bar', version: '1.2.3' }]]), } MANIFESTS['@foo/bar'] = foobarManifest - exec.exec(['@foo/bar', 'one arg', 'two arg'], er => { - if (er) - throw er - t.strictSame(MKDIRPS, [], 'no need to make any dirs') - t.match(ARB_CTOR, [{ path }]) - t.strictSame(ARB_REIFY, [], 'no need to reify anything') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'baz' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH: process.env.PATH }, - stdio: 'inherit', - }]) - t.end() - }) + await exec.exec(['@foo/bar', 'one arg', 'two arg']) + t.strictSame(MKDIRPS, [], 'no need to make any dirs') + t.match(ARB_CTOR, [{ path }]) + t.strictSame(ARB_REIFY, [], 'no need to reify anything') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'baz' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH: process.env.PATH }, + stdio: 'inherit', + }]) }) -t.test('npm exec @foo/bar, with different bin alias and no unscoped named bin, locally installed', t => { +t.test('npm exec @foo/bar, with different bin alias and no unscoped named bin, locally installed', async t => { const path = t.testdir() npm.localPrefix = path ARB_ACTUAL_TREE[path] = { @@ -589,22 +539,22 @@ t.test('npm exec @foo/bar, with different bin alias and no unscoped named bin, l _from: 'foo@', _id: '@foo/bar@1.2.3', } - exec.exec(['@foo/bar'], er => { - t.match(er, { + await t.rejects( + exec.exec(['@foo/bar']), + { message: 'could not determine executable to run', pkgid: '@foo/bar@1.2.3', - }) - t.end() - }) + } + ) }) -t.test('run command with 2 packages, need install, verify sort', t => { +t.test('run command with 2 packages, need install, verify sort', async t => { // test both directions, should use same install dir both times // also test the read() call here, verify that the prompts match const cases = [['foo', 'bar'], ['bar', 'foo']] t.plan(cases.length) for (const packages of cases) { - t.test(packages.join(', '), t => { + t.test(packages.join(', '), async t => { config.package = packages const add = packages.map(p => `${p}@`).sort((a, b) => a.localeCompare(b, 'en')) const path = t.testdir() @@ -632,31 +582,27 @@ t.test('run command with 2 packages, need install, verify sort', t => { }, _from: 'bar@', } - exec.exec(['foobar', 'one arg', 'two arg'], er => { - if (er) - throw er - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ path }]) - t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foobar' } }, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) - t.end() - }) + await exec.exec(['foobar', 'one arg', 'two arg']) + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ path }]) + t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foobar' } }, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) }) } }) -t.test('npm exec foo, no bin in package', t => { +t.test('npm exec foo, no bin in package', async t => { const path = t.testdir() npm.localPrefix = path ARB_ACTUAL_TREE[path] = { @@ -668,16 +614,16 @@ t.test('npm exec foo, no bin in package', t => { _from: 'foo@', _id: 'foo@1.2.3', } - exec.exec(['foo'], er => { - t.match(er, { + await t.rejects( + exec.exec(['foo']), + { message: 'could not determine executable to run', pkgid: 'foo@1.2.3', - }) - t.end() - }) + } + ) }) -t.test('npm exec foo, many bins in package, none named foo', t => { +t.test('npm exec foo, many bins in package, none named foo', async t => { const path = t.testdir() npm.localPrefix = path ARB_ACTUAL_TREE[path] = { @@ -693,16 +639,16 @@ t.test('npm exec foo, many bins in package, none named foo', t => { _from: 'foo@', _id: 'foo@1.2.3', } - exec.exec(['foo'], er => { - t.match(er, { + await t.rejects( + exec.exec(['foo']), + { message: 'could not determine executable to run', pkgid: 'foo@1.2.3', - }) - t.end() - }) + } + ) }) -t.test('npm exec -p foo -c "ls -laF"', t => { +t.test('npm exec -p foo -c "ls -laF"', async t => { const path = t.testdir() npm.localPrefix = path config.package = ['foo'] @@ -715,35 +661,31 @@ t.test('npm exec -p foo -c "ls -laF"', t => { version: '1.2.3', _from: 'foo@', } - exec.exec([], er => { - if (er) - throw er - t.strictSame(MKDIRPS, [], 'no need to make any dirs') - t.match(ARB_CTOR, [{ path }]) - t.strictSame(ARB_REIFY, [], 'no need to reify anything') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'ls -laF' } }, - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH: process.env.PATH }, - stdio: 'inherit', - }]) - t.end() - }) + await exec.exec([]) + t.strictSame(MKDIRPS, [], 'no need to make any dirs') + t.match(ARB_CTOR, [{ path }]) + t.strictSame(ARB_REIFY, [], 'no need to reify anything') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'ls -laF' } }, + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH: process.env.PATH }, + stdio: 'inherit', + }]) }) -t.test('positional args and --call together is an error', t => { +t.test('positional args and --call together is an error', async t => { config.call = 'true' - exec.exec(['foo'], er => { - t.equal(er, exec.usage) - t.end() - }) + await t.rejects( + exec.exec(['foo']), + exec.usage + ) }) -t.test('prompt when installs are needed if not already present and shell is a TTY', t => { +t.test('prompt when installs are needed if not already present and shell is a TTY', async t => { const stdoutTTY = process.stdout.isTTY const stdinTTY = process.stdin.isTTY t.teardown(() => { @@ -787,32 +729,28 @@ t.test('prompt when installs are needed if not already present and shell is a TT }, _from: 'bar@', } - exec.exec(['foobar'], er => { - if (er) - throw er - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ path }]) - t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foobar' } }, - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) - t.strictSame(READ, [{ - prompt: 'Need to install the following packages:\n bar\n foo\nOk to proceed? ', - default: 'y', - }]) - t.end() - }) + await exec.exec(['foobar']) + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ path }]) + t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foobar' } }, + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) + t.strictSame(READ, [{ + prompt: 'Need to install the following packages:\n bar\n foo\nOk to proceed? ', + default: 'y', + }]) }) -t.test('skip prompt when installs are needed if not already present and shell is not a tty (multiple packages)', t => { +t.test('skip prompt when installs are needed if not already present and shell is not a tty (multiple packages)', async t => { const stdoutTTY = process.stdout.isTTY const stdinTTY = process.stdin.isTTY t.teardown(() => { @@ -856,30 +794,26 @@ t.test('skip prompt when installs are needed if not already present and shell is }, _from: 'bar@', } - exec.exec(['foobar'], er => { - if (er) - throw er - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ path }]) - t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foobar' } }, - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) - t.strictSame(READ, [], 'should not have prompted') - t.strictSame(LOG_WARN, [['exec', 'The following packages were not found and will be installed: bar, foo']], 'should have printed a warning') - t.end() - }) + await exec.exec(['foobar']) + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ path }]) + t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install both packages') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foobar' } }, + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) + t.strictSame(READ, [], 'should not have prompted') + t.strictSame(LOG_WARN, [['exec', 'The following packages were not found and will be installed: bar, foo']], 'should have printed a warning') }) -t.test('skip prompt when installs are needed if not already present and shell is not a tty (single package)', t => { +t.test('skip prompt when installs are needed if not already present and shell is not a tty (single package)', async t => { const stdoutTTY = process.stdout.isTTY const stdinTTY = process.stdin.isTTY t.teardown(() => { @@ -915,30 +849,26 @@ t.test('skip prompt when installs are needed if not already present and shell is }, _from: 'foo@', } - exec.exec(['foobar'], er => { - if (er) - throw er - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ path }]) - t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install the package') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foobar' } }, - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { PATH }, - stdio: 'inherit', - }]) - t.strictSame(READ, [], 'should not have prompted') - t.strictSame(LOG_WARN, [['exec', 'The following package was not found and will be installed: foo']], 'should have printed a warning') - t.end() - }) + await exec.exec(['foobar']) + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ path }]) + t.match(ARB_REIFY, [{add, legacyPeerDeps: false}], 'need to install the package') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + const PATH = `${resolve(installDir, 'node_modules', '.bin')}${delimiter}${process.env.PATH}` + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foobar' } }, + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { PATH }, + stdio: 'inherit', + }]) + t.strictSame(READ, [], 'should not have prompted') + t.strictSame(LOG_WARN, [['exec', 'The following package was not found and will be installed: foo']], 'should have printed a warning') }) -t.test('abort if prompt rejected', t => { +t.test('abort if prompt rejected', async t => { const stdoutTTY = process.stdout.isTTY const stdinTTY = process.stdin.isTTY t.teardown(() => { @@ -981,22 +911,23 @@ t.test('abort if prompt rejected', t => { }, _from: 'bar@', } - exec.exec(['foobar'], er => { - t.match(er, /canceled/, 'should be canceled') - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ path }]) - t.strictSame(ARB_REIFY, [], 'no install performed') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.strictSame(RUN_SCRIPTS, []) - t.strictSame(READ, [{ - prompt: 'Need to install the following packages:\n bar\n foo\nOk to proceed? ', - default: 'y', - }]) - t.end() - }) + await t.rejects( + exec.exec(['foobar']), + /canceled/, + 'should be canceled' + ) + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ path }]) + t.strictSame(ARB_REIFY, [], 'no install performed') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.strictSame(RUN_SCRIPTS, []) + t.strictSame(READ, [{ + prompt: 'Need to install the following packages:\n bar\n foo\nOk to proceed? ', + default: 'y', + }]) }) -t.test('abort if prompt false', t => { +t.test('abort if prompt false', async t => { const stdoutTTY = process.stdout.isTTY const stdinTTY = process.stdin.isTTY t.teardown(() => { @@ -1039,22 +970,23 @@ t.test('abort if prompt false', t => { }, _from: 'bar@', } - exec.exec(['foobar'], er => { - t.equal(er, 'canceled', 'should be canceled') - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ path }]) - t.strictSame(ARB_REIFY, [], 'no install performed') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.strictSame(RUN_SCRIPTS, []) - t.strictSame(READ, [{ - prompt: 'Need to install the following packages:\n bar\n foo\nOk to proceed? ', - default: 'y', - }]) - t.end() - }) + await t.rejects( + exec.exec(['foobar']), + 'canceled', + 'should be canceled' + ) + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ path }]) + t.strictSame(ARB_REIFY, [], 'no install performed') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.strictSame(RUN_SCRIPTS, []) + t.strictSame(READ, [{ + prompt: 'Need to install the following packages:\n bar\n foo\nOk to proceed? ', + default: 'y', + }]) }) -t.test('abort if -n provided', t => { +t.test('abort if -n provided', async t => { const stdoutTTY = process.stdout.isTTY const stdinTTY = process.stdin.isTTY t.teardown(() => { @@ -1096,19 +1028,20 @@ t.test('abort if -n provided', t => { }, _from: 'bar@', } - exec.exec(['foobar'], er => { - t.match(er, /canceled/, 'should be canceled') - t.strictSame(MKDIRPS, [installDir], 'need to make install dir') - t.match(ARB_CTOR, [{ path }]) - t.strictSame(ARB_REIFY, [], 'no install performed') - t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') - t.strictSame(RUN_SCRIPTS, []) - t.strictSame(READ, []) - t.end() - }) + await t.rejects( + exec.exec(['foobar']), + /canceled/, + 'should be canceled' + ) + t.strictSame(MKDIRPS, [installDir], 'need to make install dir') + t.match(ARB_CTOR, [{ path }]) + t.strictSame(ARB_REIFY, [], 'no install performed') + t.equal(PROGRESS_ENABLED, true, 'progress re-enabled') + t.strictSame(RUN_SCRIPTS, []) + t.strictSame(READ, []) }) -t.test('forward legacyPeerDeps opt', t => { +t.test('forward legacyPeerDeps opt', async t => { const path = t.testdir() const installDir = resolve('npx-cache-dir/f7fbba6e0636f890') npm.localPrefix = path @@ -1128,12 +1061,8 @@ t.test('forward legacyPeerDeps opt', t => { } config.yes = true flatOptions.legacyPeerDeps = true - exec.exec(['foo'], er => { - if (er) - throw er - t.match(ARB_REIFY, [{add: ['foo@'], legacyPeerDeps: true}], 'need to install foo@ using legacyPeerDeps opt') - t.end() - }) + await exec.exec(['foo']) + t.match(ARB_REIFY, [{add: ['foo@'], legacyPeerDeps: true}], 'need to install foo@ using legacyPeerDeps opt') }) t.test('workspaces', t => { @@ -1169,59 +1098,43 @@ t.test('workspaces', t => { PROGRESS_IGNORED = true npm.localBin = resolve(npm.localPrefix, 'node_modules/.bin') - t.test('with args, run scripts in the context of a workspace', t => { - exec.execWorkspaces(['foo', 'one arg', 'two arg'], ['a', 'b'], er => { - if (er) - throw er + t.test('with args, run scripts in the context of a workspace', async t => { + await exec.execWorkspaces(['foo', 'one arg', 'two arg'], ['a', 'b']) - t.match(RUN_SCRIPTS, [{ - pkg: { scripts: { npx: 'foo' }}, - args: ['one arg', 'two arg'], - banner: false, - path: process.cwd(), - stdioString: true, - event: 'npx', - env: { - PATH: [npm.localBin, ...PATH].join(delimiter), - }, - stdio: 'inherit', - }]) - t.end() - }) + t.match(RUN_SCRIPTS, [{ + pkg: { scripts: { npx: 'foo' }}, + args: ['one arg', 'two arg'], + banner: false, + path: process.cwd(), + stdioString: true, + event: 'npx', + env: { + PATH: [npm.localBin, ...PATH].join(delimiter), + }, + stdio: 'inherit', + }]) }) t.test('no args, spawn interactive shell', async t => { CI_NAME = null process.stdin.isTTY = true - await new Promise((res, rej) => { - exec.execWorkspaces([], ['a'], er => { - if (er) - return rej(er) - - t.strictSame(LOG_WARN, []) - t.strictSame(npm._mockOutputs, [ - [`\nEntering npm script environment in workspace a@1.0.0 at location:\n${resolve(npm.localPrefix, 'packages/a')}\nType 'exit' or ^D when finished\n`], - ], 'printed message about interactive shell') - res() - }) - }) + await exec.execWorkspaces([], ['a']) + + t.strictSame(LOG_WARN, []) + t.strictSame(npm._mockOutputs, [ + [`\nEntering npm script environment in workspace a@1.0.0 at location:\n${resolve(npm.localPrefix, 'packages/a')}\nType 'exit' or ^D when finished\n`], + ], 'printed message about interactive shell') npm.color = true flatOptions.color = true npm._mockOutputs.length = 0 - await new Promise((res, rej) => { - exec.execWorkspaces([], ['a'], er => { - if (er) - return rej(er) - - t.strictSame(LOG_WARN, []) - t.strictSame(npm._mockOutputs, [ - [`\u001b[0m\u001b[0m\n\u001b[0mEntering npm script environment\u001b[0m\u001b[0m in workspace \u001b[32ma@1.0.0\u001b[39m at location:\u001b[0m\n\u001b[0m\u001b[2m${resolve(npm.localPrefix, 'packages/a')}\u001b[22m\u001b[0m\u001b[1m\u001b[22m\n\u001b[1mType 'exit' or ^D when finished\u001b[22m\n\u001b[1m\u001b[22m`], - ], 'printed message about interactive shell') - res() - }) - }) + await exec.execWorkspaces([], ['a']) + + t.strictSame(LOG_WARN, []) + t.strictSame(npm._mockOutputs, [ + [`\u001b[0m\u001b[0m\n\u001b[0mEntering npm script environment\u001b[0m\u001b[0m in workspace \u001b[32ma@1.0.0\u001b[39m at location:\u001b[0m\n\u001b[0m\u001b[2m${resolve(npm.localPrefix, 'packages/a')}\u001b[22m\u001b[0m\u001b[1m\u001b[22m\n\u001b[1mType 'exit' or ^D when finished\u001b[22m\n\u001b[1m\u001b[22m`], + ], 'printed message about interactive shell') }) t.end() diff --git a/deps/npm/test/lib/explain.js b/deps/npm/test/lib/commands/explain.js similarity index 56% rename from deps/npm/test/lib/explain.js rename to deps/npm/test/lib/commands/explain.js index ebec1361991744..63deb8bc78a4cf 100644 --- a/deps/npm/test/lib/explain.js +++ b/deps/npm/test/lib/commands/explain.js @@ -11,10 +11,10 @@ const { resolve } = require('path') const OUTPUT = [] -const Explain = t.mock('../../lib/explain.js', { +const Explain = t.mock('../../../lib/commands/explain.js', { // keep the snapshots pared down a bit, since this has its own tests. - '../../lib/utils/explain-dep.js': { + '../../../lib/utils/explain-dep.js': { explainNode: (expl, depth, color) => { return `${expl.name}@${expl.version} depth=${depth} color=${color}` }, @@ -22,29 +22,28 @@ const Explain = t.mock('../../lib/explain.js', { }) const explain = new Explain(npm) -t.test('no args throws usage', t => { - t.plan(1) - explain.exec([], er => { - t.equal(er, explain.usage) - t.end() - }) +t.test('no args throws usage', async t => { + await t.rejects( + explain.exec([]), + explain.usage + ) }) -t.test('no match throws not found', t => { +t.test('no match throws not found', async t => { npm.prefix = t.testdir() - t.plan(1) - explain.exec(['foo@1.2.3', 'node_modules/baz'], er => { - t.equal(er, 'No dependencies found matching foo@1.2.3, node_modules/baz') - }) + await t.rejects( + explain.exec(['foo@1.2.3', 'node_modules/baz']), + 'No dependencies found matching foo@1.2.3, node_modules/baz' + ) }) -t.test('invalid package name throws not found', t => { +t.test('invalid package name throws not found', async t => { npm.prefix = t.testdir() - t.plan(1) const badName = ' not a valid package name ' - explain.exec([`${badName}@1.2.3`], er => { - t.equal(er, `No dependencies found matching ${badName}@1.2.3`) - }) + await t.rejects( + explain.exec([`${badName}@1.2.3`]), + `No dependencies found matching ${badName}@1.2.3` + ) }) t.test('explain some nodes', t => { @@ -103,75 +102,51 @@ t.test('explain some nodes', t => { }), }) - t.test('works with the location', t => { + t.test('works with the location', async t => { const path = 'node_modules/foo' - explain.exec([path], er => { - if (er) - throw er - t.strictSame(OUTPUT, [['foo@1.2.3 depth=Infinity color=true']]) - t.end() - }) + await explain.exec([path]) + t.strictSame(OUTPUT, [['foo@1.2.3 depth=Infinity color=true']]) }) - t.test('works with a full actual path', t => { + + t.test('works with a full actual path', async t => { const path = resolve(npm.prefix, 'node_modules/foo') - explain.exec([path], er => { - if (er) - throw er - t.strictSame(OUTPUT, [['foo@1.2.3 depth=Infinity color=true']]) - t.end() - }) + await explain.exec([path]) + t.strictSame(OUTPUT, [['foo@1.2.3 depth=Infinity color=true']]) }) - t.test('finds all nodes by name', t => { - explain.exec(['bar'], er => { - if (er) - throw er - t.strictSame(OUTPUT, [[ - 'bar@1.2.3 depth=Infinity color=true\n\n' + - 'bar@2.3.4 depth=Infinity color=true', - ]]) - t.end() - }) + t.test('finds all nodes by name', async t => { + await explain.exec(['bar']) + t.strictSame(OUTPUT, [[ + 'bar@1.2.3 depth=Infinity color=true\n\n' + + 'bar@2.3.4 depth=Infinity color=true', + ]]) }) - t.test('finds only nodes that match the spec', t => { - explain.exec(['bar@1'], er => { - if (er) - throw er - t.strictSame(OUTPUT, [['bar@1.2.3 depth=Infinity color=true']]) - t.end() - }) + t.test('finds only nodes that match the spec', async t => { + await explain.exec(['bar@1']) + t.strictSame(OUTPUT, [['bar@1.2.3 depth=Infinity color=true']]) }) - t.test('finds extraneous nodes', t => { - explain.exec(['extra'], er => { - if (er) - throw er - t.strictSame(OUTPUT, [['extra@99.9999.999999 depth=Infinity color=true']]) - t.end() - }) + t.test('finds extraneous nodes', async t => { + await explain.exec(['extra']) + t.strictSame(OUTPUT, [['extra@99.9999.999999 depth=Infinity color=true']]) }) - t.test('json output', t => { + t.test('json output', async t => { npm.flatOptions.json = true - explain.exec(['node_modules/foo'], er => { - if (er) - throw er - t.match(JSON.parse(OUTPUT[0][0]), [{ - name: 'foo', - version: '1.2.3', - dependents: Array, - }]) - t.end() - }) + await explain.exec(['node_modules/foo']) + t.match(JSON.parse(OUTPUT[0][0]), [{ + name: 'foo', + version: '1.2.3', + dependents: Array, + }]) }) - t.test('report if no nodes found', t => { - t.plan(1) - explain.exec(['asdf/foo/bar', 'quux@1.x'], er => { - t.equal(er, 'No dependencies found matching asdf/foo/bar, quux@1.x') - t.end() - }) + t.test('report if no nodes found', async t => { + await t.rejects( + explain.exec(['asdf/foo/bar', 'quux@1.x']), + 'No dependencies found matching asdf/foo/bar, quux@1.x' + ) }) t.end() }) @@ -240,66 +215,40 @@ t.test('workspaces', async t => { }, }) - await new Promise((res, rej) => { - explain.exec(['wrappy'], err => { - if (err) - rej(err) - - t.strictSame( - OUTPUT, - [['wrappy@2.0.0 depth=Infinity color=true']], - 'should explain workspaces deps' - ) - OUTPUT.length = 0 - res() - }) - }) - - await new Promise((res, rej) => { - explain.execWorkspaces(['wrappy'], ['a'], err => { - if (err) - rej(err) - - t.strictSame( - OUTPUT, - [ - ['wrappy@2.0.0 depth=Infinity color=true'], - ], - 'should explain deps when filtering to a single ws' - ) - OUTPUT.length = 0 - res() - }) - }) + await explain.exec(['wrappy']) + t.strictSame( + OUTPUT, + [['wrappy@2.0.0 depth=Infinity color=true']], + 'should explain workspaces deps' + ) + OUTPUT.length = 0 - await new Promise((res, rej) => { - explain.execWorkspaces(['abbrev'], [], err => { - if (err) - rej(err) + await explain.execWorkspaces(['wrappy'], ['a']) - t.strictSame( - OUTPUT, - [ - ['abbrev@1.0.0 depth=Infinity color=true'], - ], - 'should explain deps of workspaces only' - ) - OUTPUT.length = 0 - res() - }) - }) + t.strictSame( + OUTPUT, + [ + ['wrappy@2.0.0 depth=Infinity color=true'], + ], + 'should explain deps when filtering to a single ws' + ) + OUTPUT.length = 0 - await new Promise((res, rej) => { - explain.execWorkspaces(['abbrev'], ['a'], err => { - t.equal( - err, - 'No dependencies found matching abbrev', - 'should throw usage if dep not found within filtered ws' - ) + await explain.execWorkspaces(['abbrev'], []) + t.strictSame( + OUTPUT, + [ + ['abbrev@1.0.0 depth=Infinity color=true'], + ], + 'should explain deps of workspaces only' + ) + OUTPUT.length = 0 - res() - }) - }) + await t.rejects( + explain.execWorkspaces(['abbrev'], ['a']), + 'No dependencies found matching abbrev', + 'should throw usage if dep not found within filtered ws' + ) }) t.test('workspaces disabled', async t => { @@ -366,15 +315,10 @@ t.test('workspaces disabled', async t => { }, }) - await new Promise((res, rej) => { - explain.npm.flatOptions.workspacesEnabled = false - explain.exec(['once'], err => { - t.equal( - err, - 'No dependencies found matching once', - 'should throw usage if dep not found when excluding ws' - ) - res() - }) - }) + npm.flatOptions.workspacesEnabled = false + await t.rejects( + explain.exec(['once']), + 'No dependencies found matching once', + 'should throw usage if dep not found when excluding ws' + ) }) diff --git a/deps/npm/test/lib/explore.js b/deps/npm/test/lib/commands/explore.js similarity index 64% rename from deps/npm/test/lib/explore.js rename to deps/npm/test/lib/commands/explore.js index fd9949e73fc4c7..4ae10afc69e77e 100644 --- a/deps/npm/test/lib/explore.js +++ b/deps/npm/test/lib/commands/explore.js @@ -45,8 +45,8 @@ const mockRunScript = ({ pkg, banner, path, event, stdio }) => { const output = [] const logs = [] const getExplore = (windows) => { - const Explore = t.mock('../../lib/explore.js', { - '../../lib/utils/is-windows.js': windows, + const Explore = t.mock('../../../lib/commands/explore.js', { + '../../../lib/utils/is-windows.js': windows, path: require('path')[windows ? 'win32' : 'posix'], 'read-package-json-fast': mockRPJ, '@npmcli/run-script': mockRunScript, @@ -74,9 +74,8 @@ const posixExplore = getExplore(false) t.test('basic interactive', t => { t.afterEach(() => output.length = 0) - t.test('windows', t => windowsExplore.exec(['pkg'], er => { - if (er) - throw er + t.test('windows', async t => { + await windowsExplore.exec(['pkg']) t.strictSame({ RPJ_CALLED, @@ -88,12 +87,10 @@ t.test('basic interactive', t => { t.strictSame(output, [ "\nExploring c:\\npm\\dir\\pkg\nType 'exit' or ^D when finished\n", ]) - t.end() - })) + }) - t.test('posix', t => posixExplore.exec(['pkg'], er => { - if (er) - throw er + t.test('posix', async t => { + await posixExplore.exec(['pkg']) t.strictSame({ RPJ_CALLED, @@ -105,8 +102,7 @@ t.test('basic interactive', t => { t.strictSame(output, [ "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", ]) - t.end() - })) + }) t.end() }) @@ -123,9 +119,8 @@ t.test('interactive tracks exit code', t => { process.exitCode = exitCode }) - t.test('windows', t => windowsExplore.exec(['pkg'], er => { - if (er) - throw er + t.test('windows', async t => { + await windowsExplore.exec(['pkg']) t.strictSame({ RPJ_CALLED, @@ -138,12 +133,10 @@ t.test('interactive tracks exit code', t => { "\nExploring c:\\npm\\dir\\pkg\nType 'exit' or ^D when finished\n", ]) t.equal(process.exitCode, 99) - t.end() - })) + }) - t.test('posix', t => posixExplore.exec(['pkg'], er => { - if (er) - throw er + t.test('posix', async t => { + await posixExplore.exec(['pkg']) t.strictSame({ RPJ_CALLED, @@ -156,49 +149,48 @@ t.test('interactive tracks exit code', t => { "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", ]) t.equal(process.exitCode, 99) - t.end() - })) + }) - t.test('posix spawn fail', t => { + t.test('posix spawn fail', async t => { RUN_SCRIPT_ERROR = Object.assign(new Error('glorb'), { code: 33, }) - posixExplore.exec(['pkg'], er => { - t.match(er, { message: 'glorb', code: 33 }) - t.strictSame(output, [ - "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", - ]) - t.equal(process.exitCode, 33) - t.end() - }) + await t.rejects( + posixExplore.exec(['pkg']), + { message: 'glorb', code: 33 } + ) + t.strictSame(output, [ + "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", + ]) + t.equal(process.exitCode, 33) }) - t.test('posix spawn fail, 0 exit code', t => { + t.test('posix spawn fail, 0 exit code', async t => { RUN_SCRIPT_ERROR = Object.assign(new Error('glorb'), { code: 0, }) - posixExplore.exec(['pkg'], er => { - t.match(er, { message: 'glorb', code: 0 }) - t.strictSame(output, [ - "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", - ]) - t.equal(process.exitCode, 1) - t.end() - }) + await t.rejects( + posixExplore.exec(['pkg']), + { message: 'glorb', code: 0 } + ) + t.strictSame(output, [ + "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", + ]) + t.equal(process.exitCode, 1) }) - t.test('posix spawn fail, no exit code', t => { + t.test('posix spawn fail, no exit code', async t => { RUN_SCRIPT_ERROR = Object.assign(new Error('command failed'), { code: 'EPROBLEM', }) - posixExplore.exec(['pkg'], er => { - t.match(er, { message: 'command failed', code: 'EPROBLEM' }) - t.strictSame(output, [ - "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", - ]) - t.equal(process.exitCode, 1) - t.end() - }) + await t.rejects( + posixExplore.exec(['pkg']), + { message: 'command failed', code: 'EPROBLEM' } + ) + t.strictSame(output, [ + "\nExploring /npm/dir/pkg\nType 'exit' or ^D when finished\n", + ]) + t.equal(process.exitCode, 1) }) t.end() @@ -207,9 +199,8 @@ t.test('interactive tracks exit code', t => { t.test('basic non-interactive', t => { t.afterEach(() => output.length = 0) - t.test('windows', t => windowsExplore.exec(['pkg', 'ls'], er => { - if (er) - throw er + t.test('windows', async t => { + await windowsExplore.exec(['pkg', 'ls']) t.strictSame({ RPJ_CALLED, @@ -219,12 +210,10 @@ t.test('basic non-interactive', t => { RUN_SCRIPT_EXEC: 'ls', }) t.strictSame(output, []) - t.end() - })) + }) - t.test('posix', t => posixExplore.exec(['pkg', 'ls'], er => { - if (er) - throw er + t.test('posix', async t => { + await posixExplore.exec(['pkg', 'ls']) t.strictSame({ RPJ_CALLED, @@ -235,7 +224,7 @@ t.test('basic non-interactive', t => { }) t.strictSame(output, []) t.end() - })) + }) t.end() }) @@ -254,11 +243,14 @@ t.test('signal fails non-interactive', t => { }) t.afterEach(() => process.exitCode = exitCode) - t.test('windows', t => windowsExplore.exec(['pkg', 'ls'], er => { - t.match(er, { - message: 'command failed', - signal: 'SIGPROBLEM', - }) + t.test('windows', async t => { + await t.rejects( + windowsExplore.exec(['pkg', 'ls']), + { + message: 'command failed', + signal: 'SIGPROBLEM', + } + ) t.strictSame({ RPJ_CALLED, @@ -268,14 +260,16 @@ t.test('signal fails non-interactive', t => { RUN_SCRIPT_EXEC: 'ls', }) t.strictSame(output, []) - t.end() - })) + }) - t.test('posix', t => posixExplore.exec(['pkg', 'ls'], er => { - t.match(er, { - message: 'command failed', - signal: 'SIGPROBLEM', - }) + t.test('posix', async t => { + await t.rejects( + posixExplore.exec(['pkg', 'ls']), + { + message: 'command failed', + signal: 'SIGPROBLEM', + } + ) t.strictSame({ RPJ_CALLED, @@ -286,7 +280,7 @@ t.test('signal fails non-interactive', t => { }) t.strictSame(output, []) t.end() - })) + }) t.end() }) @@ -305,37 +299,39 @@ t.test('usage if no pkg provided', t => { ] t.plan(noPkg.length) for (const args of noPkg) { - t.test(JSON.stringify(args), t => { - posixExplore.exec(args, er => { - t.match(er, 'Usage:') - t.strictSame({ - RPJ_CALLED, - RUN_SCRIPT_EXEC, - }, { - RPJ_CALLED: '/npm/dir/pkg/package.json', - RUN_SCRIPT_EXEC: 'ls', - }) - t.end() + t.test(JSON.stringify(args), async t => { + await t.rejects( + posixExplore.exec(args), + 'Usage:' + ) + t.strictSame({ + RPJ_CALLED, + RUN_SCRIPT_EXEC, + }, { + RPJ_CALLED: '/npm/dir/pkg/package.json', + RUN_SCRIPT_EXEC: 'ls', }) }) } }) -t.test('pkg not installed', t => { +t.test('pkg not installed', async t => { + t.teardown(() => { + logs.length = 0 + }) RPJ_ERROR = new Error('plurple') - posixExplore.exec(['pkg', 'ls'], er => { - t.strictSame({ - RPJ_CALLED, - RUN_SCRIPT_EXEC, - }, { - RPJ_CALLED: '/npm/dir/pkg/package.json', - RUN_SCRIPT_EXEC: 'ls', - }) - t.strictSame(output, []) - t.match(er, { message: 'plurple' }) - t.match(logs, [['explore', `It doesn't look like pkg is installed.`]]) - t.end() - logs.length = 0 + await t.rejects( + posixExplore.exec(['pkg', 'ls']), + { message: 'plurple' } + ) + t.strictSame({ + RPJ_CALLED, + RUN_SCRIPT_EXEC, + }, { + RPJ_CALLED: '/npm/dir/pkg/package.json', + RUN_SCRIPT_EXEC: 'ls', }) + t.strictSame(output, []) + t.match(logs, [['explore', `It doesn't look like pkg is installed.`]]) }) diff --git a/deps/npm/test/lib/find-dupes.js b/deps/npm/test/lib/commands/find-dupes.js similarity index 81% rename from deps/npm/test/lib/find-dupes.js rename to deps/npm/test/lib/commands/find-dupes.js index 17940764b94a59..c1b9c71df5a79e 100644 --- a/deps/npm/test/lib/find-dupes.js +++ b/deps/npm/test/lib/commands/find-dupes.js @@ -1,10 +1,10 @@ const t = require('tap') -const { real: mockNpm } = require('../fixtures/mock-npm') +const { real: mockNpm } = require('../../fixtures/mock-npm') t.test('should run dedupe in dryRun mode', async (t) => { t.plan(5) - const { npm, command } = mockNpm(t, { + const { Npm } = mockNpm(t, { '@npmcli/arborist': function (args) { t.ok(args, 'gets options object') t.ok(args.path, 'gets path option') @@ -17,10 +17,11 @@ t.test('should run dedupe in dryRun mode', async (t) => { t.ok(arb, 'gets arborist tree') }, }) + const npm = new Npm() await npm.load() // explicitly set to false so we can be 100% sure it's always true when it // hits arborist npm.config.set('dry-run', false) npm.config.set('prefix', 'foo') - await command('find-dupes') + await npm.exec('find-dupes', []) }) diff --git a/deps/npm/test/lib/fund.js b/deps/npm/test/lib/commands/fund.js similarity index 55% rename from deps/npm/test/lib/fund.js rename to deps/npm/test/lib/commands/fund.js index 784989827edc16..7a86389f084df6 100644 --- a/deps/npm/test/lib/fund.js +++ b/deps/npm/test/lib/commands/fund.js @@ -1,5 +1,5 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') const version = '1.0.0' const funding = { @@ -199,8 +199,8 @@ const openUrl = async (npm, url, msg) => { } else printUrl = `${msg}:\n ${url}` } -const Fund = t.mock('../../lib/fund.js', { - '../../lib/utils/open-url.js': openUrl, +const Fund = t.mock('../../../lib/commands/fund.js', { + '../../../lib/utils/open-url.js': openUrl, pacote: { manifest: (arg) => arg.name === 'ntl' ? Promise.resolve({ @@ -217,7 +217,11 @@ const npm = mockNpm({ }) const fund = new Fund(npm) -t.test('fund with no package containing funding', t => { +t.afterEach(() => { + printUrl = '' + result = '' +}) +t.test('fund with no package containing funding', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'no-funding-package', @@ -225,213 +229,175 @@ t.test('fund with no package containing funding', t => { }), }) - fund.exec([], (err) => { - t.error(err, 'should not error out') - t.matchSnapshot(result, 'should print empty funding info') - result = '' - t.end() - }) + await fund.exec([]) + t.matchSnapshot(result, 'should print empty funding info') }) -t.test('fund in which same maintainer owns all its deps', t => { +t.test('fund in which same maintainer owns all its deps', async t => { npm.prefix = t.testdir(maintainerOwnsAllDeps) - fund.exec([], (err) => { - t.error(err, 'should not error out') - t.matchSnapshot(result, 'should print stack packages together') - result = '' - t.end() - }) + await fund.exec([]) + t.matchSnapshot(result, 'should print stack packages together') }) -t.test('fund in which same maintainer owns all its deps, using --json option', t => { +t.test('fund in which same maintainer owns all its deps, using --json option', async t => { config.json = true npm.prefix = t.testdir(maintainerOwnsAllDeps) - fund.exec([], (err) => { - t.error(err, 'should not error out') - t.same( - JSON.parse(result), - { - length: 3, - name: 'maintainer-owns-all-deps', - version: '1.0.0', - funding: { type: 'individual', url: 'http://example.com/donate' }, - dependencies: { - 'dep-bar': { - version: '1.0.0', - funding: { type: 'individual', url: 'http://example.com/donate' }, - }, - 'dep-foo': { - version: '1.0.0', - funding: { type: 'individual', url: 'http://example.com/donate' }, - dependencies: { - 'dep-sub-foo': { - version: '1.0.0', - funding: { type: 'individual', url: 'http://example.com/donate' }, - }, + await fund.exec([]) + t.same( + JSON.parse(result), + { + length: 3, + name: 'maintainer-owns-all-deps', + version: '1.0.0', + funding: { type: 'individual', url: 'http://example.com/donate' }, + dependencies: { + 'dep-bar': { + version: '1.0.0', + funding: { type: 'individual', url: 'http://example.com/donate' }, + }, + 'dep-foo': { + version: '1.0.0', + funding: { type: 'individual', url: 'http://example.com/donate' }, + dependencies: { + 'dep-sub-foo': { + version: '1.0.0', + funding: { type: 'individual', url: 'http://example.com/donate' }, }, }, }, }, - 'should print stack packages together' - ) - - result = '' - config.json = false - t.end() - }) + }, + 'should print stack packages together' + ) + config.json = false }) -t.test('fund containing multi-level nested deps with no funding', t => { +t.test('fund containing multi-level nested deps with no funding', async t => { npm.prefix = t.testdir(nestedNoFundingPackages) - fund.exec([], (err) => { - t.error(err, 'should not error out') - t.matchSnapshot( - result, - 'should omit dependencies with no funding declared' - ) - - result = '' - t.end() - }) + await fund.exec([]) + t.matchSnapshot( + result, + 'should omit dependencies with no funding declared' + ) + t.end() }) -t.test('fund containing multi-level nested deps with no funding, using --json option', t => { +t.test('fund containing multi-level nested deps with no funding, using --json option', async t => { npm.prefix = t.testdir(nestedNoFundingPackages) config.json = true - fund.exec([], (err) => { - t.error(err, 'should not error out') - t.same( - JSON.parse(result), - { - length: 2, - name: 'nested-no-funding-packages', - version: '1.0.0', - dependencies: { - lorem: { - version: '1.0.0', - funding: { url: 'https://example.com/lorem' }, - }, - bar: { - version: '1.0.0', - funding: { type: 'individual', url: 'http://example.com/donate' }, - }, + await fund.exec([]) + t.same( + JSON.parse(result), + { + length: 2, + name: 'nested-no-funding-packages', + version: '1.0.0', + dependencies: { + lorem: { + version: '1.0.0', + funding: { url: 'https://example.com/lorem' }, + }, + bar: { + version: '1.0.0', + funding: { type: 'individual', url: 'http://example.com/donate' }, }, }, - 'should omit dependencies with no funding declared in json output' - ) - - result = '' - config.json = false - t.end() - }) + }, + 'should omit dependencies with no funding declared in json output' + ) + config.json = false }) -t.test('fund containing multi-level nested deps with no funding, using --json option', t => { +t.test('fund containing multi-level nested deps with no funding, using --json option', async t => { npm.prefix = t.testdir(nestedMultipleFundingPackages) config.json = true - fund.exec([], (err) => { - t.error(err, 'should not error out') - t.same( - JSON.parse(result), - { - length: 2, - name: 'nested-multiple-funding-packages', - version: '1.0.0', - funding: [ - { - url: 'https://one.example.com', - }, - { - url: 'https://two.example.com', - }, - ], - dependencies: { - bar: { - version: '1.0.0', - funding: [ - { - url: 'http://collective.example.com', - }, - { - url: 'http://sponsors.example.com/you', - }, - ], - }, - foo: { - version: '1.0.0', - funding: [ - { - url: 'http://example.com', - }, - { - url: 'http://sponsors.example.com/me', - }, - { - url: 'http://collective.example.com', - }, - ], - }, + await fund.exec([]) + t.same( + JSON.parse(result), + { + length: 2, + name: 'nested-multiple-funding-packages', + version: '1.0.0', + funding: [ + { + url: 'https://one.example.com', + }, + { + url: 'https://two.example.com', + }, + ], + dependencies: { + bar: { + version: '1.0.0', + funding: [ + { + url: 'http://collective.example.com', + }, + { + url: 'http://sponsors.example.com/you', + }, + ], + }, + foo: { + version: '1.0.0', + funding: [ + { + url: 'http://example.com', + }, + { + url: 'http://sponsors.example.com/me', + }, + { + url: 'http://collective.example.com', + }, + ], }, }, - 'should list multiple funding entries in json output' - ) - - result = '' - config.json = false - t.end() - }) + }, + 'should list multiple funding entries in json output' + ) + config.json = false }) -t.test('fund does not support global', t => { +t.test('fund does not support global', async t => { npm.prefix = t.testdir({}) config.global = true - fund.exec([], (err) => { - t.match(err.code, 'EFUNDGLOBAL', 'should throw EFUNDGLOBAL error') - - result = '' - config.global = false - t.end() - }) + await t.rejects( + fund.exec([]), + { code: 'EFUNDGLOBAL' }, + 'should throw EFUNDGLOBAL error' + ) + config.global = false }) -t.test('fund using package argument', t => { +t.test('fund using package argument', async t => { npm.prefix = t.testdir(maintainerOwnsAllDeps) - fund.exec(['.'], (err) => { - t.error(err, 'should not error out') - t.matchSnapshot(printUrl, 'should open funding url') - - printUrl = '' - t.end() - }) + await fund.exec(['.']) + t.matchSnapshot(printUrl, 'should open funding url') }) -t.test('fund does not support global, using --json option', t => { +t.test('fund does not support global, using --json option', async t => { npm.prefix = t.testdir({}) config.global = true config.json = true - fund.exec([], (err) => { - t.equal(err.code, 'EFUNDGLOBAL', 'should use EFUNDGLOBAL error code') - t.equal( - err.message, - '`npm fund` does not support global packages', - 'should use expected error msg' - ) - - config.global = false - config.json = false - t.end() - }) + await t.rejects( + fund.exec([]), + { code: 'EFUNDGLOBAL', message: '`npm fund` does not support global packages' }, + 'should use expected error msg' + ) + config.global = false + config.json = false }) -t.test('fund using string shorthand', t => { +t.test('fund using string shorthand', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'funding-string-shorthand', @@ -440,28 +406,18 @@ t.test('fund using string shorthand', t => { }), }) - fund.exec(['.'], (err) => { - t.error(err, 'should not error out') - t.matchSnapshot(printUrl, 'should open string-only url') - - printUrl = '' - t.end() - }) + await fund.exec(['.']) + t.matchSnapshot(printUrl, 'should open string-only url') }) -t.test('fund using nested packages with multiple sources', t => { +t.test('fund using nested packages with multiple sources', async t => { npm.prefix = t.testdir(nestedMultipleFundingPackages) - fund.exec(['.'], (err) => { - t.error(err, 'should not error out') - t.matchSnapshot(result, 'should prompt with all available URLs') - - result = '' - t.end() - }) + await fund.exec(['.']) + t.matchSnapshot(result, 'should prompt with all available URLs') }) -t.test('fund using symlink ref', t => { +t.test('fund using symlink ref', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'using-symlink-ref', @@ -480,34 +436,27 @@ t.test('fund using symlink ref', t => { }) // using symlinked ref - fund.exec(['./node_modules/a'], (err) => { - t.error(err, 'should not error out') - t.match( - printUrl, - 'http://example.com/a', - 'should retrieve funding url from symlink' - ) - - printUrl = '' - - // using target ref - fund.exec(['./a'], (err) => { - t.error(err, 'should not error out') - - t.match( - printUrl, - 'http://example.com/a', - 'should retrieve funding url from symlink target' - ) - - printUrl = '' - result = '' - t.end() - }) - }) + await fund.exec(['./node_modules/a']) + t.match( + printUrl, + 'http://example.com/a', + 'should retrieve funding url from symlink' + ) + + printUrl = '' + result = '' + + // using target ref + await fund.exec(['./a']) + + t.match( + printUrl, + 'http://example.com/a', + 'should retrieve funding url from symlink target' + ) }) -t.test('fund using data from actual tree', t => { +t.test('fund using data from actual tree', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'using-actual-tree', @@ -541,134 +490,91 @@ t.test('fund using data from actual tree', t => { }) // using symlinked ref - fund.exec(['a'], (err) => { - t.error(err, 'should not error out') - t.match( - printUrl, - 'http://example.com/_AAA', - 'should retrieve fund info from actual tree, using greatest version found' - ) - - printUrl = '' - t.end() - }) + await fund.exec(['a']) + t.match( + printUrl, + 'http://example.com/_AAA', + 'should retrieve fund info from actual tree, using greatest version found' + ) }) -t.test('fund using nested packages with multiple sources, with a source number', t => { +t.test('fund using nested packages with multiple sources, with a source number', async t => { npm.prefix = t.testdir(nestedMultipleFundingPackages) config.which = '1' - fund.exec(['.'], (err) => { - t.error(err, 'should not error out') - t.matchSnapshot(printUrl, 'should open the numbered URL') - - config.which = null - printUrl = '' - t.end() - }) + await fund.exec(['.']) + t.matchSnapshot(printUrl, 'should open the numbered URL') + config.which = null }) -t.test('fund using pkg name while having conflicting versions', t => { +t.test('fund using pkg name while having conflicting versions', async t => { npm.prefix = t.testdir(conflictingFundingPackages) config.which = '1' - fund.exec(['foo'], (err) => { - t.error(err, 'should not error out') - t.matchSnapshot(printUrl, 'should open greatest version') - - printUrl = '' - t.end() - }) + await fund.exec(['foo']) + t.matchSnapshot(printUrl, 'should open greatest version') }) -t.test('fund using package argument with no browser, using --json option', t => { +t.test('fund using package argument with no browser, using --json option', async t => { npm.prefix = t.testdir(maintainerOwnsAllDeps) config.json = true - fund.exec(['.'], (err) => { - t.error(err, 'should not error out') - t.same( - JSON.parse(printUrl), - { - title: 'individual funding available at the following URL', - url: 'http://example.com/donate', - }, - 'should open funding url using json output' - ) - - config.json = false - printUrl = '' - t.end() - }) + await fund.exec(['.']) + t.same( + JSON.parse(printUrl), + { + title: 'individual funding available at the following URL', + url: 'http://example.com/donate', + }, + 'should open funding url using json output' + ) + config.json = false }) -t.test('fund using package info fetch from registry', t => { +t.test('fund using package info fetch from registry', async t => { npm.prefix = t.testdir({}) - fund.exec(['ntl'], (err) => { - t.error(err, 'should not error out') - t.match( - printUrl, - /http:\/\/example.com\/pacote/, - 'should open funding url that was loaded from registry manifest' - ) - - printUrl = '' - t.end() - }) + await fund.exec(['ntl']) + t.match( + printUrl, + /http:\/\/example.com\/pacote/, + 'should open funding url that was loaded from registry manifest' + ) }) -t.test('fund tries to use package info fetch from registry but registry has nothing', t => { +t.test('fund tries to use package info fetch from registry but registry has nothing', async t => { npm.prefix = t.testdir({}) - fund.exec(['foo'], (err) => { - t.equal(err.code, 'ENOFUND', 'should have ENOFUND error code') - t.equal( - err.message, - 'No valid funding method available for: foo', - 'should have no valid funding message' - ) - - printUrl = '' - t.end() - }) + await t.rejects( + fund.exec(['foo']), + { code: 'ENOFUND', message: 'No valid funding method available for: foo' }, + 'should have no valid funding message' + ) }) -t.test('fund but target module has no funding info', t => { +t.test('fund but target module has no funding info', async t => { npm.prefix = t.testdir(nestedNoFundingPackages) - fund.exec(['foo'], (err) => { - t.equal(err.code, 'ENOFUND', 'should have ENOFUND error code') - t.equal( - err.message, - 'No valid funding method available for: foo', - 'should have no valid funding message' - ) - - result = '' - t.end() - }) + await t.rejects( + fund.exec(['foo']), + { code: 'ENOFUND', message: 'No valid funding method available for: foo' }, + 'should have no valid funding message' + ) }) -t.test('fund using bad which value', t => { +t.test('fund using bad which value', async t => { npm.prefix = t.testdir(nestedMultipleFundingPackages) config.which = 3 - fund.exec(['bar'], (err) => { - t.equal(err.code, 'EFUNDNUMBER', 'should have EFUNDNUMBER error code') - t.equal( - err.message, - '`npm fund [<@scope>/] [--which=fundingSourceNumber]` must be given a positive integer', - 'should have bad which option error message' - ) - - config.which = null - result = '' - t.end() - }) + await t.rejects( + fund.exec(['bar']), + { code: 'EFUNDNUMBER', message: '`npm fund [<@scope>/] [--which=fundingSourceNumber]` must be given a positive integer' }, + 'should have bad which option error message' + ) + config.which = null }) -t.test('fund pkg missing version number', t => { +t.test('fund pkg missing version number', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'foo', @@ -676,15 +582,11 @@ t.test('fund pkg missing version number', t => { }), }) - fund.exec([], (err) => { - t.error(err, 'should not error out') - t.matchSnapshot(result, 'should print name only') - result = '' - t.end() - }) + await fund.exec([]) + t.matchSnapshot(result, 'should print name only') }) -t.test('fund a package throws on openUrl', t => { +t.test('fund a package throws on openUrl', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'foo', @@ -693,14 +595,14 @@ t.test('fund a package throws on openUrl', t => { }), }) - fund.exec(['.'], (err) => { - t.equal(err.message, 'ERROR', 'should throw unknown error') - result = '' - t.end() - }) + await t.rejects( + fund.exec(['.']), + { message: 'ERROR' }, + 'should throw unknown error' + ) }) -t.test('fund a package with type and multiple sources', t => { +t.test('fund a package with type and multiple sources', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'foo', @@ -717,16 +619,11 @@ t.test('fund a package with type and multiple sources', t => { }), }) - fund.exec(['.'], (err) => { - t.error(err, 'should not error out') - t.matchSnapshot(result, 'should print prompt select message') - - result = '' - t.end() - }) + await fund.exec(['.']) + t.matchSnapshot(result, 'should print prompt select message') }) -t.test('fund colors', t => { +t.test('fund colors', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-fund-colors', @@ -781,17 +678,12 @@ t.test('fund colors', t => { }) npm.color = true - fund.exec([], (err) => { - t.error(err, 'should not error out') - t.matchSnapshot(result, 'should print output with color info') - - result = '' - npm.color = false - t.end() - }) + await fund.exec([]) + t.matchSnapshot(result, 'should print output with color info') + npm.color = false }) -t.test('sub dep with fund info and a parent with no funding info', t => { +t.test('sub dep with fund info and a parent with no funding info', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-multiple-funding-sources', @@ -831,16 +723,11 @@ t.test('sub dep with fund info and a parent with no funding info', t => { }, }) - fund.exec([], (err) => { - t.error(err, 'should not error out') - t.matchSnapshot(result, 'should nest sub dep as child of root') - - result = '' - t.end() - }) + await fund.exec([]) + t.matchSnapshot(result, 'should nest sub dep as child of root') }) -t.test('workspaces', t => { +t.test('workspaces', async t => { t.test('filter funding info by a specific workspace', async t => { npm.localPrefix = npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -896,32 +783,16 @@ t.test('workspaces', t => { }, }) - await new Promise((res, rej) => { - fund.execWorkspaces([], ['a'], (err) => { - if (err) - rej(err) + await fund.execWorkspaces([], ['a']) - t.matchSnapshot(result, - 'should display only filtered workspace name and its deps') + t.matchSnapshot(result, + 'should display only filtered workspace name and its deps') - result = '' - res() - }) - }) - - await new Promise((res, rej) => { - fund.execWorkspaces([], ['./packages/a'], (err) => { - if (err) - rej(err) + result = '' - t.matchSnapshot(result, - 'should display only filtered workspace path and its deps') + await fund.execWorkspaces([], ['./packages/a']) - result = '' - res() - }) - }) + t.matchSnapshot(result, + 'should display only filtered workspace path and its deps') }) - - t.end() }) diff --git a/deps/npm/test/lib/get.js b/deps/npm/test/lib/commands/get.js similarity index 61% rename from deps/npm/test/lib/get.js rename to deps/npm/test/lib/commands/get.js index 30e26b7453fe8c..ba9e770e3e0a12 100644 --- a/deps/npm/test/lib/get.js +++ b/deps/npm/test/lib/commands/get.js @@ -1,13 +1,14 @@ const t = require('tap') -const { real: mockNpm } = require('../fixtures/mock-npm') +const { real: mockNpm } = require('../../fixtures/mock-npm') t.test('should retrieve values from config', async t => { - const { joinedOutput, command, npm } = mockNpm(t) + const { joinedOutput, Npm } = mockNpm(t) + const npm = new Npm() const name = 'editor' const value = 'vigor' await npm.load() npm.config.set(name, value) - await command('get', [name]) + await npm.exec('get', [name]) t.equal( joinedOutput(), value, diff --git a/deps/npm/test/lib/help-search.js b/deps/npm/test/lib/commands/help-search.js similarity index 57% rename from deps/npm/test/lib/help-search.js rename to deps/npm/test/lib/commands/help-search.js index 2df862d4fc570d..406977b622a2f9 100644 --- a/deps/npm/test/lib/help-search.js +++ b/deps/npm/test/lib/commands/help-search.js @@ -1,6 +1,6 @@ const t = require('tap') const { join } = require('path') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') const ansicolors = require('ansicolors') const OUTPUT = [] @@ -19,10 +19,9 @@ const npm = mockNpm({ long: false, }, usage: 'npm test usage', - commands: { - help: (args, cb) => { - return cb(npmHelpErr) - }, + exec: async () => { + if (npmHelpErr) + throw npmHelpErr }, output, }) @@ -42,45 +41,37 @@ const globDir = { const glob = (p, cb) => cb(null, Object.keys(globDir).map((file) => join(globRoot, file))) -const HelpSearch = t.mock('../../lib/help-search.js', { +const HelpSearch = t.mock('../../../lib/commands/help-search.js', { glob, }) const helpSearch = new HelpSearch(npm) -t.test('npm help-search', t => { +t.test('npm help-search', async t => { globRoot = t.testdir(globDir) t.teardown(() => { OUTPUT.length = 0 globRoot = null }) - return helpSearch.exec(['exec'], (err) => { - if (err) - throw err + await helpSearch.exec(['exec']) - t.match(OUTPUT, /Top hits for "exec"/, 'outputs results') - t.end() - }) + t.match(OUTPUT, /Top hits for "exec"/, 'outputs results') }) -t.test('npm help-search multiple terms', t => { +t.test('npm help-search multiple terms', async t => { globRoot = t.testdir(globDir) t.teardown(() => { OUTPUT.length = 0 globRoot = null }) - return helpSearch.exec(['run', 'script'], (err) => { - if (err) - throw err + await helpSearch.exec(['run', 'script']) - t.match(OUTPUT, /Top hits for/, 'outputs results') - t.match(OUTPUT, /run:\d+ script:\d+/, 'shows hit counts for both terms') - t.end() - }) + t.match(OUTPUT, /Top hits for/, 'outputs results') + t.match(OUTPUT, /run:\d+ script:\d+/, 'shows hit counts for both terms') }) -t.test('npm help-search long output', t => { +t.test('npm help-search long output', async t => { globRoot = t.testdir(globDir) config.long = true t.teardown(() => { @@ -89,16 +80,12 @@ t.test('npm help-search long output', t => { globRoot = null }) - return helpSearch.exec(['exec'], (err) => { - if (err) - throw err + await helpSearch.exec(['exec']) - t.match(OUTPUT, /has multiple lines of exec help/, 'outputs detailed results') - t.end() - }) + t.match(OUTPUT, /has multiple lines of exec help/, 'outputs detailed results') }) -t.test('npm help-search long output with color', t => { +t.test('npm help-search long output with color', async t => { globRoot = t.testdir(globDir) config.long = true npm.color = true @@ -109,36 +96,23 @@ t.test('npm help-search long output with color', t => { globRoot = null }) - return helpSearch.exec(['help-search'], (err) => { - if (err) - throw err + await helpSearch.exec(['help-search']) - const highlightedText = ansicolors.bgBlack(ansicolors.red('help-search')) - t.equal(OUTPUT.some((line) => line.includes(highlightedText)), true, 'returned highlighted search terms') - t.end() - }) + const highlightedText = ansicolors.bgBlack(ansicolors.red('help-search')) + t.equal(OUTPUT.some((line) => line.includes(highlightedText)), true, 'returned highlighted search terms') }) -t.test('npm help-search no args', t => { - return helpSearch.exec([], (err) => { - t.notOk(err) - t.match(OUTPUT, /npm help-search/, 'outputs usage') - t.end() - }) +t.test('npm help-search no args', async t => { + t.rejects(helpSearch.exec([]), /npm help-search/, 'outputs usage') }) -t.test('npm help-search no matches', t => { +t.test('npm help-search no matches', async t => { globRoot = t.testdir(globDir) t.teardown(() => { OUTPUT.length = 0 globRoot = null }) - return helpSearch.exec(['asdfasdf'], (err) => { - if (err) - throw err - - t.match(OUTPUT, /No matches/) - t.end() - }) + await helpSearch.exec(['asdfasdf']) + t.match(OUTPUT, /No matches/) }) diff --git a/deps/npm/test/lib/help.js b/deps/npm/test/lib/commands/help.js similarity index 53% rename from deps/npm/test/lib/help.js rename to deps/npm/test/lib/commands/help.js index 44ba5b1cabc3c1..9ea2b9d92ae7e7 100644 --- a/deps/npm/test/lib/help.js +++ b/deps/npm/test/lib/commands/help.js @@ -20,14 +20,11 @@ const npm = { cooked: [], }, }, - commands: { - 'help-search': (args, cb) => { + exec: async (cmd, args) => { + if (cmd === 'help-search') helpSearchArgs = args - return cb() - }, - help: { - usage: 'npm help ', - }, + else if (cmd === 'help') + return { usage: 'npm help ' } }, deref: (cmd) => {}, output: msg => { @@ -67,8 +64,8 @@ const openUrl = async (npm, url, msg) => { openUrlArg = url } -const Help = t.mock('../../lib/help.js', { - '../../lib/utils/open-url.js': openUrl, +const Help = t.mock('../../../lib/commands/help.js', { + '../../../lib/utils/open-url.js': openUrl, child_process: { spawn, }, @@ -76,14 +73,10 @@ const Help = t.mock('../../lib/help.js', { }) const help = new Help(npm) -t.test('npm help', t => { - return help.exec([], (err) => { - if (err) - throw err +t.test('npm help', async t => { + await help.exec([]) - t.match(OUTPUT, ['test npm usage'], 'showed npm usage') - t.end() - }) + t.match(OUTPUT, ['test npm usage'], 'showed npm usage') }) t.test('npm help completion', async t => { @@ -99,37 +92,28 @@ t.test('npm help completion', async t => { t.rejects(help.completion({ conf: { argv: { remain: [] } } }), /glob failed/, 'glob errors propagate') }) -t.test('npm help multiple args calls search', t => { +t.test('npm help multiple args calls search', async t => { t.teardown(() => { helpSearchArgs = null }) - return help.exec(['run', 'script'], (err) => { - if (err) - throw err + await help.exec(['run', 'script']) - t.strictSame(helpSearchArgs, ['run', 'script'], 'passed the args to help-search') - t.end() - }) + t.strictSame(helpSearchArgs, ['run', 'script'], 'passed the args to help-search') }) -t.test('npm help no matches calls search', t => { +t.test('npm help no matches calls search', async t => { globResult = [] t.teardown(() => { helpSearchArgs = null globResult = globDefaults }) - return help.exec(['asdfasdf'], (err) => { - if (err) - throw err - - t.strictSame(helpSearchArgs, ['asdfasdf'], 'passed the args to help-search') - t.end() - }) + await help.exec(['asdfasdf']) + t.strictSame(helpSearchArgs, ['asdfasdf'], 'passed the args to help-search') }) -t.test('npm help glob errors propagate', t => { +t.test('npm help glob errors propagate', async t => { globErr = new Error('glob failed') t.teardown(() => { globErr = null @@ -137,13 +121,14 @@ t.test('npm help glob errors propagate', t => { spawnArgs = null }) - return help.exec(['whoami'], (err) => { - t.match(err, /glob failed/, 'glob error propagates') - t.end() - }) + await t.rejects( + help.exec(['whoami']), + /glob failed/, + 'glob error propagates' + ) }) -t.test('npm help whoami', t => { +t.test('npm help whoami', async t => { globResult = ['/root/man/man1/npm-whoami.1.xz'] t.teardown(() => { globResult = globDefaults @@ -151,17 +136,13 @@ t.test('npm help whoami', t => { spawnArgs = null }) - return help.exec(['whoami'], (err) => { - if (err) - throw err + await help.exec(['whoami']) - t.equal(spawnBin, 'man', 'calls man by default') - t.strictSame(spawnArgs, [globResult[0]], 'passes the correct arguments') - t.end() - }) + t.equal(spawnBin, 'man', 'calls man by default') + t.strictSame(spawnArgs, [globResult[0]], 'passes the correct arguments') }) -t.test('npm help 1 install', t => { +t.test('npm help 1 install', async t => { npmConfig.viewer = 'browser' globResult = [ '/root/man/man5/install.5', @@ -175,16 +156,13 @@ t.test('npm help 1 install', t => { spawnArgs = null }) - return help.exec(['1', 'install'], (err) => { - if (err) - throw err + await help.exec(['1', 'install']) - t.match(openUrlArg, /commands(\/|\\)npm-install.html$/, 'attempts to open the correct url') - t.end() - }) + t.match(openUrlArg, /commands(\/|\\)npm-install.html$/, 'attempts to open the correct url') + t.ok(openUrlArg.startsWith('file:///'), 'opens with the correct uri schema') }) -t.test('npm help 5 install', t => { +t.test('npm help 5 install', async t => { npmConfig.viewer = 'browser' globResult = [ '/root/man/man5/install.5', @@ -198,17 +176,13 @@ t.test('npm help 5 install', t => { spawnArgs = null }) - return help.exec(['5', 'install'], (err) => { - if (err) - throw err + await help.exec(['5', 'install']) - t.match(globParam, /man5/, 'searches only in man5 folder') - t.match(openUrlArg, /configuring-npm(\/|\\)install.html$/, 'attempts to open the correct url') - t.end() - }) + t.match(globParam, /man5/, 'searches only in man5 folder') + t.match(openUrlArg, /configuring-npm(\/|\\)install.html$/, 'attempts to open the correct url') }) -t.test('npm help 7 config', t => { +t.test('npm help 7 config', async t => { npmConfig.viewer = 'browser' globResult = [ '/root/man/man7/config.7', @@ -221,17 +195,13 @@ t.test('npm help 7 config', t => { spawnArgs = null }) - return help.exec(['7', 'config'], (err) => { - if (err) - throw err + await help.exec(['7', 'config']) - t.match(globParam, /man7/, 'searches only in man5 folder') - t.match(openUrlArg, /using-npm(\/|\\)config.html$/, 'attempts to open the correct url') - t.end() - }) + t.match(globParam, /man7/, 'searches only in man5 folder') + t.match(openUrlArg, /using-npm(\/|\\)config.html$/, 'attempts to open the correct url') }) -t.test('npm help package.json redirects to package-json', t => { +t.test('npm help package.json redirects to package-json', async t => { globResult = ['/root/man/man5/package-json.5'] t.teardown(() => { globResult = globDefaults @@ -239,18 +209,14 @@ t.test('npm help package.json redirects to package-json', t => { spawnArgs = null }) - return help.exec(['package.json'], (err) => { - if (err) - throw err + await help.exec(['package.json']) - t.equal(spawnBin, 'man', 'calls man by default') - t.match(globParam, /package-json/, 'glob was asked to find package-json') - t.strictSame(spawnArgs, [globResult[0]], 'passes the correct arguments') - t.end() - }) + t.equal(spawnBin, 'man', 'calls man by default') + t.match(globParam, /package-json/, 'glob was asked to find package-json') + t.strictSame(spawnArgs, [globResult[0]], 'passes the correct arguments') }) -t.test('npm help ?(un)star', t => { +t.test('npm help ?(un)star', async t => { npmConfig.viewer = 'woman' globResult = [ '/root/man/man1/npm-star.1', @@ -263,17 +229,13 @@ t.test('npm help ?(un)star', t => { spawnArgs = null }) - return help.exec(['?(un)star'], (err) => { - if (err) - throw err + await help.exec(['?(un)star']) - t.equal(spawnBin, 'emacsclient', 'maps woman to emacs correctly') - t.strictSame(spawnArgs, ['-e', `(woman-find-file '/root/man/man1/npm-star.1')`], 'passes the correct arguments') - t.end() - }) + t.equal(spawnBin, 'emacsclient', 'maps woman to emacs correctly') + t.strictSame(spawnArgs, ['-e', `(woman-find-file '/root/man/man1/npm-star.1')`], 'passes the correct arguments') }) -t.test('npm help - woman viewer propagates errors', t => { +t.test('npm help - woman viewer propagates errors', async t => { npmConfig.viewer = 'woman' spawnCode = 1 globResult = [ @@ -288,15 +250,16 @@ t.test('npm help - woman viewer propagates errors', t => { spawnArgs = null }) - return help.exec(['?(un)star'], (err) => { - t.match(err, /help process exited with code: 1/, 'received the correct error') - t.equal(spawnBin, 'emacsclient', 'maps woman to emacs correctly') - t.strictSame(spawnArgs, ['-e', `(woman-find-file '/root/man/man1/npm-star.1')`], 'passes the correct arguments') - t.end() - }) + await t.rejects( + help.exec(['?(un)star']), + /help process exited with code: 1/, + 'received the correct error' + ) + t.equal(spawnBin, 'emacsclient', 'maps woman to emacs correctly') + t.strictSame(spawnArgs, ['-e', `(woman-find-file '/root/man/man1/npm-star.1')`], 'passes the correct arguments') }) -t.test('npm help un*', t => { +t.test('npm help un*', async t => { globResult = [ '/root/man/man1/npm-unstar.1', '/root/man/man1/npm-uninstall.1', @@ -308,17 +271,13 @@ t.test('npm help un*', t => { spawnArgs = null }) - return help.exec(['un*'], (err) => { - if (err) - throw err + await help.exec(['un*']) - t.equal(spawnBin, 'man', 'calls man by default') - t.strictSame(spawnArgs, ['/root/man/man1/npm-uninstall.1'], 'passes the correct arguments') - t.end() - }) + t.equal(spawnBin, 'man', 'calls man by default') + t.strictSame(spawnArgs, ['/root/man/man1/npm-uninstall.1'], 'passes the correct arguments') }) -t.test('npm help - man viewer propagates errors', t => { +t.test('npm help - man viewer propagates errors', async t => { spawnCode = 1 globResult = [ '/root/man/man1/npm-unstar.1', @@ -332,15 +291,16 @@ t.test('npm help - man viewer propagates errors', t => { spawnArgs = null }) - return help.exec(['un*'], (err) => { - t.match(err, /help process exited with code: 1/, 'received correct error') - t.equal(spawnBin, 'man', 'calls man by default') - t.strictSame(spawnArgs, ['/root/man/man1/npm-uninstall.1'], 'passes the correct arguments') - t.end() - }) + await t.rejects( + help.exec(['un*']), + /help process exited with code: 1/, + 'received correct error' + ) + t.equal(spawnBin, 'man', 'calls man by default') + t.strictSame(spawnArgs, ['/root/man/man1/npm-uninstall.1'], 'passes the correct arguments') }) -t.test('npm help with complex installation path finds proper help file', t => { +t.test('npm help with complex installation path finds proper help file', async t => { npmConfig.viewer = 'browser' globResult = [ 'C:/Program Files/node-v14.15.5-win-x64/node_modules/npm/man/man1/npm-install.1', @@ -354,11 +314,7 @@ t.test('npm help with complex installation path finds proper help file', t => { spawnArgs = null }) - return help.exec(['1', 'install'], (err) => { - if (err) - throw err + await help.exec(['1', 'install']) - t.match(openUrlArg, /commands(\/|\\)npm-install.html$/, 'attempts to open the correct url') - t.end() - }) + t.match(openUrlArg, /commands(\/|\\)npm-install.html$/, 'attempts to open the correct url') }) diff --git a/deps/npm/test/lib/commands/hook.js b/deps/npm/test/lib/commands/hook.js new file mode 100644 index 00000000000000..af162e4fce37ce --- /dev/null +++ b/deps/npm/test/lib/commands/hook.js @@ -0,0 +1,504 @@ +const t = require('tap') + +const output = [] +const npm = { + flatOptions: { + json: false, + parseable: false, + silent: false, + loglevel: 'info', + unicode: false, + }, + output: (msg) => { + output.push(msg) + }, +} + +const pkgTypes = { + semver: 'package', + '@npmcli': 'scope', + npm: 'owner', +} + +const now = Date.now() +let hookResponse = null +let hookArgs = null +const libnpmhook = { + add: async (pkg, uri, secret, opts) => { + hookArgs = { pkg, uri, secret, opts } + return { id: 1, name: pkg.replace(/^@/, ''), type: pkgTypes[pkg], endpoint: uri } + }, + ls: async (opts) => { + hookArgs = opts + let id = 0 + if (hookResponse) + return hookResponse + + return Object.keys(pkgTypes).map((name) => ({ + id: ++id, + name: name.replace(/^@/, ''), + type: pkgTypes[name], + endpoint: 'https://google.com', + last_delivery: id % 2 === 0 ? now : undefined, + })) + }, + rm: async (id, opts) => { + hookArgs = { id, opts } + const pkg = Object.keys(pkgTypes)[0] + return { id: 1, name: pkg.replace(/^@/, ''), type: pkgTypes[pkg], endpoint: 'https://google.com' } + }, + update: async (id, uri, secret, opts) => { + hookArgs = { id, uri, secret, opts } + const pkg = Object.keys(pkgTypes)[0] + return { id, name: pkg.replace(/^@/, ''), type: pkgTypes[pkg], endpoint: uri } + }, +} + +const Hook = t.mock('../../../lib/commands/hook.js', { + '../../../lib/utils/otplease.js': async (opts, fn) => fn(opts), + libnpmhook, +}) +const hook = new Hook(npm) + +t.test('npm hook no args', async t => { + await t.rejects( + hook.exec([]), + hook.usage, 'throws usage with no arguments' + ) +}) + +t.test('npm hook add', async t => { + t.teardown(() => { + hookArgs = null + output.length = 0 + }) + + await hook.exec(['add', 'semver', 'https://google.com', 'some-secret']) + + t.strictSame(hookArgs, { + pkg: 'semver', + uri: 'https://google.com', + secret: 'some-secret', + opts: npm.flatOptions, + }, 'provided the correct arguments to libnpmhook') + t.strictSame(output, ['+ semver -> https://google.com'], 'prints the correct output') +}) + +t.test('npm hook add - unicode output', async t => { + npm.flatOptions.unicode = true + t.teardown(() => { + npm.flatOptions.unicode = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['add', 'semver', 'https://google.com', 'some-secret']) + + t.strictSame(hookArgs, { + pkg: 'semver', + uri: 'https://google.com', + secret: 'some-secret', + opts: npm.flatOptions, + }, 'provided the correct arguments to libnpmhook') + t.strictSame(output, ['+ semver ➜ https://google.com'], 'prints the correct output') +}) + +t.test('npm hook add - json output', async t => { + npm.flatOptions.json = true + t.teardown(() => { + npm.flatOptions.json = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['add', '@npmcli', 'https://google.com', 'some-secret']) + + t.strictSame(hookArgs, { + pkg: '@npmcli', + uri: 'https://google.com', + secret: 'some-secret', + opts: npm.flatOptions, + }, 'provided the correct arguments to libnpmhook') + t.strictSame(JSON.parse(output[0]), { + id: 1, + name: 'npmcli', + endpoint: 'https://google.com', + type: 'scope', + }, 'prints the correct json output') +}) + +t.test('npm hook add - parseable output', async t => { + npm.flatOptions.parseable = true + t.teardown(() => { + npm.flatOptions.parseable = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['add', '@npmcli', 'https://google.com', 'some-secret']) + + t.strictSame(hookArgs, { + pkg: '@npmcli', + uri: 'https://google.com', + secret: 'some-secret', + opts: npm.flatOptions, + }, 'provided the correct arguments to libnpmhook') + t.strictSame(output[0].split(/\t/), [ + 'id', 'name', 'type', 'endpoint', + ], 'prints the correct parseable output headers') + t.strictSame(output[1].split(/\t/), [ + '1', 'npmcli', 'scope', 'https://google.com', + ], 'prints the correct parseable values') +}) + +t.test('npm hook add - silent output', async t => { + npm.flatOptions.silent = true + t.teardown(() => { + npm.flatOptions.silent = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['add', '@npmcli', 'https://google.com', 'some-secret']) + + t.strictSame(hookArgs, { + pkg: '@npmcli', + uri: 'https://google.com', + secret: 'some-secret', + opts: npm.flatOptions, + }, 'provided the correct arguments to libnpmhook') + t.strictSame(output, [], 'printed no output') +}) + +t.test('npm hook ls', async t => { + t.teardown(() => { + hookArgs = null + output.length = 0 + }) + + await hook.exec(['ls']) + + t.strictSame(hookArgs, { + ...npm.flatOptions, + package: undefined, + }, 'received the correct arguments') + t.equal(output[0], 'You have 3 hooks configured.', 'prints the correct header') + const out = require('../../../lib/utils/ansi-trim')(output[1]) + t.match(out, /semver.*https:\/\/google.com.*\n.*\n.*never triggered/, 'prints package hook') + t.match(out, /@npmcli.*https:\/\/google.com.*\n.*\n.*triggered just now/, 'prints scope hook') + t.match(out, /~npm.*https:\/\/google.com.*\n.*\n.*never triggered/, 'prints owner hook') +}) + +t.test('npm hook ls, no results', async t => { + hookResponse = [] + t.teardown(() => { + hookResponse = null + hookArgs = null + output.length = 0 + }) + + await hook.exec(['ls']) + + t.strictSame(hookArgs, { + ...npm.flatOptions, + package: undefined, + }, 'received the correct arguments') + t.equal(output[0], 'You don\'t have any hooks configured yet.', 'prints the correct result') +}) + +t.test('npm hook ls, single result', async t => { + hookResponse = [{ + id: 1, + name: 'semver', + type: 'package', + endpoint: 'https://google.com', + }] + + t.teardown(() => { + hookResponse = null + hookArgs = null + output.length = 0 + }) + + await hook.exec(['ls']) + + t.strictSame(hookArgs, { + ...npm.flatOptions, + package: undefined, + }, 'received the correct arguments') + t.equal(output[0], 'You have one hook configured.', 'prints the correct header') + const out = require('../../../lib/utils/ansi-trim')(output[1]) + t.match(out, /semver.*https:\/\/google.com.*\n.*\n.*never triggered/, 'prints package hook') +}) + +t.test('npm hook ls - json output', async t => { + npm.flatOptions.json = true + t.teardown(() => { + npm.flatOptions.json = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['ls']) + + t.strictSame(hookArgs, { + ...npm.flatOptions, + package: undefined, + }, 'received the correct arguments') + const out = JSON.parse(output[0]) + t.match(out, [{ + id: 1, + name: 'semver', + type: 'package', + endpoint: 'https://google.com', + }, { + id: 2, + name: 'npmcli', + type: 'scope', + endpoint: 'https://google.com', + }, { + id: 3, + name: 'npm', + type: 'owner', + endpoint: 'https://google.com', + }], 'prints the correct output') +}) + +t.test('npm hook ls - parseable output', async t => { + npm.flatOptions.parseable = true + t.teardown(() => { + npm.flatOptions.parseable = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['ls']) + + t.strictSame(hookArgs, { + ...npm.flatOptions, + package: undefined, + }, 'received the correct arguments') + t.strictSame(output.map(line => line.split(/\t/)), [ + ['id', 'name', 'type', 'endpoint', 'last_delivery'], + ['1', 'semver', 'package', 'https://google.com', ''], + ['2', 'npmcli', 'scope', 'https://google.com', `${now}`], + ['3', 'npm', 'owner', 'https://google.com', ''], + ], 'prints the correct result') +}) + +t.test('npm hook ls - silent output', async t => { + npm.flatOptions.silent = true + t.teardown(() => { + npm.flatOptions.silent = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['ls']) + + t.strictSame(hookArgs, { + ...npm.flatOptions, + package: undefined, + }, 'received the correct arguments') + t.strictSame(output, [], 'printed no output') +}) + +t.test('npm hook rm', async t => { + t.teardown(() => { + hookArgs = null + output.length = 0 + }) + + await hook.exec(['rm', '1']) + + t.strictSame(hookArgs, { + id: '1', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.strictSame(output, [ + '- semver X https://google.com', + ], 'printed the correct output') +}) + +t.test('npm hook rm - unicode output', async t => { + npm.flatOptions.unicode = true + t.teardown(() => { + npm.flatOptions.unicode = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['rm', '1']) + + t.strictSame(hookArgs, { + id: '1', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.strictSame(output, [ + '- semver ✘ https://google.com', + ], 'printed the correct output') +}) + +t.test('npm hook rm - silent output', async t => { + npm.flatOptions.silent = true + t.teardown(() => { + npm.flatOptions.silent = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['rm', '1']) + + t.strictSame(hookArgs, { + id: '1', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.strictSame(output, [], 'printed no output') +}) + +t.test('npm hook rm - json output', async t => { + npm.flatOptions.json = true + t.teardown(() => { + npm.flatOptions.json = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['rm', '1']) + + t.strictSame(hookArgs, { + id: '1', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.strictSame(JSON.parse(output[0]), { + id: 1, + name: 'semver', + type: 'package', + endpoint: 'https://google.com', + }, 'printed correct output') +}) + +t.test('npm hook rm - parseable output', async t => { + npm.flatOptions.parseable = true + t.teardown(() => { + npm.flatOptions.parseable = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['rm', '1']) + + t.strictSame(hookArgs, { + id: '1', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.strictSame(output.map(line => line.split(/\t/)), [ + ['id', 'name', 'type', 'endpoint'], + ['1', 'semver', 'package', 'https://google.com'], + ], 'printed correct output') +}) + +t.test('npm hook update', async t => { + t.teardown(() => { + hookArgs = null + output.length = 0 + }) + + await hook.exec(['update', '1', 'https://google.com', 'some-secret']) + + t.strictSame(hookArgs, { + id: '1', + uri: 'https://google.com', + secret: 'some-secret', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.strictSame(output, [ + '+ semver -> https://google.com', + ], 'printed the correct output') +}) + +t.test('npm hook update - unicode', async t => { + npm.flatOptions.unicode = true + t.teardown(() => { + npm.flatOptions.unicode = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['update', '1', 'https://google.com', 'some-secret']) + + t.strictSame(hookArgs, { + id: '1', + uri: 'https://google.com', + secret: 'some-secret', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.strictSame(output, [ + '+ semver ➜ https://google.com', + ], 'printed the correct output') +}) + +t.test('npm hook update - json output', async t => { + npm.flatOptions.json = true + t.teardown(() => { + npm.flatOptions.json = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['update', '1', 'https://google.com', 'some-secret']) + + t.strictSame(hookArgs, { + id: '1', + uri: 'https://google.com', + secret: 'some-secret', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.strictSame(JSON.parse(output[0]), { + id: '1', + name: 'semver', + type: 'package', + endpoint: 'https://google.com', + }, 'printed the correct output') +}) + +t.test('npm hook update - parseable output', async t => { + npm.flatOptions.parseable = true + t.teardown(() => { + npm.flatOptions.parseable = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['update', '1', 'https://google.com', 'some-secret']) + + t.strictSame(hookArgs, { + id: '1', + uri: 'https://google.com', + secret: 'some-secret', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.strictSame(output.map(line => line.split(/\t/)), [ + ['id', 'name', 'type', 'endpoint'], + ['1', 'semver', 'package', 'https://google.com'], + ], 'printed the correct output') +}) + +t.test('npm hook update - silent output', async t => { + npm.flatOptions.silent = true + t.teardown(() => { + npm.flatOptions.silent = false + hookArgs = null + output.length = 0 + }) + + await hook.exec(['update', '1', 'https://google.com', 'some-secret']) + + t.strictSame(hookArgs, { + id: '1', + uri: 'https://google.com', + secret: 'some-secret', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.strictSame(output, [], 'printed no output') +}) diff --git a/deps/npm/test/lib/init.js b/deps/npm/test/lib/commands/init.js similarity index 64% rename from deps/npm/test/lib/init.js rename to deps/npm/test/lib/commands/init.js index f11ce356f5c5a1..74b33168ade582 100644 --- a/deps/npm/test/lib/init.js +++ b/deps/npm/test/lib/commands/init.js @@ -1,7 +1,7 @@ const t = require('tap') const fs = require('fs') const { resolve } = require('path') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') const npmLog = { disableProgress: () => null, @@ -26,9 +26,9 @@ const npm = mockNpm({ log: npmLog, }) const mocks = { - '../../lib/utils/usage.js': () => 'usage instructions', + '../../../lib/utils/usage.js': () => 'usage instructions', } -const Init = t.mock('../../lib/init.js', mocks) +const Init = t.mock('../../../lib/commands/init.js', mocks) const init = new Init(npm) const _cwd = process.cwd() const _consolelog = console.log @@ -42,7 +42,7 @@ t.afterEach(() => { console.log = _consolelog }) -t.test('classic npm init -y', t => { +t.test('classic npm init -y', async t => { npm.localPrefix = t.testdir({}) // init-package-json prints directly to console.log @@ -50,22 +50,18 @@ t.test('classic npm init -y', t => { console.log = noop process.chdir(npm.localPrefix) - init.exec([], err => { - if (err) - throw err - - const pkg = require(resolve(npm.localPrefix, 'package.json')) - t.equal(pkg.version, '1.0.0') - t.equal(pkg.license, 'ISC') - t.end() - }) + await init.exec([]) + + const pkg = require(resolve(npm.localPrefix, 'package.json')) + t.equal(pkg.version, '1.0.0') + t.equal(pkg.license, 'ISC') }) -t.test('classic interactive npm init', t => { +t.test('classic interactive npm init', async t => { npm.localPrefix = t.testdir({}) config.yes = undefined - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { ...mocks, 'init-package-json': (path, initFile, config, cb) => { t.equal( @@ -79,19 +75,14 @@ t.test('classic interactive npm init', t => { const init = new Init(npm) process.chdir(npm.localPrefix) - init.exec([], err => { - if (err) - throw err - - t.end() - }) + await init.exec([]) }) -t.test('npm init ', t => { +t.test('npm init ', async t => { t.plan(3) npm.localPrefix = t.testdir({}) - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { libnpmexec: ({ args, cache, npxCache }) => { t.same( args, @@ -105,17 +96,14 @@ t.test('npm init ', t => { const init = new Init(npm) process.chdir(npm.localPrefix) - init.exec(['react-app'], err => { - if (err) - throw err - }) + await init.exec(['react-app']) }) -t.test('npm init -- other-args', t => { +t.test('npm init -- other-args', async t => { t.plan(1) npm.localPrefix = t.testdir({}) - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { libnpmexec: ({ args }) => { t.same( args, @@ -127,20 +115,14 @@ t.test('npm init -- other-args', t => { const init = new Init(npm) process.chdir(npm.localPrefix) - init.exec( - ['react-app', 'my-path', '--some-option', 'some-value'], - err => { - if (err) - throw err - } - ) + await init.exec(['react-app', 'my-path', '--some-option', 'some-value']) }) -t.test('npm init @scope/name', t => { +t.test('npm init @scope/name', async t => { t.plan(1) npm.localPrefix = t.testdir({}) - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { libnpmexec: ({ args }) => { t.same( args, @@ -152,17 +134,14 @@ t.test('npm init @scope/name', t => { const init = new Init(npm) process.chdir(npm.localPrefix) - init.exec(['@npmcli/something'], err => { - if (err) - throw err - }) + await init.exec(['@npmcli/something']) }) -t.test('npm init git spec', t => { +t.test('npm init git spec', async t => { t.plan(1) npm.localPrefix = t.testdir({}) - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { libnpmexec: ({ args }) => { t.same( args, @@ -174,17 +153,14 @@ t.test('npm init git spec', t => { const init = new Init(npm) process.chdir(npm.localPrefix) - init.exec(['npm/something'], err => { - if (err) - throw err - }) + await init.exec(['npm/something']) }) -t.test('npm init @scope', t => { +t.test('npm init @scope', async t => { t.plan(1) npm.localPrefix = t.testdir({}) - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { libnpmexec: ({ args }) => { t.same( args, @@ -196,31 +172,25 @@ t.test('npm init @scope', t => { const init = new Init(npm) process.chdir(npm.localPrefix) - init.exec(['@npmcli'], err => { - if (err) - throw err - }) + await init.exec(['@npmcli']) }) -t.test('npm init tgz', t => { +t.test('npm init tgz', async t => { npm.localPrefix = t.testdir({}) process.chdir(npm.localPrefix) - init.exec(['something.tgz'], err => { - t.match( - err, - /Error: Unrecognized initializer: something.tgz/, - 'should throw error when using an unsupported spec' - ) - t.end() - }) + await t.rejects( + init.exec(['something.tgz']), + /Unrecognized initializer: something.tgz/, + 'should throw error when using an unsupported spec' + ) }) -t.test('npm init @next', t => { +t.test('npm init @next', async t => { t.plan(1) npm.localPrefix = t.testdir({}) - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { libnpmexec: ({ args }) => { t.same( args, @@ -232,16 +202,13 @@ t.test('npm init @next', t => { const init = new Init(npm) process.chdir(npm.localPrefix) - init.exec(['something@next'], err => { - if (err) - throw err - }) + await init.exec(['something@next']) }) -t.test('npm init exec error', t => { +t.test('npm init exec error', async t => { npm.localPrefix = t.testdir({}) - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { libnpmexec: async ({ args }) => { throw new Error('ERROR') }, @@ -249,21 +216,18 @@ t.test('npm init exec error', t => { const init = new Init(npm) process.chdir(npm.localPrefix) - init.exec(['something@next'], err => { - t.match( - err, - /ERROR/, - 'should exit with exec error' - ) - t.end() - }) + await t.rejects( + init.exec(['something@next']), + /ERROR/, + 'should exit with exec error' + ) }) -t.test('should not rewrite flatOptions', t => { +t.test('should not rewrite flatOptions', async t => { t.plan(1) npm.localPrefix = t.testdir({}) - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { libnpmexec: async ({ args }) => { t.same( args, @@ -275,17 +239,14 @@ t.test('should not rewrite flatOptions', t => { const init = new Init(npm) process.chdir(npm.localPrefix) - init.exec(['react-app', 'my-app'], err => { - if (err) - throw err - }) + await init.exec(['react-app', 'my-app']) }) -t.test('npm init cancel', t => { +t.test('npm init cancel', async t => { t.plan(2) npm.localPrefix = t.testdir({}) - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { ...mocks, 'init-package-json': (dir, initFile, config, cb) => cb( new Error('canceled') @@ -299,16 +260,13 @@ t.test('npm init cancel', t => { } process.chdir(npm.localPrefix) - init.exec([], err => { - if (err) - throw err - }) + await init.exec([]) }) -t.test('npm init error', t => { +t.test('npm init error', async t => { npm.localPrefix = t.testdir({}) - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { ...mocks, 'init-package-json': (dir, initFile, config, cb) => cb( new Error('Unknown Error') @@ -317,14 +275,15 @@ t.test('npm init error', t => { const init = new Init(npm) process.chdir(npm.localPrefix) - init.exec([], err => { - t.match(err, /Unknown Error/, 'should throw error') - t.end() - }) + await t.rejects( + init.exec([]), + /Unknown Error/, + 'should throw error' + ) }) t.test('workspaces', t => { - t.test('no args', t => { + t.test('no args', async t => { t.teardown(() => { npm._mockOutputs.length = 0 }) @@ -334,7 +293,7 @@ t.test('workspaces', t => { }), }) - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { ...mocks, 'init-package-json': (dir, initFile, config, cb) => { t.equal(dir, resolve(npm.localPrefix, 'a'), 'should use the ws path') @@ -342,16 +301,11 @@ t.test('workspaces', t => { }, }) const init = new Init(npm) - init.execWorkspaces([], ['a'], err => { - if (err) - throw err - - t.matchSnapshot(npm._mockOutputs, 'should print helper info') - t.end() - }) + await init.execWorkspaces([], ['a']) + t.matchSnapshot(npm._mockOutputs, 'should print helper info') }) - t.test('no args, existing folder', t => { + t.test('no args, existing folder', async t => { t.teardown(() => { npm._mockOutputs.length = 0 }) @@ -374,16 +328,12 @@ t.test('workspaces', t => { }), }) - init.execWorkspaces([], ['packages/a'], err => { - if (err) - throw err + await init.execWorkspaces([], ['packages/a']) - t.matchSnapshot(npm._mockOutputs, 'should print helper info') - t.end() - }) + t.matchSnapshot(npm._mockOutputs, 'should print helper info') }) - t.test('with arg but missing workspace folder', t => { + t.test('with arg but missing workspace folder', async t => { t.teardown(() => { npm._mockOutputs.length = 0 }) @@ -409,16 +359,12 @@ t.test('workspaces', t => { }), }) - init.execWorkspaces([], ['packages/a'], err => { - if (err) - throw err + await init.execWorkspaces([], ['packages/a']) - t.matchSnapshot(npm._mockOutputs, 'should print helper info') - t.end() - }) + t.matchSnapshot(npm._mockOutputs, 'should print helper info') }) - t.test('fail parsing top-level package.json to set workspace', t => { + t.test('fail parsing top-level package.json to set workspace', async t => { // init-package-json prints directly to console.log // this avoids poluting test output with those logs console.log = noop @@ -429,7 +375,7 @@ t.test('workspaces', t => { }), }) - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { ...mocks, '@npmcli/package-json': { async load () { @@ -439,37 +385,31 @@ t.test('workspaces', t => { }) const init = new Init(npm) - init.execWorkspaces([], ['a'], err => { - t.match( - err, - /ERR/, - 'should exit with error' - ) - t.end() - }) + await t.rejects( + init.execWorkspaces([], ['a']), + /ERR/, + 'should exit with error' + ) }) - t.test('missing top-level package.json when settting workspace', t => { + t.test('missing top-level package.json when settting workspace', async t => { // init-package-json prints directly to console.log // this avoids poluting test output with those logs console.log = noop npm.localPrefix = t.testdir({}) - const Init = require('../../lib/init.js') + const Init = require('../../../lib/commands/init.js') const init = new Init(npm) - init.execWorkspaces([], ['a'], err => { - t.match( - err, - { code: 'ENOENT' }, - 'should exit with missing package.json file error' - ) - t.end() - }) + await t.rejects( + init.execWorkspaces([], ['a']), + { code: 'ENOENT' }, + 'should exit with missing package.json file error' + ) }) - t.test('using args', t => { + t.test('using args', async t => { npm.localPrefix = t.testdir({ b: { 'package.json': JSON.stringify({ @@ -482,7 +422,7 @@ t.test('workspaces', t => { }), }) - const Init = t.mock('../../lib/init.js', { + const Init = t.mock('../../../lib/commands/init.js', { ...mocks, libnpmexec: ({ args, path }) => { t.same( @@ -503,17 +443,13 @@ t.test('workspaces', t => { }) const init = new Init(npm) - init.execWorkspaces(['react-app'], ['a'], err => { - if (err) - throw err - - t.end() - }) + await init.execWorkspaces(['react-app'], ['a']) }) t.end() }) -t.test('npm init workspces with root', t => { + +t.test('npm init workspces with root', async t => { t.teardown(() => { npm._mockOutputs.length = 0 }) @@ -525,14 +461,9 @@ t.test('npm init workspces with root', t => { console.log = noop process.chdir(npm.localPrefix) - init.execWorkspaces([], ['packages/a'], err => { - if (err) - throw err - - const pkg = require(resolve(npm.localPrefix, 'package.json')) - t.equal(pkg.version, '1.0.0') - t.equal(pkg.license, 'ISC') - t.matchSnapshot(npm._mockOutputs, 'does not print helper info') - t.end() - }) + await init.execWorkspaces([], ['packages/a']) + const pkg = require(resolve(npm.localPrefix, 'package.json')) + t.equal(pkg.version, '1.0.0') + t.equal(pkg.license, 'ISC') + t.matchSnapshot(npm._mockOutputs, 'does not print helper info') }) diff --git a/deps/npm/test/lib/commands/install-ci-test.js b/deps/npm/test/lib/commands/install-ci-test.js new file mode 100644 index 00000000000000..2baec1e0120ef5 --- /dev/null +++ b/deps/npm/test/lib/commands/install-ci-test.js @@ -0,0 +1,55 @@ +const t = require('tap') + +const InstallCITest = require('../../../lib/commands/install-ci-test.js') + +let ciArgs = null +let ciCalled = false +let testArgs = null +let testCalled = false +let ciError = null + +const installCITest = new InstallCITest({ + exec: (cmd, args) => { + if (cmd === 'ci') { + ciArgs = args + ciCalled = true + } + if (ciError) + throw ciError + + if (cmd === 'test') { + testArgs = args + testCalled = true + } + }, +}) + +t.test('the install-ci-test command', t => { + t.afterEach(() => { + ciArgs = null + ciCalled = false + testArgs = null + testCalled = false + ciError = null + }) + + t.test('ci and test', async t => { + await installCITest.exec(['extra']) + t.equal(ciCalled, true) + t.equal(testCalled, true) + t.match(ciArgs, ['extra']) + t.match(testArgs, []) + }) + + t.test('ci fails', async t => { + ciError = new Error('test fail') + await t.rejects( + installCITest.exec(['extra']), + 'test fail' + ) + t.equal(ciCalled, true) + t.equal(testCalled, false) + t.match(ciArgs, ['extra']) + }) + t.end() +}) diff --git a/deps/npm/test/lib/commands/install-test.js b/deps/npm/test/lib/commands/install-test.js new file mode 100644 index 00000000000000..291755bf8288b7 --- /dev/null +++ b/deps/npm/test/lib/commands/install-test.js @@ -0,0 +1,55 @@ +const t = require('tap') + +const InstallTest = require('../../../lib/commands/install-test.js') + +let installArgs = null +let installCalled = false +let testArgs = null +let testCalled = false +let installError = null + +const installTest = new InstallTest({ + exec: (cmd, args) => { + if (cmd === 'install') { + installArgs = args + installCalled = true + } + if (installError) + throw installError + + if (cmd === 'test') { + testArgs = args + testCalled = true + } + }, +}) + +t.test('the install-test command', t => { + t.afterEach(() => { + installArgs = null + installCalled = false + testArgs = null + testCalled = false + installError = null + }) + + t.test('install and test', async t => { + await installTest.exec(['extra']) + t.equal(installCalled, true) + t.equal(testCalled, true) + t.match(installArgs, ['extra']) + t.match(testArgs, []) + }) + + t.test('install fails', async t => { + installError = new Error('test fail') + await t.rejects( + installTest.exec(['extra']), + 'test fail' + ) + t.equal(installCalled, true) + t.equal(testCalled, false) + t.match(installArgs, ['extra']) + }) + t.end() +}) diff --git a/deps/npm/test/lib/install.js b/deps/npm/test/lib/commands/install.js similarity index 66% rename from deps/npm/test/lib/install.js rename to deps/npm/test/lib/commands/install.js index 2cbee02e67b287..3f9c5f264a3bac 100644 --- a/deps/npm/test/lib/install.js +++ b/deps/npm/test/lib/commands/install.js @@ -1,7 +1,7 @@ const t = require('tap') -const Install = require('../../lib/install.js') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const Install = require('../../../lib/commands/install.js') +const { fake: mockNpm } = require('../../fixtures/mock-npm') t.test('should install using Arborist', (t) => { const SCRIPTS = [] @@ -9,7 +9,7 @@ t.test('should install using Arborist', (t) => { let REIFY_CALLED = false let ARB_OBJ = null - const Install = t.mock('../../lib/install.js', { + const Install = t.mock('../../../lib/commands/install.js', { '@npmcli/run-script': ({ event }) => { SCRIPTS.push(event) }, @@ -23,7 +23,7 @@ t.test('should install using Arborist', (t) => { REIFY_CALLED = true } }, - '../../lib/utils/reify-finish.js': (npm, arb) => { + '../../../lib/utils/reify-finish.js': (npm, arb) => { if (arb !== ARB_OBJ) throw new Error('got wrong object passed to reify-finish') }, @@ -37,46 +37,38 @@ t.test('should install using Arborist', (t) => { }) const install = new Install(npm) - t.test('with args', t => { - install.exec(['fizzbuzz'], er => { - if (er) - throw er - t.match(ARB_ARGS, - { global: false, path: 'foo', auditLevel: null }, - 'Arborist gets correct args and ignores auditLevel') - t.equal(REIFY_CALLED, true, 'called reify') - t.strictSame(SCRIPTS, [], 'no scripts when adding dep') - t.end() - }) + t.test('with args', async t => { + await install.exec(['fizzbuzz']) + t.match(ARB_ARGS, + { global: false, path: 'foo', auditLevel: null }, + 'Arborist gets correct args and ignores auditLevel') + t.equal(REIFY_CALLED, true, 'called reify') + t.strictSame(SCRIPTS, [], 'no scripts when adding dep') }) - t.test('just a local npm install', t => { - install.exec([], er => { - if (er) - throw er - t.match(ARB_ARGS, { global: false, path: 'foo' }) - t.equal(REIFY_CALLED, true, 'called reify') - t.strictSame(SCRIPTS, [ - 'preinstall', - 'install', - 'postinstall', - 'prepublish', - 'preprepare', - 'prepare', - 'postprepare', - ], 'exec scripts when doing local build') - t.end() - }) + t.test('just a local npm install', async t => { + await install.exec([]) + t.match(ARB_ARGS, { global: false, path: 'foo' }) + t.equal(REIFY_CALLED, true, 'called reify') + t.strictSame(SCRIPTS, [ + 'preinstall', + 'install', + 'postinstall', + 'prepublish', + 'preprepare', + 'prepare', + 'postprepare', + ], 'exec scripts when doing local build') }) t.end() }) -t.test('should ignore scripts with --ignore-scripts', (t) => { +t.test('should ignore scripts with --ignore-scripts', async t => { const SCRIPTS = [] let REIFY_CALLED = false - const Install = t.mock('../../lib/install.js', { - '../../lib/utils/reify-finish.js': async () => {}, + const Install = t.mock('../../../lib/commands/install.js', { + '../../../lib/utils/reify-finish.js': async () => {}, '@npmcli/run-script': ({ event }) => { SCRIPTS.push(event) }, @@ -96,18 +88,14 @@ t.test('should ignore scripts with --ignore-scripts', (t) => { }, }) const install = new Install(npm) - install.exec([], er => { - if (er) - throw er - t.equal(REIFY_CALLED, true, 'called reify') - t.strictSame(SCRIPTS, [], 'no scripts when adding dep') - t.end() - }) + await install.exec([]) + t.equal(REIFY_CALLED, true, 'called reify') + t.strictSame(SCRIPTS, [], 'no scripts when adding dep') }) -t.test('should install globally using Arborist', (t) => { - const Install = t.mock('../../lib/install.js', { - '../../lib/utils/reify-finish.js': async () => {}, +t.test('should install globally using Arborist', async t => { + const Install = t.mock('../../../lib/commands/install.js', { + '../../../lib/utils/reify-finish.js': async () => {}, '@npmcli/arborist': function () { this.reify = () => {} }, @@ -119,16 +107,12 @@ t.test('should install globally using Arborist', (t) => { flatOptions: { global: true }, }) const install = new Install(npm) - install.exec([], er => { - if (er) - throw er - t.end() - }) + await install.exec([]) }) -t.test('npm i -g npm engines check success', (t) => { - const Install = t.mock('../../lib/install.js', { - '../../lib/utils/reify-finish.js': async () => {}, +t.test('npm i -g npm engines check success', async t => { + const Install = t.mock('../../../lib/commands/install.js', { + '../../../lib/utils/reify-finish.js': async () => {}, '@npmcli/arborist': function () { this.reify = () => {} }, @@ -150,15 +134,11 @@ t.test('npm i -g npm engines check success', (t) => { }, }) const install = new Install(npm) - install.exec(['npm'], er => { - if (er) - throw er - t.end() - }) + await install.exec(['npm']) }) -t.test('npm i -g npm engines check failure', (t) => { - const Install = t.mock('../../lib/install.js', { +t.test('npm i -g npm engines check failure', async t => { + const Install = t.mock('../../../lib/commands/install.js', { pacote: { manifest: () => { return { @@ -178,8 +158,9 @@ t.test('npm i -g npm engines check failure', (t) => { }, }) const install = new Install(npm) - install.exec(['npm'], er => { - t.match(er, { + await t.rejects( + install.exec(['npm']), + { message: 'Unsupported engine', pkgid: 'npm@1.2.3', current: { @@ -190,14 +171,13 @@ t.test('npm i -g npm engines check failure', (t) => { node: '>1000', }, code: 'EBADENGINE', - }) - t.end() - }) + } + ) }) -t.test('npm i -g npm engines check failure forced override', (t) => { - const Install = t.mock('../../lib/install.js', { - '../../lib/utils/reify-finish.js': async () => {}, +t.test('npm i -g npm engines check failure forced override', async t => { + const Install = t.mock('../../../lib/commands/install.js', { + '../../../lib/utils/reify-finish.js': async () => {}, '@npmcli/arborist': function () { this.reify = () => {} }, @@ -221,15 +201,11 @@ t.test('npm i -g npm engines check failure forced override', (t) => { }, }) const install = new Install(npm) - install.exec(['npm'], er => { - if (er) - throw er - t.end() - }) + await install.exec(['npm']) }) -t.test('npm i -g npm@version engines check failure', (t) => { - const Install = t.mock('../../lib/install.js', { +t.test('npm i -g npm@version engines check failure', async t => { + const Install = t.mock('../../../lib/commands/install.js', { pacote: { manifest: () => { return { @@ -249,8 +225,9 @@ t.test('npm i -g npm@version engines check failure', (t) => { }, }) const install = new Install(npm) - install.exec(['npm@100'], er => { - t.match(er, { + await t.rejects( + install.exec(['npm@100']), + { message: 'Unsupported engine', pkgid: 'npm@1.2.3', current: { @@ -261,14 +238,13 @@ t.test('npm i -g npm@version engines check failure', (t) => { node: '>1000', }, code: 'EBADENGINE', - }) - t.end() - }) + } + ) }) t.test('completion to folder', async t => { - const Install = t.mock('../../lib/install.js', { - '../../lib/utils/reify-finish.js': async () => {}, + const Install = t.mock('../../../lib/commands/install.js', { + '../../../lib/utils/reify-finish.js': async () => {}, util: { promisify: (fn) => fn, }, @@ -285,12 +261,11 @@ t.test('completion to folder', async t => { const res = await install.completion({ partialWord: '/ar' }) const expect = process.platform === 'win32' ? '\\arborist' : '/arborist' t.strictSame(res, [expect], 'package dir match') - t.end() }) t.test('completion to folder - invalid dir', async t => { - const Install = t.mock('../../lib/install.js', { - '../../lib/utils/reify-finish.js': async () => {}, + const Install = t.mock('../../../lib/commands/install.js', { + '../../../lib/utils/reify-finish.js': async () => {}, util: { promisify: (fn) => fn, }, @@ -303,12 +278,11 @@ t.test('completion to folder - invalid dir', async t => { const install = new Install({}) const res = await install.completion({ partialWord: 'path/to/folder' }) t.strictSame(res, [], 'invalid dir: no matching') - t.end() }) t.test('completion to folder - no matches', async t => { - const Install = t.mock('../../lib/install.js', { - '../../lib/utils/reify-finish.js': async () => {}, + const Install = t.mock('../../../lib/commands/install.js', { + '../../../lib/utils/reify-finish.js': async () => {}, util: { promisify: (fn) => fn, }, @@ -321,12 +295,11 @@ t.test('completion to folder - no matches', async t => { const install = new Install({}) const res = await install.completion({ partialWord: '/pa' }) t.strictSame(res, [], 'no name match') - t.end() }) t.test('completion to folder - match is not a package', async t => { - const Install = t.mock('../../lib/install.js', { - '../../lib/utils/reify-finish.js': async () => {}, + const Install = t.mock('../../../lib/commands/install.js', { + '../../../lib/utils/reify-finish.js': async () => {}, util: { promisify: (fn) => fn, }, @@ -342,19 +315,16 @@ t.test('completion to folder - match is not a package', async t => { const install = new Install({}) const res = await install.completion({ partialWord: '/ar' }) t.strictSame(res, [], 'no name match') - t.end() }) t.test('completion to url', async t => { const install = new Install({}) const res = await install.completion({ partialWord: 'http://path/to/url' }) t.strictSame(res, []) - t.end() }) t.test('completion', async t => { const install = new Install({}) const res = await install.completion({ partialWord: 'toto' }) t.notOk(res) - t.end() }) diff --git a/deps/npm/test/lib/link.js b/deps/npm/test/lib/commands/link.js similarity index 77% rename from deps/npm/test/lib/link.js rename to deps/npm/test/lib/commands/link.js index 96f689892ff83b..60215a0dcc0641 100644 --- a/deps/npm/test/lib/link.js +++ b/deps/npm/test/lib/commands/link.js @@ -3,7 +3,7 @@ const { resolve } = require('path') const fs = require('fs') const Arborist = require('@npmcli/arborist') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') const redactCwd = (path) => { const normalizePath = p => p @@ -15,7 +15,6 @@ const redactCwd = (path) => { t.cleanSnapshot = (str) => redactCwd(str) -let reifyOutput const config = {} const npm = mockNpm({ globalDir: null, @@ -37,15 +36,13 @@ const printLinks = async (opts) => { } const mocks = { - '../../lib/utils/reify-output.js': () => reifyOutput(), + '../../../lib/utils/reify-output.js': async () => {}, } -const Link = t.mock('../../lib/link.js', mocks) +const Link = t.mock('../../../lib/commands/link.js', mocks) const link = new Link(npm) -t.test('link to globalDir when in current working dir of pkg and no args', (t) => { - t.plan(2) - +t.test('link to globalDir when in current working dir of pkg and no args', async t => { const testdir = t.testdir({ 'global-prefix': { lib: { @@ -69,25 +66,16 @@ t.test('link to globalDir when in current working dir of pkg and no args', (t) = npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules') npm.prefix = resolve(testdir, 'test-pkg-link') - reifyOutput = async () => { - reifyOutput = undefined - - const links = await printLinks({ - path: resolve(npm.globalDir, '..'), - global: true, - }) - - t.matchSnapshot(links, 'should create a global link to current pkg') - } - - link.exec([], (err) => { - t.error(err, 'should not error out') + await link.exec([]) + const links = await printLinks({ + path: resolve(npm.globalDir, '..'), + global: true, }) -}) -t.test('link ws to globalDir when workspace specified and no args', (t) => { - t.plan(2) + t.matchSnapshot(links, 'should create a global link to current pkg') +}) +t.test('link ws to globalDir when workspace specified and no args', async t => { const testdir = t.testdir({ 'global-prefix': { lib: { @@ -121,27 +109,18 @@ t.test('link ws to globalDir when workspace specified and no args', (t) => { npm.prefix = resolve(testdir, 'test-pkg-link') npm.localPrefix = resolve(testdir, 'test-pkg-link') - reifyOutput = async () => { - reifyOutput = undefined - - const links = await printLinks({ - path: resolve(npm.globalDir, '..'), - global: true, - }) - - t.matchSnapshot(links, 'should create a global link to current pkg') - } - // link.workspaces = ['a'] // link.workspacePaths = [resolve(testdir, 'test-pkg-link/packages/a')] - link.execWorkspaces([], ['a'], (err) => { - t.error(err, 'should not error out') + await link.execWorkspaces([], ['a']) + const links = await printLinks({ + path: resolve(npm.globalDir, '..'), + global: true, }) -}) -t.test('link global linked pkg to local nm when using args', (t) => { - t.plan(2) + t.matchSnapshot(links, 'should create a global link to current pkg') +}) +t.test('link global linked pkg to local nm when using args', async t => { const testdir = t.testdir({ 'global-prefix': { lib: { @@ -219,37 +198,28 @@ t.test('link global linked pkg to local nm when using args', (t) => { const _cwd = process.cwd() process.chdir(npm.prefix) - reifyOutput = async () => { - reifyOutput = undefined - process.chdir(_cwd) - - const links = await printLinks({ - path: npm.prefix, - }) - - t.matchSnapshot(links, 'should create a local symlink to global pkg') - } - // installs examples for: // - test-pkg-link: pkg linked to globalDir from local fs // - @myscope/linked: scoped pkg linked to globalDir from local fs // - @myscope/bar: prev installed scoped package available in globalDir // - a: prev installed package available in globalDir // - file:./link-me-too: pkg that needs to be reified in globalDir first - link.exec([ + await link.exec([ 'test-pkg-link', '@myscope/linked', '@myscope/bar', 'a', 'file:../link-me-too', - ], (err) => { - t.error(err, 'should not error out') + ]) + process.chdir(_cwd) + const links = await printLinks({ + path: npm.prefix, }) -}) -t.test('link global linked pkg to local workspace using args', (t) => { - t.plan(2) + t.matchSnapshot(links, 'should create a local symlink to global pkg') +}) +t.test('link global linked pkg to local workspace using args', async t => { const testdir = t.testdir({ 'global-prefix': { lib: { @@ -337,37 +307,29 @@ t.test('link global linked pkg to local workspace using args', (t) => { const _cwd = process.cwd() process.chdir(npm.prefix) - reifyOutput = async () => { - reifyOutput = undefined - process.chdir(_cwd) - - const links = await printLinks({ - path: npm.prefix, - }) - - t.matchSnapshot(links, 'should create a local symlink to global pkg') - } - // installs examples for: // - test-pkg-link: pkg linked to globalDir from local fs // - @myscope/linked: scoped pkg linked to globalDir from local fs // - @myscope/bar: prev installed scoped package available in globalDir // - a: prev installed package available in globalDir // - file:./link-me-too: pkg that needs to be reified in globalDir first - link.execWorkspaces([ + await link.execWorkspaces([ 'test-pkg-link', '@myscope/linked', '@myscope/bar', 'a', 'file:../link-me-too', - ], ['x'], (err) => { - t.error(err, 'should not error out') + ], ['x']) + process.chdir(_cwd) + + const links = await printLinks({ + path: npm.prefix, }) -}) -t.test('link pkg already in global space', (t) => { - t.plan(3) + t.matchSnapshot(links, 'should create a local symlink to global pkg') +}) +t.test('link pkg already in global space', async t => { const testdir = t.testdir({ 'global-prefix': { lib: { @@ -399,38 +361,30 @@ t.test('link pkg already in global space', (t) => { const _cwd = process.cwd() process.chdir(npm.prefix) - reifyOutput = async () => { - reifyOutput = undefined - process.chdir(_cwd) - npm.config.find = () => null - - const links = await printLinks({ - path: npm.prefix, - }) - - t.equal( - require(resolve(testdir, 'my-project', 'package.json')).dependencies, - undefined, - 'should not save to package.json upon linking' - ) - - t.matchSnapshot(links, 'should create a local symlink to global pkg') - } - // installs examples for: // - test-pkg-link: pkg linked to globalDir from local fs // - @myscope/linked: scoped pkg linked to globalDir from local fs // - @myscope/bar: prev installed scoped package available in globalDir // - a: prev installed package available in globalDir // - file:./link-me-too: pkg that needs to be reified in globalDir first - link.exec(['@myscope/linked'], (err) => { - t.error(err, 'should not error out') + await link.exec(['@myscope/linked']) + process.chdir(_cwd) + npm.config.find = () => null + + const links = await printLinks({ + path: npm.prefix, }) -}) -t.test('link pkg already in global space when prefix is a symlink', (t) => { - t.plan(3) + t.equal( + require(resolve(testdir, 'my-project', 'package.json')).dependencies, + undefined, + 'should not save to package.json upon linking' + ) + + t.matchSnapshot(links, 'should create a local symlink to global pkg') +}) +t.test('link pkg already in global space when prefix is a symlink', async t => { const testdir = t.testdir({ 'global-prefix': t.fixture('symlink', './real-global-prefix'), 'real-global-prefix': { @@ -463,27 +417,21 @@ t.test('link pkg already in global space when prefix is a symlink', (t) => { const _cwd = process.cwd() process.chdir(npm.prefix) - reifyOutput = async () => { - reifyOutput = undefined - process.chdir(_cwd) - npm.config.find = () => null - - const links = await printLinks({ - path: npm.prefix, - }) + await link.exec(['@myscope/linked']) + process.chdir(_cwd) + npm.config.find = () => null - t.equal( - require(resolve(testdir, 'my-project', 'package.json')).dependencies, - undefined, - 'should not save to package.json upon linking' - ) + const links = await printLinks({ + path: npm.prefix, + }) - t.matchSnapshot(links, 'should create a local symlink to global pkg') - } + t.equal( + require(resolve(testdir, 'my-project', 'package.json')).dependencies, + undefined, + 'should not save to package.json upon linking' + ) - link.exec(['@myscope/linked'], (err) => { - t.error(err, 'should not error out') - }) + t.matchSnapshot(links, 'should create a local symlink to global pkg') }) t.test('should not prune dependencies when linking packages', async t => { @@ -515,18 +463,11 @@ t.test('should not prune dependencies when linking packages', async t => { }) npm.globalDir = resolve(testdir, 'global-prefix', 'lib', 'node_modules') npm.prefix = resolve(testdir, 'my-project') - reifyOutput = () => {} const _cwd = process.cwd() process.chdir(npm.prefix) - await new Promise((res, rej) => { - link.exec(['linked'], (err) => { - if (err) - rej(err) - res() - }) - }) + await link.exec(['linked']) t.ok( fs.statSync(resolve(testdir, 'my-project/node_modules/foo')), @@ -556,21 +497,19 @@ t.test('completion', async t => { ['bar', 'foo', 'ipsum', 'lorem'], 'should list all package names available in globalDir' ) - t.end() }) -t.test('--global option', t => { +t.test('--global option', async t => { + t.teardown(() => { + npm.config = _config + }) const _config = npm.config npm.config = { get () { return true } } - link.exec([], (err) => { - npm.config = _config - t.match( - err.message, - /link should never be --global/, - 'should throw an useful error' - ) - t.end() - }) + await t.rejects( + link.exec([]), + /link should never be --global/, + 'should throw an useful error' + ) }) diff --git a/deps/npm/test/lib/ll.js b/deps/npm/test/lib/commands/ll.js similarity index 79% rename from deps/npm/test/lib/ll.js rename to deps/npm/test/lib/commands/ll.js index 28a3ab12c6a5fe..98463485842935 100644 --- a/deps/npm/test/lib/ll.js +++ b/deps/npm/test/lib/commands/ll.js @@ -8,14 +8,13 @@ t.test('ll', t => { this.npm = npm } - exec (args, cb) { + async exec (args) { t.same(args, ['pkg'], 'should forward args') - cb() } } - const LL = t.mock('../../lib/ll.js', { - '../../lib/ls.js': LS, + const LL = t.mock('../../../lib/commands/ll.js', { + '../../../lib/commands/ls.js': LS, }) const ll = new LL({ config: { diff --git a/deps/npm/test/lib/logout.js b/deps/npm/test/lib/commands/logout.js similarity index 50% rename from deps/npm/test/lib/logout.js rename to deps/npm/test/lib/commands/logout.js index 7cb5c2790d6216..09dc805c996327 100644 --- a/deps/npm/test/lib/logout.js +++ b/deps/npm/test/lib/commands/logout.js @@ -1,5 +1,5 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') const config = { registry: 'https://registry.npmjs.org/', @@ -23,11 +23,20 @@ const mocks = { 'npm-registry-fetch': npmFetch, } -const Logout = t.mock('../../lib/logout.js', mocks) +const Logout = t.mock('../../../lib/commands/logout.js', mocks) const logout = new Logout(npm) t.test('token logout', async (t) => { - t.plan(6) + t.teardown(() => { + delete flatOptions.token + result = null + mocks['npm-registry-fetch'] = null + config.clearCredentialsByURI = null + config.delete = null + config.save = null + npmlog.verbose = null + }) + t.plan(5) flatOptions['//registry.npmjs.org/:_authToken'] = '@foo/' @@ -52,40 +61,39 @@ t.test('token logout', async (t) => { t.equal(type, 'user', 'should save to user config') } - await new Promise((res, rej) => { - logout.exec([], (err) => { - t.error(err, 'should not error out') - - t.same( - result, - { - url: '/-/user/token/%40foo%2F', - opts: { - registry: 'https://registry.npmjs.org/', - scope: '', - '//registry.npmjs.org/:_authToken': '@foo/', - method: 'DELETE', - ignoreBody: true, - }, - }, - 'should call npm-registry-fetch with expected values' - ) - - delete flatOptions.token - result = null - mocks['npm-registry-fetch'] = null - config.clearCredentialsByURI = null - config.delete = null - config.save = null - npmlog.verbose = null - - res() - }) - }) + await logout.exec([]) + + t.same( + result, + { + url: '/-/user/token/%40foo%2F', + opts: { + registry: 'https://registry.npmjs.org/', + scope: '', + '//registry.npmjs.org/:_authToken': '@foo/', + method: 'DELETE', + ignoreBody: true, + }, + }, + 'should call npm-registry-fetch with expected values' + ) }) t.test('token scoped logout', async (t) => { - t.plan(8) + t.teardown(() => { + config.scope = '' + delete flatOptions['//diff-registry.npmjs.com/:_authToken'] + delete flatOptions['//registry.npmjs.org/:_authToken'] + delete config['@myscope:registry'] + delete flatOptions.scope + result = null + mocks['npm-registry-fetch'] = null + config.clearCredentialsByURI = null + config.delete = null + config.save = null + npmlog.verbose = null + }) + t.plan(7) flatOptions['//diff-registry.npmjs.com/:_authToken'] = '@bar/' flatOptions['//registry.npmjs.org/:_authToken'] = '@foo/' @@ -124,46 +132,35 @@ t.test('token scoped logout', async (t) => { t.equal(type, 'user', 'should save to user config') } - await new Promise((res, rej) => { - logout.exec([], (err) => { - t.error(err, 'should not error out') - - t.same( - result, - { - url: '/-/user/token/%40bar%2F', - opts: { - registry: 'https://registry.npmjs.org/', - '@myscope:registry': 'https://diff-registry.npmjs.com/', - scope: '@myscope', - '//registry.npmjs.org/:_authToken': '@foo/', // <- removed by npm-registry-fetch - '//diff-registry.npmjs.com/:_authToken': '@bar/', - method: 'DELETE', - ignoreBody: true, - }, - }, - 'should call npm-registry-fetch with expected values' - ) - - config.scope = '' - delete flatOptions['//diff-registry.npmjs.com/:_authToken'] - delete flatOptions['//registry.npmjs.org/:_authToken'] - delete config['@myscope:registry'] - delete flatOptions.scope - result = null - mocks['npm-registry-fetch'] = null - config.clearCredentialsByURI = null - config.delete = null - config.save = null - npmlog.verbose = null - - res() - }) - }) + await logout.exec([]) + + t.same( + result, + { + url: '/-/user/token/%40bar%2F', + opts: { + registry: 'https://registry.npmjs.org/', + '@myscope:registry': 'https://diff-registry.npmjs.com/', + scope: '@myscope', + '//registry.npmjs.org/:_authToken': '@foo/', // <- removed by npm-registry-fetch + '//diff-registry.npmjs.com/:_authToken': '@bar/', + method: 'DELETE', + ignoreBody: true, + }, + }, + 'should call npm-registry-fetch with expected values' + ) }) t.test('user/pass logout', async (t) => { - t.plan(3) + t.teardown(() => { + delete flatOptions['//registry.npmjs.org/:username'] + delete flatOptions['//registry.npmjs.org/:_password'] + npm.config.clearCredentialsByURI = null + npm.config.save = null + npmlog.verbose = null + }) + t.plan(2) flatOptions['//registry.npmjs.org/:username'] = 'foo' flatOptions['//registry.npmjs.org/:_password'] = 'bar' @@ -180,35 +177,28 @@ t.test('user/pass logout', async (t) => { npm.config.clearCredentialsByURI = () => null npm.config.save = () => null - await new Promise((res, rej) => { - logout.exec([], (err) => { - t.error(err, 'should not error out') - - delete flatOptions['//registry.npmjs.org/:username'] - delete flatOptions['//registry.npmjs.org/:_password'] - npm.config.clearCredentialsByURI = null - npm.config.save = null - npmlog.verbose = null - - res() - }) - }) + await logout.exec([]) }) -t.test('missing credentials', (t) => { - logout.exec([], (err) => { - t.match( - err.message, - /not logged in to https:\/\/registry.npmjs.org\/, so can't log out!/, - 'should throw with expected message' - ) - t.equal(err.code, 'ENEEDAUTH', 'should throw with expected error code') - t.end() - }) +t.test('missing credentials', async t => { + await t.rejects( + logout.exec([]), + { code: 'ENEEDAUTH', message: /not logged in to https:\/\/registry.npmjs.org\/, so can't log out!/ }, + 'should throw with expected error code' + ) }) t.test('ignore invalid scoped registry config', async (t) => { - t.plan(5) + t.teardown(() => { + delete flatOptions.token + result = null + mocks['npm-registry-fetch'] = null + config.clearCredentialsByURI = null + config.delete = null + config.save = null + npmlog.verbose = null + }) + t.plan(4) flatOptions['//registry.npmjs.org/:_authToken'] = '@foo/' config.scope = '@myscope' @@ -234,34 +224,20 @@ t.test('ignore invalid scoped registry config', async (t) => { npm.config.delete = () => null npm.config.save = () => null - await new Promise((res, rej) => { - logout.exec([], (err) => { - t.error(err, 'should not error out') - - t.same( - result, - { - url: '/-/user/token/%40foo%2F', - opts: { - '//registry.npmjs.org/:_authToken': '@foo/', - registry: 'https://registry.npmjs.org/', - '@myscope:registry': '', - method: 'DELETE', - ignoreBody: true, - }, - }, - 'should call npm-registry-fetch with expected values' - ) - - delete flatOptions.token - result = null - mocks['npm-registry-fetch'] = null - config.clearCredentialsByURI = null - config.delete = null - config.save = null - npmlog.verbose = null - - res() - }) - }) + await logout.exec([]) + + t.same( + result, + { + url: '/-/user/token/%40foo%2F', + opts: { + '//registry.npmjs.org/:_authToken': '@foo/', + registry: 'https://registry.npmjs.org/', + '@myscope:registry': '', + method: 'DELETE', + ignoreBody: true, + }, + }, + 'should call npm-registry-fetch with expected values' + ) }) diff --git a/deps/npm/test/lib/ls.js b/deps/npm/test/lib/commands/ls.js similarity index 65% rename from deps/npm/test/lib/ls.js rename to deps/npm/test/lib/commands/ls.js index 46dfd7fba5aa9a..97224a74c80111 100644 --- a/deps/npm/test/lib/ls.js +++ b/deps/npm/test/lib/commands/ls.js @@ -3,7 +3,7 @@ // of them contain the tap testdir folders, which are auto-generated and // may change when node-tap is updated. const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm.js') +const { fake: mockNpm } = require('../../fixtures/mock-npm.js') const { resolve } = require('path') const { utimesSync } = require('fs') @@ -90,7 +90,7 @@ const diffDepTypesNmFixture = { } let result = '' -const LS = t.mock('../../lib/ls.js', { +const LS = t.mock('../../../lib/commands/ls.js', { path: { ...require('path'), sep: '/', @@ -148,7 +148,7 @@ t.test('ls', (t) => { t.beforeEach(cleanUpResult) config.json = false config.unicode = false - t.test('no args', (t) => { + t.test('no args', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -160,25 +160,19 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output tree representation of dependencies structure') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree representation of dependencies structure') }) - t.test('missing package.json', (t) => { + t.test('missing package.json', async t => { npm.prefix = t.testdir({ ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err) // should not error for extraneous - t.matchSnapshot(redactCwd(result), 'should output tree missing name/version of top-level package') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree missing name/version of top-level package') }) - t.test('extraneous deps', (t) => { + t.test('extraneous deps', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -189,14 +183,11 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err) // should not error for extraneous - t.matchSnapshot(redactCwd(result), 'should output containing problems info') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output containing problems info') }) - t.test('with filter arg', (t) => { + t.test('with filter arg', async t => { npm.color = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -209,15 +200,12 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls.exec(['chai'], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurrences of filtered by package and colored output') - npm.color = false - t.end() - }) + await ls.exec(['chai']) + t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurrences of filtered by package and colored output') + npm.color = false }) - t.test('with dot filter arg', (t) => { + t.test('with dot filter arg', async t => { config.all = false config.depth = 0 npm.prefix = t.testdir({ @@ -231,16 +219,14 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls.exec(['.'], (err) => { - t.error(err, 'should not throw on missing dep above current level') - t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurrences of filtered by package and colored output') - config.all = true - config.depth = Infinity - t.end() - }) + await ls.exec(['.']) + t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurrences of filtered by package and colored output') + config.all = true + config.depth = Infinity + process.exitCode = 0 }) - t.test('with filter arg nested dep', (t) => { + t.test('with filter arg nested dep', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -252,14 +238,11 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls.exec(['dog'], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurrences of filtered package and its ancestors') - t.end() - }) + await ls.exec(['dog']) + t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurrences of filtered package and its ancestors') }) - t.test('with multiple filter args', (t) => { + t.test('with multiple filter args', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -280,14 +263,11 @@ t.test('ls', (t) => { }, }, }) - ls.exec(['dog@*', 'chai@1.0.0'], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurrences of multiple filtered packages and their ancestors') - t.end() - }) + await ls.exec(['dog@*', 'chai@1.0.0']) + t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurrences of multiple filtered packages and their ancestors') }) - t.test('with missing filter arg', (t) => { + t.test('with missing filter arg', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -299,20 +279,17 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls.exec(['notadep'], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output tree containing no dependencies info') - t.equal( - process.exitCode, - 1, - 'should exit with error code 1' - ) - process.exitCode = 0 - t.end() - }) + await ls.exec(['notadep']) + t.matchSnapshot(redactCwd(result), 'should output tree containing no dependencies info') + t.equal( + process.exitCode, + 1, + 'should exit with error code 1' + ) + process.exitCode = 0 }) - t.test('default --depth value should be 0', (t) => { + t.test('default --depth value should be 0', async t => { config.all = false config.depth = undefined npm.prefix = t.testdir({ @@ -326,16 +303,13 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output tree containing only top-level dependencies') - config.all = true - config.depth = Infinity - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing only top-level dependencies') + config.all = true + config.depth = Infinity }) - t.test('--depth=0', (t) => { + t.test('--depth=0', async t => { config.all = false config.depth = 0 npm.prefix = t.testdir({ @@ -349,16 +323,13 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output tree containing only top-level dependencies') - config.all = true - config.depth = Infinity - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing only top-level dependencies') + config.all = true + config.depth = Infinity }) - t.test('--depth=1', (t) => { + t.test('--depth=1', async t => { config.all = false config.depth = 1 npm.prefix = t.testdir({ @@ -410,16 +381,14 @@ t.test('ls', (t) => { }, }, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps and their deps only') - config.all = true - config.depth = Infinity - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps and their deps only') + config.all = true + config.depth = Infinity }) - t.test('missing/invalid/extraneous', (t) => { + t.test('missing/invalid/extraneous', async t => { + t.plan(3) npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -431,7 +400,7 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { + await ls.exec([]).catch(err => { t.equal(err.code, 'ELSPROBLEMS', 'should have error code') t.equal( redactCwd(err.message).replace(/\r\n/g, '\n'), @@ -440,12 +409,11 @@ t.test('ls', (t) => { 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', 'should log missing/invalid/extraneous errors' ) - t.matchSnapshot(redactCwd(result), 'should output tree containing missing, invalid, extraneous labels') - t.end() }) + t.matchSnapshot(redactCwd(result), 'should output tree containing missing, invalid, extraneous labels') }) - t.test('colored output', (t) => { + t.test('colored output', async t => { npm.color = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -458,15 +426,16 @@ t.test('ls', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.equal(err.code, 'ELSPROBLEMS', 'should have error code') - t.matchSnapshot(redactCwd(result), 'should output tree containing color info') - npm.color = false - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS' }, + 'should have error code' + ) + t.matchSnapshot(redactCwd(result), 'should output tree containing color info') + npm.color = false }) - t.test('--dev', (t) => { + t.test('--dev', async t => { config.dev = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -488,14 +457,12 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing dev deps') - config.dev = false - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing dev deps') + config.dev = false }) - t.test('--only=development', (t) => { + t.test('--only=development', async t => { config.only = 'development' npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -517,14 +484,12 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing only development deps') - config.only = null - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing only development deps') + config.only = null }) - t.test('--link', (t) => { + t.test('--link', async t => { config.link = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -556,14 +521,12 @@ t.test('ls', (t) => { ...diffDepTypesNmFixture.node_modules, }, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps') - config.link = false - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps') + config.link = false }) - t.test('print deduped symlinks', (t) => { + t.test('print deduped symlinks', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'print-deduped-symlinks', @@ -592,14 +555,12 @@ t.test('ls', (t) => { b: t.fixture('symlink', '../b'), }, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps') - config.link = false - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps') + config.link = false }) - t.test('--production', (t) => { + t.test('--production', async t => { config.production = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -621,14 +582,12 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing production deps') - config.production = false - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing production deps') + config.production = false }) - t.test('--only=prod', (t) => { + t.test('--only=prod', async t => { config.only = 'prod' npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -650,14 +609,12 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing only prod deps') - config.only = null - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing only prod deps') + config.only = null }) - t.test('--long', (t) => { + t.test('--long', async t => { config.long = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -679,14 +636,12 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree info with descriptions') - config.long = true - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree info with descriptions') + config.long = true }) - t.test('--long --depth=0', (t) => { + t.test('--long --depth=0', async t => { config.all = false config.depth = 0 config.long = true @@ -710,36 +665,32 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps with descriptions') - config.all = true - config.depth = Infinity - config.long = false - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps with descriptions') + config.all = true + config.depth = Infinity + config.long = false }) - t.test('json read problems', (t) => { + t.test('json read problems', async t => { npm.prefix = t.testdir({ 'package.json': '{broken json', }) - ls.exec([], (err) => { - t.match(err, { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error') - t.matchSnapshot(redactCwd(result), 'should print empty result') - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'EJSONPARSE' }, + 'should throw EJSONPARSE error' + ) + t.matchSnapshot(redactCwd(result), 'should print empty result') }) - t.test('empty location', (t) => { + t.test('empty location', async t => { npm.prefix = t.testdir({}) - ls.exec([], (err) => { - t.error(err, 'should not error out on empty locations') - t.matchSnapshot(redactCwd(result), 'should print empty result') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should print empty result') }) - t.test('invalid peer dep', (t) => { + t.test('invalid peer dep', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -760,13 +711,11 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree signaling mismatching peer dep in problems') - t.end() - }) + await t.rejects(ls.exec([])) + t.matchSnapshot(redactCwd(result), 'should output tree signaling mismatching peer dep in problems') }) - t.test('invalid deduped dep', (t) => { + t.test('invalid deduped dep', async t => { npm.color = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -795,14 +744,12 @@ t.test('ls', (t) => { }, }, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree signaling mismatching peer dep in problems') - npm.color = false - t.end() - }) + await t.rejects(ls.exec([])) + t.matchSnapshot(redactCwd(result), 'should output tree signaling mismatching peer dep in problems') + npm.color = false }) - t.test('deduped missing dep', (t) => { + t.test('deduped missing dep', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -824,15 +771,15 @@ t.test('ls', (t) => { }, }, }) - ls.exec([], (err) => { - t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') - t.match(err.message, /missing: b@\^1.0.0/, 'should list missing dep problem') - t.matchSnapshot(redactCwd(result), 'should output parseable signaling missing peer dep in problems') - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS', message: /missing: b@\^1.0.0/ }, + 'should list missing dep problem' + ) + t.matchSnapshot(redactCwd(result), 'should output parseable signaling missing peer dep in problems') }) - t.test('unmet peer dep', (t) => { + t.test('unmet peer dep', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -842,15 +789,15 @@ t.test('ls', (t) => { }, }), }) - ls.exec([], (err) => { - t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') - t.match(err.message, 'missing: peer-dep@*, required by test-npm-ls@1.0.0', 'should have missing peer-dep error msg') - t.matchSnapshot(redactCwd(result), 'should output tree signaling missing peer dep in problems') - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS', message: 'missing: peer-dep@*, required by test-npm-ls@1.0.0' }, + 'should have missing peer-dep error msg' + ) + t.matchSnapshot(redactCwd(result), 'should output tree signaling missing peer dep in problems') }) - t.test('unmet optional dep', (t) => { + t.test('unmet optional dep', async t => { npm.color = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -873,16 +820,16 @@ t.test('ls', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], (err) => { - t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') - t.match(err.message, /invalid: optional-dep@1.0.0/, 'should have invalid dep error msg') - t.matchSnapshot(redactCwd(result), 'should output tree with empty entry for missing optional deps') - npm.color = false - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS', message: /invalid: optional-dep@1.0.0/ }, + 'should have invalid dep error msg' + ) + t.matchSnapshot(redactCwd(result), 'should output tree with empty entry for missing optional deps') + npm.color = false }) - t.test('cycle deps', (t) => { + t.test('cycle deps', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -912,14 +859,11 @@ t.test('ls', (t) => { }, }, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') }) - t.test('cycle deps with filter args', (t) => { + t.test('cycle deps with filter args', async t => { npm.color = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -950,15 +894,12 @@ t.test('ls', (t) => { }, }, }) - ls.exec(['a'], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') - npm.color = false - t.end() - }) + await ls.exec(['a']) + t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') + npm.color = false }) - t.test('with no args dedupe entries', (t) => { + t.test('with no args dedupe entries', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'dedupe-entries', @@ -998,14 +939,11 @@ t.test('ls', (t) => { }, }, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') }) - t.test('with no args dedupe entries and not displaying all', (t) => { + t.test('with no args dedupe entries and not displaying all', async t => { config.all = false config.depth = 0 npm.prefix = t.testdir({ @@ -1047,16 +985,13 @@ t.test('ls', (t) => { }, }, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') - config.all = true - config.depth = Infinity - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') + config.all = true + config.depth = Infinity }) - t.test('with args and dedupe entries', (t) => { + t.test('with args and dedupe entries', async t => { npm.color = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -1097,15 +1032,12 @@ t.test('ls', (t) => { }, }, }) - ls.exec(['@npmcli/b'], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') - npm.color = false - t.end() - }) + await ls.exec(['@npmcli/b']) + t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') + npm.color = false }) - t.test('with args and different order of items', (t) => { + t.test('with args and different order of items', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'dedupe-entries', @@ -1145,14 +1077,11 @@ t.test('ls', (t) => { }, }, }) - ls.exec(['@npmcli/c'], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') - t.end() - }) + await ls.exec(['@npmcli/c']) + t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') }) - t.test('using aliases', (t) => { + t.test('using aliases', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -1189,13 +1118,11 @@ t.test('ls', (t) => { }, }) touchHiddenPackageLock(npm.prefix) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing aliases') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing aliases') }) - t.test('resolved points to git ref', (t) => { + t.test('resolved points to git ref', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -1235,14 +1162,11 @@ t.test('ls', (t) => { }, }) touchHiddenPackageLock(npm.prefix) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output tree containing git refs') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing git refs') }) - t.test('broken resolved field', (t) => { + t.test('broken resolved field', async t => { npm.prefix = t.testdir({ node_modules: { a: { @@ -1279,14 +1203,11 @@ t.test('ls', (t) => { }, }), }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should NOT print git refs in output tree') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should NOT print git refs in output tree') }) - t.test('from and resolved properties', (t) => { + t.test('from and resolved properties', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -1334,13 +1255,11 @@ t.test('ls', (t) => { }, }) touchHiddenPackageLock(npm.prefix) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should not be printed in tree output') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should not be printed in tree output') }) - t.test('global', (t) => { + t.test('global', async t => { config.global = true const fixtures = t.testdir({ node_modules: { @@ -1370,15 +1289,13 @@ t.test('ls', (t) => { // mimics lib/npm.js globalDir getter but pointing to fixtures npm.globalDir = resolve(fixtures, 'node_modules') - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should print tree and not mark top-level items extraneous') - npm.globalDir = 'MISSING_GLOBAL_DIR' - config.global = false - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should print tree and not mark top-level items extraneous') + npm.globalDir = 'MISSING_GLOBAL_DIR' + config.global = false }) - t.test('filtering by child of missing dep', (t) => { + t.test('filtering by child of missing dep', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'filter-by-child-of-missing-dep', @@ -1423,11 +1340,8 @@ t.test('ls', (t) => { }, }) - ls.exec(['c'], (err) => { - t.error(err) // should not error for extraneous - t.matchSnapshot(redactCwd(result), 'should print tree and not duplicate child of missing items') - t.end() - }) + await ls.exec(['c']) + t.matchSnapshot(redactCwd(result), 'should print tree and not duplicate child of missing items') }) t.test('loading a tree containing workspaces', async (t) => { @@ -1514,118 +1428,63 @@ t.test('ls', (t) => { }, }) - await new Promise((res, rej) => { - config.all = false - config.depth = 0 - npm.color = true - ls.exec([], (err) => { - if (err) - rej(err) - - t.matchSnapshot(redactCwd(result), - 'should list workspaces properly with default configs') - config.all = true - config.depth = Infinity - npm.color = false - res() - }) - }) + config.all = false + config.depth = 0 + npm.color = true + await ls.exec([]) + t.matchSnapshot(redactCwd(result), + 'should list workspaces properly with default configs') - await new Promise((res, rej) => { - config.all = false - config.depth = 0 - npm.color = true - npm.flatOptions.workspacesEnabled = false - ls.exec([], (err) => { - if (err) - rej(err) - - t.matchSnapshot(redactCwd(result), - 'should not list workspaces with --no-workspaces') - config.all = true - config.depth = Infinity - npm.color = false - npm.flatOptions.workspacesEnabled = true - res() - }) - }) + config.all = false + config.depth = 0 + npm.color = true + npm.flatOptions.workspacesEnabled = false + await ls.exec([]) + t.matchSnapshot(redactCwd(result), + 'should not list workspaces with --no-workspaces') + config.all = true + config.depth = Infinity + npm.color = false + npm.flatOptions.workspacesEnabled = true // --all - await new Promise((res, rej) => { - ls.exec([], (err) => { - if (err) - rej(err) - - t.matchSnapshot(redactCwd(result), - 'should list --all workspaces properly') - res() - }) - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), + 'should list --all workspaces properly') // --production - await new Promise((res, rej) => { - config.production = true - ls.exec([], (err) => { - if (err) - rej(err) + config.production = true + await ls.exec([]) - t.matchSnapshot(redactCwd(result), - 'should list only prod deps of workspaces') + t.matchSnapshot(redactCwd(result), + 'should list only prod deps of workspaces') - config.production = false - res() - }) - }) + config.production = false // filter out a single workspace using args - await new Promise((res, rej) => { - ls.exec(['d'], (err) => { - if (err) - rej(err) - - t.matchSnapshot(redactCwd(result), 'should filter single workspace') - res() - }) - }) + await ls.exec(['d']) + t.matchSnapshot(redactCwd(result), 'should filter single workspace') // filter out a single workspace and its deps using workspaces filters - await new Promise((res, rej) => { - ls.execWorkspaces([], ['a'], (err) => { - if (err) - rej(err) - - t.matchSnapshot(redactCwd(result), - 'should filter using workspace config') - res() - }) - }) + await ls.execWorkspaces([], ['a']) + + t.matchSnapshot(redactCwd(result), + 'should filter using workspace config') // filter out a workspace by parent path - await new Promise((res, rej) => { - ls.execWorkspaces([], ['./group'], (err) => { - if (err) - rej(err) - - t.matchSnapshot(redactCwd(result), - 'should filter by parent folder workspace config') - res() - }) - }) + await ls.execWorkspaces([], ['./group']) + + t.matchSnapshot(redactCwd(result), + 'should filter by parent folder workspace config') // filter by a dep within a workspaces sub tree - await new Promise((res, rej) => { - ls.execWorkspaces(['bar'], ['d'], (err) => { - if (err) - rej(err) - - t.matchSnapshot(redactCwd(result), - 'should print all tree and filter by dep within only the ws subtree') - res() - }) - }) + await ls.execWorkspaces(['bar'], ['d']) + + t.matchSnapshot(redactCwd(result), + 'should print all tree and filter by dep within only the ws subtree') }) - t.test('filter pkg arg using depth option', (t) => { + t.test('filter pkg arg using depth option', async t => { config.depth = 0 npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -1673,23 +1532,18 @@ t.test('ls', (t) => { }, }) - t.plan(6) - ls.exec(['a'], (err) => { - t.error(err, 'should NOT have ELSPROBLEMS error code') - t.matchSnapshot(redactCwd(result), 'should list a in top-level only') - - ls.exec(['d'], (err) => { - t.error(err, 'should NOT have ELSPROBLEMS error code when filter') - t.matchSnapshot(redactCwd(result), 'should print empty results msg') - - // if no --depth config is defined, should print path to dep - config.depth = null // default config value - ls.exec(['d'], (err) => { - t.error(err, 'should NOT have ELSPROBLEMS error code when filter') - t.matchSnapshot(redactCwd(result), 'should print expected result') - }) - }) - }) + t.plan(3) + await ls.exec(['a']) + t.matchSnapshot(redactCwd(result), 'should list a in top-level only') + + await ls.exec(['d']) + t.matchSnapshot(redactCwd(result), 'should print empty results msg') + + // if no --depth config is defined, should print path to dep + config.depth = null // default config value + await ls.exec(['d']) + t.matchSnapshot(redactCwd(result), 'should print expected result') + process.exitCode = 0 }) t.teardown(() => { @@ -1704,7 +1558,7 @@ t.test('ls --parseable', (t) => { config.json = false config.unicode = false config.parseable = true - t.test('no args', (t) => { + t.test('no args', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -1716,25 +1570,19 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output parseable representation of dependencies structure') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output parseable representation of dependencies structure') }) - t.test('missing package.json', (t) => { + t.test('missing package.json', async t => { npm.prefix = t.testdir({ ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err) // should not error for extraneous - t.matchSnapshot(redactCwd(result), 'should output parseable missing name/version of top-level package') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output parseable missing name/version of top-level package') }) - t.test('extraneous deps', (t) => { + t.test('extraneous deps', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -1745,14 +1593,11 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err) // should not error for extraneous - t.matchSnapshot(redactCwd(result), 'should output containing problems info') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output containing problems info') }) - t.test('with filter arg', (t) => { + t.test('with filter arg', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -1764,14 +1609,11 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls.exec(['chai'], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output parseable contaning only occurrences of filtered by package') - t.end() - }) + await ls.exec(['chai']) + t.matchSnapshot(redactCwd(result), 'should output parseable contaning only occurrences of filtered by package') }) - t.test('with filter arg nested dep', (t) => { + t.test('with filter arg nested dep', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -1783,14 +1625,11 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls.exec(['dog'], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output parseable contaning only occurrences of filtered package') - t.end() - }) + await ls.exec(['dog']) + t.matchSnapshot(redactCwd(result), 'should output parseable contaning only occurrences of filtered package') }) - t.test('with multiple filter args', (t) => { + t.test('with multiple filter args', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -1811,14 +1650,11 @@ t.test('ls --parseable', (t) => { }, }, }) - ls.exec(['dog@*', 'chai@1.0.0'], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output parseable contaning only occurrences of multiple filtered packages and their ancestors') - t.end() - }) + await ls.exec(['dog@*', 'chai@1.0.0']) + t.matchSnapshot(redactCwd(result), 'should output parseable contaning only occurrences of multiple filtered packages and their ancestors') }) - t.test('with missing filter arg', (t) => { + t.test('with missing filter arg', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -1830,20 +1666,11 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls.exec(['notadep'], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output parseable output containing no dependencies info') - t.equal( - process.exitCode, - 1, - 'should exit with error code 1' - ) - process.exitCode = 0 - t.end() - }) + await ls.exec(['notadep']) + t.matchSnapshot(redactCwd(result), 'should output parseable output containing no dependencies info') }) - t.test('default --depth value should be 0', (t) => { + t.test('default --depth value should be 0', async t => { config.all = false config.depth = undefined npm.prefix = t.testdir({ @@ -1857,16 +1684,13 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output parseable output containing only top-level dependencies') - config.all = true - config.depth = Infinity - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output parseable output containing only top-level dependencies') + config.all = true + config.depth = Infinity }) - t.test('--depth=0', (t) => { + t.test('--depth=0', async t => { config.all = false config.depth = 0 npm.prefix = t.testdir({ @@ -1880,16 +1704,13 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output tree containing only top-level dependencies') - config.all = true - config.depth = Infinity - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing only top-level dependencies') + config.all = true + config.depth = Infinity }) - t.test('--depth=1', (t) => { + t.test('--depth=1', async t => { config.all = false config.depth = 1 npm.prefix = t.testdir({ @@ -1903,16 +1724,13 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output parseable containing top-level deps and their deps only') - config.all = true - config.depth = Infinity - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output parseable containing top-level deps and their deps only') + config.all = true + config.depth = Infinity }) - t.test('missing/invalid/extraneous', (t) => { + t.test('missing/invalid/extraneous', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -1924,14 +1742,15 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems') - t.matchSnapshot(redactCwd(result), 'should output parseable containing top-level deps and their deps only') - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS' }, + 'should list dep problems' + ) + t.matchSnapshot(redactCwd(result), 'should output parseable containing top-level deps and their deps only') }) - t.test('--dev', (t) => { + t.test('--dev', async t => { config.dev = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -1953,14 +1772,12 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing dev deps') - config.dev = false - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing dev deps') + config.dev = false }) - t.test('--only=development', (t) => { + t.test('--only=development', async t => { config.only = 'development' npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -1982,14 +1799,12 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing only development deps') - config.only = null - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing only development deps') + config.only = null }) - t.test('--link', (t) => { + t.test('--link', async t => { config.link = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -2021,14 +1836,12 @@ t.test('ls --parseable', (t) => { ...diffDepTypesNmFixture.node_modules, }, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps') - config.link = false - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing linked deps') + config.link = false }) - t.test('--production', (t) => { + t.test('--production', async t => { config.production = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -2050,14 +1863,12 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing production deps') - config.production = false - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing production deps') + config.production = false }) - t.test('--only=prod', (t) => { + t.test('--only=prod', async t => { config.only = 'prod' npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -2079,14 +1890,12 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing only prod deps') - config.only = null - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing only prod deps') + config.only = null }) - t.test('--long', (t) => { + t.test('--long', async t => { config.long = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -2108,14 +1917,12 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree info with descriptions') - config.long = true - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree info with descriptions') + config.long = true }) - t.test('--long with extraneous deps', (t) => { + t.test('--long with extraneous deps', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -2126,14 +1933,11 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err) // should not error for extraneous - t.matchSnapshot(redactCwd(result), 'should output long parseable output with extraneous info') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output long parseable output with extraneous info') }) - t.test('--long missing/invalid/extraneous', (t) => { + t.test('--long missing/invalid/extraneous', async t => { config.long = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -2146,15 +1950,16 @@ t.test('ls --parseable', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems') - t.matchSnapshot(redactCwd(result), 'should output parseable result containing EXTRANEOUS/INVALID labels') - config.long = false - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS' }, + 'should list dep problems' + ) + t.matchSnapshot(redactCwd(result), 'should output parseable result containing EXTRANEOUS/INVALID labels') + config.long = false }) - t.test('--long print symlink target location', (t) => { + t.test('--long print symlink target location', async t => { config.long = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -2186,15 +1991,12 @@ t.test('ls --parseable', (t) => { ...diffDepTypesNmFixture.node_modules, }, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output parseable results with symlink targets') - config.long = false - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output parseable results with symlink targets') + config.long = false }) - t.test('--long --depth=0', (t) => { + t.test('--long --depth=0', async t => { config.all = false config.depth = 0 config.long = true @@ -2218,36 +2020,31 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps with descriptions') - config.all = true - config.depth = Infinity - config.long = false - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps with descriptions') + config.all = true + config.depth = Infinity + config.long = false }) - t.test('json read problems', (t) => { + t.test('json read problems', async t => { npm.prefix = t.testdir({ 'package.json': '{broken json', }) - ls.exec([], (err) => { - t.match(err, { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error') - t.matchSnapshot(redactCwd(result), 'should print empty result') - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'EJSONPARSE' }, + 'should throw EJSONPARSE error') + t.matchSnapshot(redactCwd(result), 'should print empty result') }) - t.test('empty location', (t) => { + t.test('empty location', async t => { npm.prefix = t.testdir({}) - ls.exec([], (err) => { - t.error(err, 'should not error out on empty locations') - t.matchSnapshot(redactCwd(result), 'should print empty result') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should print empty result') }) - t.test('unmet peer dep', (t) => { + t.test('unmet peer dep', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -2268,13 +2065,11 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output parseable signaling missing peer dep in problems') - t.end() - }) + await t.rejects(ls.exec([])) + t.matchSnapshot(redactCwd(result), 'should output parseable signaling missing peer dep in problems') }) - t.test('unmet optional dep', (t) => { + t.test('unmet optional dep', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -2296,15 +2091,15 @@ t.test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], (err) => { - t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') - t.match(err.message, /invalid: optional-dep@1.0.0/, 'should have invalid dep error msg') - t.matchSnapshot(redactCwd(result), 'should output parseable with empty entry for missing optional deps') - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS', message: /invalid: optional-dep@1.0.0/ }, + 'should have invalid dep error msg' + ) + t.matchSnapshot(redactCwd(result), 'should output parseable with empty entry for missing optional deps') }) - t.test('cycle deps', (t) => { + t.test('cycle deps', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -2334,13 +2129,11 @@ t.test('ls --parseable', (t) => { }, }, }) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should print tree output omitting deduped ref') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should print tree output omitting deduped ref') }) - t.test('using aliases', (t) => { + t.test('using aliases', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -2373,13 +2166,11 @@ t.test('ls --parseable', (t) => { }, }) touchHiddenPackageLock(npm.prefix) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing aliases') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing aliases') }) - t.test('resolved points to git ref', (t) => { + t.test('resolved points to git ref', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -2418,13 +2209,11 @@ t.test('ls --parseable', (t) => { }, }) touchHiddenPackageLock(npm.prefix) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing git refs') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should output tree containing git refs') }) - t.test('from and resolved properties', (t) => { + t.test('from and resolved properties', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -2472,13 +2261,11 @@ t.test('ls --parseable', (t) => { }, }) touchHiddenPackageLock(npm.prefix) - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should not be printed in tree output') - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should not be printed in tree output') }) - t.test('global', (t) => { + t.test('global', async t => { config.global = true const fixtures = t.testdir({ node_modules: { @@ -2508,12 +2295,10 @@ t.test('ls --parseable', (t) => { // mimics lib/npm.js globalDir getter but pointing to fixtures npm.globalDir = resolve(fixtures, 'node_modules') - ls.exec([], () => { - t.matchSnapshot(redactCwd(result), 'should print parseable output for global deps') - npm.globalDir = 'MISSING_GLOBAL_DIR' - config.global = false - t.end() - }) + await ls.exec([]) + t.matchSnapshot(redactCwd(result), 'should print parseable output for global deps') + npm.globalDir = 'MISSING_GLOBAL_DIR' + config.global = false }) t.end() @@ -2588,34 +2373,36 @@ t.test('ignore missing optional deps', async t => { const cleanupPaths = str => str.toLowerCase().replace(/\\/g, '/').split(prefix).join('{project}') - t.test('--json', t => { + t.test('--json', async t => { config.json = true config.parseable = false - ls.exec([], (err) => { - t.match(err, { code: 'ELSPROBLEMS' }) - result = JSON.parse(result) - const problems = result.problems.map(cleanupPaths) - t.matchSnapshot(problems, 'ls --json problems') - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS' } + ) + result = JSON.parse(result) + const problems = result.problems.map(cleanupPaths) + t.matchSnapshot(problems, 'ls --json problems') }) - t.test('--parseable', t => { + + t.test('--parseable', async t => { config.json = false config.parseable = true - ls.exec([], (err) => { - t.match(err, { code: 'ELSPROBLEMS' }) - t.matchSnapshot(cleanupPaths(result), 'ls --parseable result') - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS' } + ) + t.matchSnapshot(cleanupPaths(result), 'ls --parseable result') }) - t.test('human output', t => { + + t.test('human output', async t => { config.json = false config.parseable = false - ls.exec([], (err) => { - t.match(err, { code: 'ELSPROBLEMS' }) - t.matchSnapshot(cleanupPaths(result), 'ls result') - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS' } + ) + t.matchSnapshot(cleanupPaths(result), 'ls result') }) }) @@ -2623,7 +2410,7 @@ t.test('ls --json', (t) => { t.beforeEach(cleanUpResult) config.json = true config.parseable = false - t.test('no args', (t) => { + t.test('no args', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -2635,83 +2422,77 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - dependencies: { - dog: { - version: '1.0.0', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { + dog: { + version: '1.0.0', }, }, - chai: { - version: '1.0.0', - }, + }, + chai: { + version: '1.0.0', }, }, - 'should output json representation of dependencies structure' - ) - t.end() - }) + }, + 'should output json representation of dependencies structure' + ) }) - t.test('missing package.json', (t) => { + t.test('missing package.json', async t => { npm.prefix = t.testdir({ ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err) // should not error for extraneous - t.same( - jsonParse(result), - { - problems: [ - 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/chai', - 'extraneous: dog@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/dog', - 'extraneous: foo@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/foo', - ], - dependencies: { - dog: { - version: '1.0.0', - extraneous: true, - problems: [ - 'extraneous: dog@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/dog', - ], - }, - foo: { - version: '1.0.0', - extraneous: true, - problems: [ - 'extraneous: foo@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/foo', - ], - dependencies: { - dog: { - version: '1.0.0', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + problems: [ + 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/chai', + 'extraneous: dog@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/dog', + 'extraneous: foo@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/foo', + ], + dependencies: { + dog: { + version: '1.0.0', + extraneous: true, + problems: [ + 'extraneous: dog@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/dog', + ], + }, + foo: { + version: '1.0.0', + extraneous: true, + problems: [ + 'extraneous: foo@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/foo', + ], + dependencies: { + dog: { + version: '1.0.0', }, }, - chai: { - version: '1.0.0', - extraneous: true, - problems: [ - 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/chai', - ], - }, + }, + chai: { + version: '1.0.0', + extraneous: true, + problems: [ + 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-package.json/node_modules/chai', + ], }, }, - 'should output json missing name/version of top-level package' - ) - t.end() - }) + }, + 'should output json missing name/version of top-level package' + ) }) - t.test('extraneous deps', (t) => { + t.test('extraneous deps', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -2722,41 +2503,39 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err) // should not error for extraneous - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - problems: [ - 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-extraneous-deps/node_modules/chai', - ], - dependencies: { - foo: { - version: '1.0.0', - dependencies: { - dog: { - version: '1.0.0', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + problems: [ + 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-extraneous-deps/node_modules/chai', + ], + dependencies: { + foo: { + version: '1.0.0', + dependencies: { + dog: { + version: '1.0.0', }, }, - chai: { - version: '1.0.0', - extraneous: true, - problems: [ - 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-extraneous-deps/node_modules/chai', - ], - }, + }, + chai: { + version: '1.0.0', + extraneous: true, + problems: [ + 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-extraneous-deps/node_modules/chai', + ], }, }, - 'should output json containing problems info' - ) - t.end() - }) + }, + 'should output json containing problems info' + ) }) - t.test('missing deps --long', (t) => { + t.test('missing deps --long', async t => { + t.plan(3) config.long = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -2771,7 +2550,8 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { + + await ls.exec([]).catch(err => { t.equal( redactCwd(err.message), 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', @@ -2782,23 +2562,22 @@ t.test('ls --json', (t) => { 'ELSPROBLEMS', 'should have ELSPROBLEMS error code' ) - t.match( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - problems: [ - 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', - ], - }, - 'should output json containing problems info' - ) - config.long = false - t.end() }) + t.match( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + problems: [ + 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', + ], + }, + 'should output json containing problems info' + ) + config.long = false }) - t.test('with filter arg', (t) => { + t.test('with filter arg', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -2810,31 +2589,28 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls.exec(['chai'], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - chai: { - version: '1.0.0', - }, + await ls.exec(['chai']) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + chai: { + version: '1.0.0', }, }, - 'should output json contaning only occurrences of filtered by package' - ) - t.equal( - process.exitCode, - 0, - 'should exit with error code 0' - ) - t.end() - }) + }, + 'should output json contaning only occurrences of filtered by package' + ) + t.not( + process.exitCode, + 1, + 'should not exit with error code 1' + ) }) - t.test('with filter arg nested dep', (t) => { + t.test('with filter arg nested dep', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -2846,31 +2622,29 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls.exec(['dog'], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - dependencies: { - dog: { - version: '1.0.0', - }, + await ls.exec(['dog']) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { + dog: { + version: '1.0.0', }, }, }, }, - 'should output json contaning only occurrences of filtered by package' - ) - t.end() - }) + }, + 'should output json contaning only occurrences of filtered by package' + ) + t.notOk(jsonParse(result).dependencies.chai) }) - t.test('with multiple filter args', (t) => { + t.test('with multiple filter args', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -2891,34 +2665,31 @@ t.test('ls --json', (t) => { }, }, }) - ls.exec(['dog@*', 'chai@1.0.0'], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - version: '1.0.0', - name: 'test-npm-ls', - dependencies: { - foo: { - version: '1.0.0', - dependencies: { - dog: { - version: '1.0.0', - }, + await ls.exec(['dog@*', 'chai@1.0.0']) + t.same( + jsonParse(result), + { + version: '1.0.0', + name: 'test-npm-ls', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { + dog: { + version: '1.0.0', }, }, - chai: { - version: '1.0.0', - }, + }, + chai: { + version: '1.0.0', }, }, - 'should output json contaning only occurrences of multiple filtered packages and their ancestors' - ) - t.end() - }) + }, + 'should output json contaning only occurrences of multiple filtered packages and their ancestors' + ) }) - t.test('with missing filter arg', (t) => { + t.test('with missing filter arg', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -2930,27 +2701,24 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls.exec(['notadep'], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - }, - 'should output json containing no dependencies info' - ) - t.equal( - process.exitCode, - 1, - 'should exit with error code 1' - ) - process.exitCode = 0 - t.end() - }) + await ls.exec(['notadep']) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + }, + 'should output json containing no dependencies info' + ) + t.equal( + process.exitCode, + 1, + 'should exit with error code 1' + ) + process.exitCode = 0 }) - t.test('default --depth value should now be 0', (t) => { + t.test('default --depth value should now be 0', async t => { config.all = false config.depth = undefined npm.prefix = t.testdir({ @@ -2964,31 +2732,28 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - }, - chai: { - version: '1.0.0', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', }, }, - 'should output json containing only top-level dependencies' - ) - config.all = true - config.depth = Infinity - t.end() - }) + }, + 'should output json containing only top-level dependencies' + ) + config.all = true + config.depth = Infinity }) - t.test('--depth=0', (t) => { + t.test('--depth=0', async t => { config.all = false config.depth = 0 npm.prefix = t.testdir({ @@ -3002,31 +2767,28 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - }, - chai: { - version: '1.0.0', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', }, }, - 'should output json containing only top-level dependencies' - ) - config.all = true - config.depth = Infinity - t.end() - }) + }, + 'should output json containing only top-level dependencies' + ) + config.all = true + config.depth = Infinity }) - t.test('--depth=1', (t) => { + t.test('--depth=1', async t => { config.all = false config.depth = 1 npm.prefix = t.testdir({ @@ -3040,36 +2802,33 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - dependencies: { - dog: { - version: '1.0.0', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { + dog: { + version: '1.0.0', }, }, - chai: { - version: '1.0.0', - }, + }, + chai: { + version: '1.0.0', }, }, - 'should output json containing top-level deps and their deps only' - ) - config.all = true - config.depth = Infinity - t.end() - }) + }, + 'should output json containing top-level deps and their deps only' + ) + config.all = true + config.depth = Infinity }) - t.test('missing/invalid/extraneous', (t) => { + t.test('missing/invalid/extraneous', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -3081,54 +2840,55 @@ t.test('ls --json', (t) => { }), ...simpleNmFixture, }) - ls.exec([], (err) => { - t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - problems: [ - 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-invalid-extraneous/node_modules/chai', - 'invalid: foo@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-invalid-extraneous/node_modules/foo', - 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', - ], - dependencies: { - foo: { - version: '1.0.0', - invalid: '"^2.0.0" from the root project', - problems: [ - 'invalid: foo@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-invalid-extraneous/node_modules/foo', - ], - dependencies: { - dog: { - version: '1.0.0', - }, + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS' }, + 'should list dep problems' + ) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + problems: [ + 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-invalid-extraneous/node_modules/chai', + 'invalid: foo@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-invalid-extraneous/node_modules/foo', + 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', + ], + dependencies: { + foo: { + version: '1.0.0', + invalid: '"^2.0.0" from the root project', + problems: [ + 'invalid: foo@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-invalid-extraneous/node_modules/foo', + ], + dependencies: { + dog: { + version: '1.0.0', }, }, - chai: { - version: '1.0.0', - extraneous: true, - problems: [ - 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-invalid-extraneous/node_modules/chai', - ], - }, - ipsum: { - required: '^1.0.0', - missing: true, - problems: [ - 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', - ], - }, + }, + chai: { + version: '1.0.0', + extraneous: true, + problems: [ + 'extraneous: chai@1.0.0 {CWD}/tap-testdir-ls-ls---json-missing-invalid-extraneous/node_modules/chai', + ], + }, + ipsum: { + required: '^1.0.0', + missing: true, + problems: [ + 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', + ], }, }, - 'should output json containing top-level deps and their deps only' - ) - t.end() - }) + }, + 'should output json containing top-level deps and their deps only' + ) }) - t.test('--dev', (t) => { + t.test('--dev', async t => { config.dev = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -3150,32 +2910,30 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'dev-dep': { - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - dependencies: { dog: { version: '1.0.0' } }, - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'dev-dep': { + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { dog: { version: '1.0.0' } }, }, }, }, }, - 'should output json containing dev deps' - ) - config.dev = false - t.end() - }) + }, + 'should output json containing dev deps' + ) + config.dev = false }) - t.test('--only=development', (t) => { + t.test('--only=development', async t => { config.only = 'development' npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -3197,32 +2955,30 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'dev-dep': { - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - dependencies: { dog: { version: '1.0.0' } }, - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'dev-dep': { + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { dog: { version: '1.0.0' } }, }, }, }, }, - 'should output json containing only development deps' - ) - config.only = null - t.end() - }) + }, + 'should output json containing only development deps' + ) + config.only = null }) - t.test('--link', (t) => { + t.test('--link', async t => { config.link = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -3254,27 +3010,25 @@ t.test('ls --json', (t) => { ...diffDepTypesNmFixture.node_modules, }, }) - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'linked-dep': { - version: '1.0.0', - resolved: 'file:../linked-dep', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'linked-dep': { + version: '1.0.0', + resolved: 'file:../linked-dep', }, }, - 'should output json containing linked deps' - ) - config.link = false - t.end() - }) + }, + 'should output json containing linked deps' + ) + config.link = false }) - t.test('--production', (t) => { + t.test('--production', async t => { config.production = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -3296,26 +3050,24 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - chai: { version: '1.0.0' }, - 'optional-dep': { version: '1.0.0' }, - 'prod-dep': { version: '1.0.0', dependencies: { dog: { version: '2.0.0' } } }, - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + chai: { version: '1.0.0' }, + 'optional-dep': { version: '1.0.0' }, + 'prod-dep': { version: '1.0.0', dependencies: { dog: { version: '2.0.0' } } }, }, - 'should output json containing production deps' - ) - config.production = false - t.end() - }) + }, + 'should output json containing production deps' + ) + config.production = false }) - t.test('--only=prod', (t) => { + t.test('--only=prod', async t => { config.only = 'prod' npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -3337,26 +3089,24 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - chai: { version: '1.0.0' }, - 'optional-dep': { version: '1.0.0' }, - 'prod-dep': { version: '1.0.0', dependencies: { dog: { version: '2.0.0' } } }, - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + chai: { version: '1.0.0' }, + 'optional-dep': { version: '1.0.0' }, + 'prod-dep': { version: '1.0.0', dependencies: { dog: { version: '2.0.0' } } }, }, - 'should output json containing only prod deps' - ) - config.only = null - t.end() - }) + }, + 'should output json containing only prod deps' + ) + config.only = null }) - t.test('from lockfile', (t) => { + t.test('from lockfile', async t => { npm.prefix = t.testdir({ node_modules: { '@isaacs': { @@ -3450,42 +3200,40 @@ t.test('ls --json', (t) => { }, }), }) - ls.exec([], () => { - t.same( - jsonParse(result), - { - version: '1.0.0', - name: 'dedupe-lockfile', - dependencies: { - '@isaacs/dedupe-tests-a': { - version: '1.0.1', - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', - dependencies: { - '@isaacs/dedupe-tests-b': { - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', - extraneous: true, - problems: [ - 'extraneous: @isaacs/dedupe-tests-b@ {CWD}/tap-testdir-ls-ls---json-from-lockfile/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b', - ], - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + version: '1.0.0', + name: 'dedupe-lockfile', + dependencies: { + '@isaacs/dedupe-tests-a': { + version: '1.0.1', + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', + dependencies: { + '@isaacs/dedupe-tests-b': { + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', + extraneous: true, + problems: [ + 'extraneous: @isaacs/dedupe-tests-b@ {CWD}/tap-testdir-ls-ls---json-from-lockfile/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b', + ], }, }, - '@isaacs/dedupe-tests-b': { - version: '2.0.0', - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', - }, }, - problems: [ - 'extraneous: @isaacs/dedupe-tests-b@ {CWD}/tap-testdir-ls-ls---json-from-lockfile/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b', - ], + '@isaacs/dedupe-tests-b': { + version: '2.0.0', + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', + }, }, - 'should output json containing only prod deps' - ) - t.end() - }) + problems: [ + 'extraneous: @isaacs/dedupe-tests-b@ {CWD}/tap-testdir-ls-ls---json-from-lockfile/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b', + ], + }, + 'should output json containing only prod deps' + ) }) - t.test('--long', (t) => { + t.test('--long', async t => { config.long = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -3507,121 +3255,119 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'peer-dep': { - name: 'peer-dep', - description: 'Peer-dep description here', - version: '1.0.0', - _id: 'peer-dep@1.0.0', - devDependencies: {}, - peerDependencies: {}, - _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/peer-dep', - extraneous: false, - }, - 'dev-dep': { - name: 'dev-dep', - description: 'A DEV dep kind of dep', - version: '1.0.0', - dependencies: { - foo: { - name: 'foo', - version: '1.0.0', - dependencies: { - dog: { - name: 'dog', - version: '1.0.0', - _id: 'dog@1.0.0', - devDependencies: {}, - peerDependencies: {}, - _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/dog', - extraneous: false, - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'peer-dep': { + name: 'peer-dep', + description: 'Peer-dep description here', + version: '1.0.0', + _id: 'peer-dep@1.0.0', + devDependencies: {}, + peerDependencies: {}, + _dependencies: {}, + path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/peer-dep', + extraneous: false, + }, + 'dev-dep': { + name: 'dev-dep', + description: 'A DEV dep kind of dep', + version: '1.0.0', + dependencies: { + foo: { + name: 'foo', + version: '1.0.0', + dependencies: { + dog: { + name: 'dog', + version: '1.0.0', + _id: 'dog@1.0.0', + devDependencies: {}, + peerDependencies: {}, + _dependencies: {}, + path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/dog', + extraneous: false, }, - _id: 'foo@1.0.0', - devDependencies: {}, - peerDependencies: {}, - _dependencies: { dog: '^1.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/foo', - extraneous: false, }, + _id: 'foo@1.0.0', + devDependencies: {}, + peerDependencies: {}, + _dependencies: { dog: '^1.0.0' }, + path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/foo', + extraneous: false, }, - _id: 'dev-dep@1.0.0', - devDependencies: {}, - peerDependencies: {}, - _dependencies: { foo: '^1.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/dev-dep', - extraneous: false, }, - chai: { - name: 'chai', - version: '1.0.0', - _id: 'chai@1.0.0', - devDependencies: {}, - peerDependencies: {}, - _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/chai', - extraneous: false, - }, - 'optional-dep': { - name: 'optional-dep', - description: 'Maybe a dep?', - version: '1.0.0', - _id: 'optional-dep@1.0.0', - devDependencies: {}, - peerDependencies: {}, - _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/optional-dep', - extraneous: false, - }, - 'prod-dep': { - name: 'prod-dep', - description: 'A PROD dep kind of dep', - version: '1.0.0', - dependencies: { - dog: { - name: 'dog', - description: 'A dep that bars', - version: '2.0.0', - _id: 'dog@2.0.0', - devDependencies: {}, - peerDependencies: {}, - _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/prod-dep/node_modules/dog', - extraneous: false, - }, + _id: 'dev-dep@1.0.0', + devDependencies: {}, + peerDependencies: {}, + _dependencies: { foo: '^1.0.0' }, + path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/dev-dep', + extraneous: false, + }, + chai: { + name: 'chai', + version: '1.0.0', + _id: 'chai@1.0.0', + devDependencies: {}, + peerDependencies: {}, + _dependencies: {}, + path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/chai', + extraneous: false, + }, + 'optional-dep': { + name: 'optional-dep', + description: 'Maybe a dep?', + version: '1.0.0', + _id: 'optional-dep@1.0.0', + devDependencies: {}, + peerDependencies: {}, + _dependencies: {}, + path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/optional-dep', + extraneous: false, + }, + 'prod-dep': { + name: 'prod-dep', + description: 'A PROD dep kind of dep', + version: '1.0.0', + dependencies: { + dog: { + name: 'dog', + description: 'A dep that bars', + version: '2.0.0', + _id: 'dog@2.0.0', + devDependencies: {}, + peerDependencies: {}, + _dependencies: {}, + path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/prod-dep/node_modules/dog', + extraneous: false, }, - _id: 'prod-dep@1.0.0', - devDependencies: {}, - peerDependencies: {}, - _dependencies: { dog: '^2.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/prod-dep', - extraneous: false, }, + _id: 'prod-dep@1.0.0', + devDependencies: {}, + peerDependencies: {}, + _dependencies: { dog: '^2.0.0' }, + path: '{CWD}/tap-testdir-ls-ls---json---long/node_modules/prod-dep', + extraneous: false, }, - devDependencies: { 'dev-dep': '^1.0.0' }, - optionalDependencies: { 'optional-dep': '^1.0.0' }, - peerDependencies: { 'peer-dep': '^1.0.0' }, - _id: 'test-npm-ls@1.0.0', - _dependencies: { 'prod-dep': '^1.0.0', chai: '^1.0.0', 'optional-dep': '^1.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long', - extraneous: false, }, - 'should output long json info' - ) - config.long = true - t.end() - }) + devDependencies: { 'dev-dep': '^1.0.0' }, + optionalDependencies: { 'optional-dep': '^1.0.0' }, + peerDependencies: { 'peer-dep': '^1.0.0' }, + _id: 'test-npm-ls@1.0.0', + _dependencies: { 'prod-dep': '^1.0.0', chai: '^1.0.0', 'optional-dep': '^1.0.0' }, + path: '{CWD}/tap-testdir-ls-ls---json---long', + extraneous: false, + }, + 'should output long json info' + ) + config.long = true }) - t.test('--long --depth=0', (t) => { + t.test('--long --depth=0', async t => { config.all = false config.depth = 0 config.long = true @@ -3645,120 +3391,115 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'peer-dep': { - name: 'peer-dep', - description: 'Peer-dep description here', - version: '1.0.0', - _id: 'peer-dep@1.0.0', - devDependencies: {}, - peerDependencies: {}, - _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/peer-dep', - extraneous: false, - }, - 'dev-dep': { - name: 'dev-dep', - description: 'A DEV dep kind of dep', - version: '1.0.0', - _id: 'dev-dep@1.0.0', - devDependencies: {}, - peerDependencies: {}, - _dependencies: { foo: '^1.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/dev-dep', - extraneous: false, - }, - chai: { - name: 'chai', - version: '1.0.0', - _id: 'chai@1.0.0', - devDependencies: {}, - peerDependencies: {}, - _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/chai', - extraneous: false, - }, - 'optional-dep': { - name: 'optional-dep', - description: 'Maybe a dep?', - version: '1.0.0', - _id: 'optional-dep@1.0.0', - devDependencies: {}, - peerDependencies: {}, - _dependencies: {}, - path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/optional-dep', - extraneous: false, - }, - 'prod-dep': { - name: 'prod-dep', - description: 'A PROD dep kind of dep', - version: '1.0.0', - _id: 'prod-dep@1.0.0', - devDependencies: {}, - peerDependencies: {}, - _dependencies: { dog: '^2.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/prod-dep', - extraneous: false, - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'peer-dep': { + name: 'peer-dep', + description: 'Peer-dep description here', + version: '1.0.0', + _id: 'peer-dep@1.0.0', + devDependencies: {}, + peerDependencies: {}, + _dependencies: {}, + path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/peer-dep', + extraneous: false, + }, + 'dev-dep': { + name: 'dev-dep', + description: 'A DEV dep kind of dep', + version: '1.0.0', + _id: 'dev-dep@1.0.0', + devDependencies: {}, + peerDependencies: {}, + _dependencies: { foo: '^1.0.0' }, + path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/dev-dep', + extraneous: false, + }, + chai: { + name: 'chai', + version: '1.0.0', + _id: 'chai@1.0.0', + devDependencies: {}, + peerDependencies: {}, + _dependencies: {}, + path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/chai', + extraneous: false, + }, + 'optional-dep': { + name: 'optional-dep', + description: 'Maybe a dep?', + version: '1.0.0', + _id: 'optional-dep@1.0.0', + devDependencies: {}, + peerDependencies: {}, + _dependencies: {}, + path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/optional-dep', + extraneous: false, + }, + 'prod-dep': { + name: 'prod-dep', + description: 'A PROD dep kind of dep', + version: '1.0.0', + _id: 'prod-dep@1.0.0', + devDependencies: {}, + peerDependencies: {}, + _dependencies: { dog: '^2.0.0' }, + path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0/node_modules/prod-dep', + extraneous: false, }, - devDependencies: { 'dev-dep': '^1.0.0' }, - optionalDependencies: { 'optional-dep': '^1.0.0' }, - peerDependencies: { 'peer-dep': '^1.0.0' }, - _id: 'test-npm-ls@1.0.0', - _dependencies: { 'prod-dep': '^1.0.0', chai: '^1.0.0', 'optional-dep': '^1.0.0' }, - path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0', - extraneous: false, }, - 'should output json containing top-level deps in long format' - ) - config.all = true - config.depth = Infinity - config.long = false - t.end() - }) + devDependencies: { 'dev-dep': '^1.0.0' }, + optionalDependencies: { 'optional-dep': '^1.0.0' }, + peerDependencies: { 'peer-dep': '^1.0.0' }, + _id: 'test-npm-ls@1.0.0', + _dependencies: { 'prod-dep': '^1.0.0', chai: '^1.0.0', 'optional-dep': '^1.0.0' }, + path: '{CWD}/tap-testdir-ls-ls---json---long---depth-0', + extraneous: false, + }, + 'should output json containing top-level deps in long format' + ) + config.all = true + config.depth = Infinity + config.long = false }) - t.test('json read problems', (t) => { + t.test('json read problems', async t => { npm.prefix = t.testdir({ 'package.json': '{broken json', }) - ls.exec([], (err) => { - t.match(err.message, 'Failed to parse root package.json', 'should have missin root package.json msg') - t.match(err.code, 'EJSONPARSE', 'should have EJSONPARSE error code') - t.same( - jsonParse(result), - { - invalid: true, - problems: [ - 'error in {CWD}/tap-testdir-ls-ls---json-json-read-problems: Failed to parse root package.json', - ], - }, - 'should print empty json result' - ) - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'EJSONPARSE', message: 'Failed to parse root package.json' }, + 'should have missin root package.json msg' + ) + t.same( + jsonParse(result), + { + invalid: true, + problems: [ + 'error in {CWD}/tap-testdir-ls-ls---json-json-read-problems: Failed to parse root package.json', + ], + }, + 'should print empty json result' + ) }) - t.test('empty location', (t) => { + t.test('empty location', async (t) => { npm.prefix = t.testdir({}) - ls.exec([], (err) => { - t.error(err, 'should not error out on empty locations') - t.same( - jsonParse(result), - {}, - 'should print empty json result' - ) - t.end() - }) + await ls.exec([]) + t.same( + jsonParse(result), + {}, + 'should print empty json result' + ) }) - t.test('unmet peer dep', (t) => { + t.test('unmet peer dep', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -3779,45 +3520,46 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], (err) => { - t.match(err.code, 'ELSPROBLEMS', 'Should have ELSPROBLEMS error code') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - problems: [ - 'invalid: peer-dep@1.0.0 {CWD}/tap-testdir-ls-ls---json-unmet-peer-dep/node_modules/peer-dep', - ], - dependencies: { - 'peer-dep': { - version: '1.0.0', - invalid: '"^2.0.0" from the root project', - problems: [ - 'invalid: peer-dep@1.0.0 {CWD}/tap-testdir-ls-ls---json-unmet-peer-dep/node_modules/peer-dep', - ], - }, - 'dev-dep': { - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - dependencies: { dog: { version: '1.0.0' } }, - }, + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS' }, + 'Should have ELSPROBLEMS error code' + ) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + problems: [ + 'invalid: peer-dep@1.0.0 {CWD}/tap-testdir-ls-ls---json-unmet-peer-dep/node_modules/peer-dep', + ], + dependencies: { + 'peer-dep': { + version: '1.0.0', + invalid: '"^2.0.0" from the root project', + problems: [ + 'invalid: peer-dep@1.0.0 {CWD}/tap-testdir-ls-ls---json-unmet-peer-dep/node_modules/peer-dep', + ], + }, + 'dev-dep': { + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { dog: { version: '1.0.0' } }, }, }, - chai: { version: '1.0.0' }, - 'optional-dep': { version: '1.0.0' }, - 'prod-dep': { version: '1.0.0', dependencies: { dog: { version: '2.0.0' } } }, }, + chai: { version: '1.0.0' }, + 'optional-dep': { version: '1.0.0' }, + 'prod-dep': { version: '1.0.0', dependencies: { dog: { version: '2.0.0' } } }, }, - 'should output json signaling missing peer dep in problems' - ) - t.end() - }) + }, + 'should output json signaling missing peer dep in problems' + ) }) - t.test('unmet optional dep', (t) => { + t.test('unmet optional dep', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -3839,49 +3581,49 @@ t.test('ls --json', (t) => { }), ...diffDepTypesNmFixture, }) - ls.exec([], (err) => { - t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') - t.match(err.message, /invalid: optional-dep@1.0.0/, 'should have invalid dep error msg') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - problems: [ - 'invalid: optional-dep@1.0.0 {CWD}/tap-testdir-ls-ls---json-unmet-optional-dep/node_modules/optional-dep', // mismatching optional deps get flagged in problems - ], - dependencies: { - 'optional-dep': { - version: '1.0.0', - invalid: '"^2.0.0" from the root project', - problems: [ - 'invalid: optional-dep@1.0.0 {CWD}/tap-testdir-ls-ls---json-unmet-optional-dep/node_modules/optional-dep', - ], - }, - 'peer-dep': { - version: '1.0.0', - }, - 'dev-dep': { - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - dependencies: { dog: { version: '1.0.0' } }, - }, + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS', message: /invalid: optional-dep@1.0.0/ }, + 'should have invalid dep error msg' + ) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + problems: [ + 'invalid: optional-dep@1.0.0 {CWD}/tap-testdir-ls-ls---json-unmet-optional-dep/node_modules/optional-dep', // mismatching optional deps get flagged in problems + ], + dependencies: { + 'optional-dep': { + version: '1.0.0', + invalid: '"^2.0.0" from the root project', + problems: [ + 'invalid: optional-dep@1.0.0 {CWD}/tap-testdir-ls-ls---json-unmet-optional-dep/node_modules/optional-dep', + ], + }, + 'peer-dep': { + version: '1.0.0', + }, + 'dev-dep': { + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { dog: { version: '1.0.0' } }, }, }, - chai: { version: '1.0.0' }, - 'prod-dep': { version: '1.0.0', dependencies: { dog: { version: '2.0.0' } } }, - 'missing-optional-dep': {}, // missing optional dep has an empty entry in json output }, + chai: { version: '1.0.0' }, + 'prod-dep': { version: '1.0.0', dependencies: { dog: { version: '2.0.0' } } }, + 'missing-optional-dep': {}, // missing optional dep has an empty entry in json output }, - 'should output json with empty entry for missing optional deps' - ) - t.end() - }) + }, + 'should output json with empty entry for missing optional deps' + ) }) - t.test('cycle deps', (t) => { + t.test('cycle deps', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -3911,33 +3653,31 @@ t.test('ls --json', (t) => { }, }, }) - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - a: { - version: '1.0.0', - dependencies: { - b: { - version: '1.0.0', - dependencies: { - a: { version: '1.0.0' }, - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + a: { + version: '1.0.0', + dependencies: { + b: { + version: '1.0.0', + dependencies: { + a: { version: '1.0.0' }, }, }, }, }, }, - 'should print json output containing deduped ref' - ) - t.end() - }) + }, + 'should print json output containing deduped ref' + ) }) - t.test('using aliases', (t) => { + t.test('using aliases', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -3969,26 +3709,24 @@ t.test('ls --json', (t) => { }, }) touchHiddenPackageLock(npm.prefix) - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - a: { - version: '1.0.0', - resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + a: { + version: '1.0.0', + resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', }, }, - 'should output json containing aliases' - ) - t.end() - }) + }, + 'should output json containing aliases' + ) }) - t.test('resolved points to git ref', (t) => { + t.test('resolved points to git ref', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -4029,26 +3767,24 @@ t.test('ls --json', (t) => { }, }) touchHiddenPackageLock(npm.prefix) - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - abbrev: { - version: '1.1.1', - resolved: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + abbrev: { + version: '1.1.1', + resolved: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', }, }, - 'should output json containing git refs' - ) - t.end() - }) + }, + 'should output json containing git refs' + ) }) - t.test('from and resolved properties', (t) => { + t.test('from and resolved properties', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -4113,45 +3849,41 @@ t.test('ls --json', (t) => { }, }) touchHiddenPackageLock(npm.prefix) - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - 'simple-output': { - version: '2.1.1', - resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'simple-output': { + version: '2.1.1', + resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', }, }, - 'should be printed in json output' - ) - t.end() - }) + }, + 'should be printed in json output' + ) }) - t.test('node.name fallback if missing root package name', (t) => { + t.test('node.name fallback if missing root package name', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ version: '1.0.0', }), }) - ls.exec([], () => { - t.same( - jsonParse(result), - { - version: '1.0.0', - name: 'tap-testdir-ls-ls---json-node.name-fallback-if-missing-root-package-name', - }, - 'should use node.name as key in json result obj' - ) - t.end() - }) + await ls.exec([]) + t.same( + jsonParse(result), + { + version: '1.0.0', + name: 'tap-testdir-ls-ls---json-node.name-fallback-if-missing-root-package-name', + }, + 'should use node.name as key in json result obj' + ) }) - t.test('global', (t) => { + t.test('global', async t => { config.global = true const fixtures = t.testdir({ node_modules: { @@ -4181,37 +3913,35 @@ t.test('ls --json', (t) => { // mimics lib/npm.js globalDir getter but pointing to fixtures npm.globalDir = resolve(fixtures, 'node_modules') - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'tap-testdir-ls-ls---json-global', - dependencies: { - a: { - version: '1.0.0', - }, - b: { - version: '1.0.0', - dependencies: { - c: { - version: '1.0.0', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'tap-testdir-ls-ls---json-global', + dependencies: { + a: { + version: '1.0.0', + }, + b: { + version: '1.0.0', + dependencies: { + c: { + version: '1.0.0', }, }, }, }, - 'should print json output for global deps' - ) - npm.globalDir = 'MISSING_GLOBAL_DIR' - config.global = false - t.end() - }) + }, + 'should print json output for global deps' + ) + npm.globalDir = 'MISSING_GLOBAL_DIR' + config.global = false }) t.end() }) -t.test('show multiple invalid reasons', (t) => { +t.test('show multiple invalid reasons', async t => { config.json = false config.all = true config.depth = Infinity @@ -4257,11 +3987,12 @@ t.test('show multiple invalid reasons', (t) => { const cleanupPaths = str => redactCwd(str).toLowerCase().replace(/\\/g, '/') - ls.exec([], (err) => { - t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems') - t.matchSnapshot(cleanupPaths(result), 'ls result') - t.end() - }) + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS' }, + 'should list dep problems' + ) + t.matchSnapshot(cleanupPaths(result), 'ls result') }) t.test('ls --package-lock-only', (t) => { @@ -4270,7 +4001,7 @@ t.test('ls --package-lock-only', (t) => { t.beforeEach(cleanUpResult) config.json = true config.parseable = false - t.test('no args', (t) => { + t.test('no args', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -4297,34 +4028,31 @@ t.test('ls --package-lock-only', (t) => { }, }), }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - dependencies: { - dog: { - version: '1.0.0', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { + dog: { + version: '1.0.0', }, }, - chai: { - version: '1.0.0', - }, + }, + chai: { + version: '1.0.0', }, }, - 'should output json representation of dependencies structure' - ) - t.end() - }) + }, + 'should output json representation of dependencies structure' + ) }) - t.test('extraneous deps', (t) => { + t.test('extraneous deps', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -4350,31 +4078,28 @@ t.test('ls --package-lock-only', (t) => { }, }), }) - ls.exec([], (err) => { - t.error(err) // should not error for extraneous - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - dependencies: { - dog: { - version: '1.0.0', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { + dog: { + version: '1.0.0', }, }, }, }, - 'should output json containing no problem info' - ) - t.end() - }) + }, + 'should output json containing no problem info' + ) }) - t.test('missing deps --long', (t) => { + t.test('missing deps --long', async t => { config.long = true npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -4407,22 +4132,19 @@ t.test('ls --package-lock-only', (t) => { }, }), }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.match( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - }, - 'should output json containing no problems info' - ) - config.long = false - t.end() - }) + await ls.exec([]) + t.match( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + }, + 'should output json containing no problems info' + ) + config.long = false }) - t.test('with filter arg', (t) => { + t.test('with filter arg', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -4452,31 +4174,28 @@ t.test('ls --package-lock-only', (t) => { }, }), }) - ls.exec(['chai'], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - chai: { - version: '1.0.0', - }, + await ls.exec(['chai']) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + chai: { + version: '1.0.0', }, }, - 'should output json contaning only occurrences of filtered by package' - ) - t.equal( - process.exitCode, - 0, - 'should exit with error code 0' - ) - t.end() - }) + }, + 'should output json contaning only occurrences of filtered by package' + ) + t.equal( + process.exitCode, + 0, + 'should exit with error code 0' + ) }) - t.test('with filter arg nested dep', (t) => { + t.test('with filter arg nested dep', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -4506,31 +4225,28 @@ t.test('ls --package-lock-only', (t) => { }, }), }) - ls.exec(['dog'], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - dependencies: { - dog: { - version: '1.0.0', - }, + await ls.exec(['dog']) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { + dog: { + version: '1.0.0', }, }, }, }, - 'should output json contaning only occurrences of filtered by package' - ) - t.end() - }) + }, + 'should output json contaning only occurrences of filtered by package' + ) }) - t.test('with multiple filter args', (t) => { + t.test('with multiple filter args', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -4561,34 +4277,31 @@ t.test('ls --package-lock-only', (t) => { }, }), }) - ls.exec(['dog@*', 'chai@1.0.0'], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - version: '1.0.0', - name: 'test-npm-ls', - dependencies: { - foo: { - version: '1.0.0', - dependencies: { - dog: { - version: '1.0.0', - }, + await ls.exec(['dog@*', 'chai@1.0.0']) + t.same( + jsonParse(result), + { + version: '1.0.0', + name: 'test-npm-ls', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { + dog: { + version: '1.0.0', }, }, - chai: { - version: '1.0.0', - }, + }, + chai: { + version: '1.0.0', }, }, - 'should output json contaning only occurrences of multiple filtered packages and their ancestors' - ) - t.end() - }) + }, + 'should output json contaning only occurrences of multiple filtered packages and their ancestors' + ) }) - t.test('with missing filter arg', (t) => { + t.test('with missing filter arg', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -4615,27 +4328,24 @@ t.test('ls --package-lock-only', (t) => { }, }), }) - ls.exec(['notadep'], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - }, - 'should output json containing no dependencies info' - ) - t.equal( - process.exitCode, - 1, - 'should exit with error code 1' - ) - process.exitCode = 0 - t.end() - }) + await ls.exec(['notadep']) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + }, + 'should output json containing no dependencies info' + ) + t.equal( + process.exitCode, + 1, + 'should exit with error code 1' + ) + process.exitCode = 0 }) - t.test('default --depth value should now be 0', (t) => { + t.test('default --depth value should now be 0', async t => { config.all = false config.depth = undefined npm.prefix = t.testdir({ @@ -4664,31 +4374,28 @@ t.test('ls --package-lock-only', (t) => { }, }), }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - }, - chai: { - version: '1.0.0', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', }, }, - 'should output json containing only top-level dependencies' - ) - config.all = true - config.depth = Infinity - t.end() - }) + }, + 'should output json containing only top-level dependencies' + ) + config.all = true + config.depth = Infinity }) - t.test('--depth=0', (t) => { + t.test('--depth=0', async t => { config.all = false config.depth = 0 npm.prefix = t.testdir({ @@ -4717,31 +4424,28 @@ t.test('ls --package-lock-only', (t) => { }, }), }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - }, - chai: { - version: '1.0.0', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + }, + chai: { + version: '1.0.0', }, }, - 'should output json containing only top-level dependencies' - ) - config.all = true - config.depth = Infinity - t.end() - }) + }, + 'should output json containing only top-level dependencies' + ) + config.all = true + config.depth = Infinity }) - t.test('--depth=1', (t) => { + t.test('--depth=1', async t => { config.all = false config.depth = 1 npm.prefix = t.testdir({ @@ -4770,36 +4474,33 @@ t.test('ls --package-lock-only', (t) => { }, }), }) - ls.exec([], (err) => { - t.error(err, 'npm ls') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - foo: { - version: '1.0.0', - dependencies: { - dog: { - version: '1.0.0', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { + dog: { + version: '1.0.0', }, }, - chai: { - version: '1.0.0', - }, + }, + chai: { + version: '1.0.0', }, }, - 'should output json containing top-level deps and their deps only' - ) - config.all = true - config.depth = Infinity - t.end() - }) + }, + 'should output json containing top-level deps and their deps only' + ) + config.all = true + config.depth = Infinity }) - t.test('missing/invalid/extraneous', (t) => { + t.test('missing/invalid/extraneous', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -4826,46 +4527,47 @@ t.test('ls --package-lock-only', (t) => { }, }), }) - ls.exec([], (err) => { - t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems') - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - problems: [ - 'invalid: foo@1.0.0 {CWD}/tap-testdir-ls-ls---package-lock-only-ls---package-lock-only---json-missing-invalid-extraneous/node_modules/foo', - 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', - ], - dependencies: { - foo: { - version: '1.0.0', - invalid: '"^2.0.0" from the root project', - problems: [ - 'invalid: foo@1.0.0 {CWD}/tap-testdir-ls-ls---package-lock-only-ls---package-lock-only---json-missing-invalid-extraneous/node_modules/foo', - ], - dependencies: { - dog: { - version: '1.0.0', - }, + await t.rejects( + ls.exec([]), + { code: 'ELSPROBLEMS' }, + 'should list dep problems' + ) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + problems: [ + 'invalid: foo@1.0.0 {CWD}/tap-testdir-ls-ls---package-lock-only-ls---package-lock-only---json-missing-invalid-extraneous/node_modules/foo', + 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', + ], + dependencies: { + foo: { + version: '1.0.0', + invalid: '"^2.0.0" from the root project', + problems: [ + 'invalid: foo@1.0.0 {CWD}/tap-testdir-ls-ls---package-lock-only-ls---package-lock-only---json-missing-invalid-extraneous/node_modules/foo', + ], + dependencies: { + dog: { + version: '1.0.0', }, }, - ipsum: { - required: '^1.0.0', - missing: true, - problems: [ - 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', - ], - }, + }, + ipsum: { + required: '^1.0.0', + missing: true, + problems: [ + 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', + ], }, }, - 'should output json containing top-level deps and their deps only' - ) - t.end() - }) + }, + 'should output json containing top-level deps and their deps only' + ) }) - t.test('from lockfile', (t) => { + t.test('from lockfile', async t => { npm.prefix = t.testdir({ 'package-lock.json': JSON.stringify({ name: 'dedupe-lockfile', @@ -4935,36 +4637,34 @@ t.test('ls --package-lock-only', (t) => { }, }), }) - ls.exec([], () => { - t.same( - jsonParse(result), - { - version: '1.0.0', - name: 'dedupe-lockfile', - dependencies: { - '@isaacs/dedupe-tests-a': { - version: '1.0.1', - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', - dependencies: { - '@isaacs/dedupe-tests-b': { - version: '1.0.0', - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + version: '1.0.0', + name: 'dedupe-lockfile', + dependencies: { + '@isaacs/dedupe-tests-a': { + version: '1.0.1', + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', + dependencies: { + '@isaacs/dedupe-tests-b': { + version: '1.0.0', + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', }, }, - '@isaacs/dedupe-tests-b': { - version: '2.0.0', - resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', - }, + }, + '@isaacs/dedupe-tests-b': { + version: '2.0.0', + resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', }, }, - 'should output json containing only prod deps' - ) - t.end() - }) + }, + 'should output json containing only prod deps' + ) }) - t.test('using aliases', (t) => { + t.test('using aliases', async t => { npm.prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -4982,26 +4682,24 @@ t.test('ls --package-lock-only', (t) => { }, }), }) - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - a: { - version: '1.0.0', - resolved: 'https://localhost:8080/abbrev/-/abbrev-1.0.0.tgz', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + a: { + version: '1.0.0', + resolved: 'https://localhost:8080/abbrev/-/abbrev-1.0.0.tgz', }, }, - 'should output json containing aliases' - ) - t.end() - }) + }, + 'should output json containing aliases' + ) }) - t.test('resolved points to git ref', (t) => { + t.test('resolved points to git ref', async t => { config.long = false npm.prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -5025,22 +4723,20 @@ t.test('ls --package-lock-only', (t) => { } ), }) - ls.exec([], () => { - t.same( - jsonParse(result), - { - name: 'test-npm-ls', - version: '1.0.0', - dependencies: { - abbrev: { - resolved: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', - }, + await ls.exec([]) + t.same( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + abbrev: { + resolved: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', }, }, - 'should output json containing git refs' - ) - t.end() - }) + }, + 'should output json containing git refs' + ) }) t.end() diff --git a/deps/npm/test/lib/commands/org.js b/deps/npm/test/lib/commands/org.js new file mode 100644 index 00000000000000..16a432c27b5168 --- /dev/null +++ b/deps/npm/test/lib/commands/org.js @@ -0,0 +1,519 @@ +const t = require('tap') +const ansiTrim = require('../../../lib/utils/ansi-trim.js') + +const output = [] +const npm = { + flatOptions: { + json: false, + parseable: false, + silent: false, + loglevel: 'info', + }, + output: (msg) => { + output.push(msg) + }, +} + +let orgSize = 1 +let orgSetArgs = null +let orgRmArgs = null +let orgLsArgs = null +let orgList = {} +const libnpmorg = { + set: async (org, user, role, opts) => { + orgSetArgs = { org, user, role, opts } + return { + org: { + name: org, + size: orgSize, + }, + user, + role, + } + }, + rm: async (org, user, opts) => { + orgRmArgs = { org, user, opts } + }, + ls: async (org, opts) => { + orgLsArgs = { org, opts } + return orgList + }, +} + +const Org = t.mock('../../../lib/commands/org.js', { + '../../../lib/utils/otplease.js': async (opts, fn) => fn(opts), + libnpmorg, +}) +const org = new Org(npm) + +t.test('completion', async t => { + const completion = (argv) => + org.completion({ conf: { argv: { remain: argv } } }) + + const assertions = [ + [['npm', 'org'], ['set', 'rm', 'ls']], + [['npm', 'org', 'ls'], []], + [['npm', 'org', 'add'], []], + [['npm', 'org', 'rm'], []], + [['npm', 'org', 'set'], []], + ] + + for (const [argv, expected] of assertions) + t.resolveMatch(completion(argv), expected, `completion for: ${argv.join(', ')}`) + + t.rejects(completion(['npm', 'org', 'flurb']), /flurb not recognized/, 'errors for unknown subcommand') +}) + +t.test('npm org - invalid subcommand', async t => { + await t.rejects( + org.exec(['foo']), + org.usage + ) +}) + +t.test('npm org add', async t => { + t.teardown(() => { + orgSetArgs = null + output.length = 0 + }) + + await org.exec(['add', 'orgname', 'username']) + + t.strictSame(orgSetArgs, { + org: 'orgname', + user: 'username', + role: 'developer', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.equal(output[0], 'Added username as developer to orgname. You now have 1 member in this org.', 'printed the correct output') +}) + +t.test('npm org add - no org', async t => { + t.teardown(() => { + orgSetArgs = null + output.length = 0 + }) + + await t.rejects( + org.exec(['add', '', 'username']), + /`orgname` is required/, + 'returns the correct error' + ) +}) + +t.test('npm org add - no user', async t => { + t.teardown(() => { + orgSetArgs = null + output.length = 0 + }) + + await t.rejects( + org.exec(['add', 'orgname', '']), + /`username` is required/, + 'returns the correct error' + ) +}) + +t.test('npm org add - invalid role', async t => { + t.teardown(() => { + orgSetArgs = null + output.length = 0 + }) + + await t.rejects( + org.exec(['add', 'orgname', 'username', 'person']), + /`role` must be one of/, + 'returns the correct error' + ) +}) + +t.test('npm org add - more users', async t => { + orgSize = 5 + t.teardown(() => { + orgSize = 1 + orgSetArgs = null + output.length = 0 + }) + + await org.exec(['add', 'orgname', 'username']) + t.strictSame(orgSetArgs, { + org: 'orgname', + user: 'username', + role: 'developer', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.equal(output[0], 'Added username as developer to orgname. You now have 5 members in this org.', 'printed the correct output') +}) + +t.test('npm org add - json output', async t => { + npm.flatOptions.json = true + t.teardown(() => { + npm.flatOptions.json = false + orgSetArgs = null + output.length = 0 + }) + + await org.exec(['add', 'orgname', 'username']) + + t.strictSame(orgSetArgs, { + org: 'orgname', + user: 'username', + role: 'developer', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.strictSame(JSON.parse(output[0]), { + org: { + name: 'orgname', + size: 1, + }, + user: 'username', + role: 'developer', + }, 'printed the correct output') +}) + +t.test('npm org add - parseable output', async t => { + npm.flatOptions.parseable = true + t.teardown(() => { + npm.flatOptions.parseable = false + orgSetArgs = null + output.length = 0 + }) + + await org.exec(['add', 'orgname', 'username']) + + t.strictSame(orgSetArgs, { + org: 'orgname', + user: 'username', + role: 'developer', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.strictSame(output.map(line => line.split(/\t/)), [ + ['org', 'orgsize', 'user', 'role'], + ['orgname', '1', 'username', 'developer'], + ], 'printed the correct output') +}) + +t.test('npm org add - silent output', async t => { + npm.flatOptions.silent = true + t.teardown(() => { + npm.flatOptions.silent = false + orgSetArgs = null + output.length = 0 + }) + + await org.exec(['add', 'orgname', 'username']) + + t.strictSame(orgSetArgs, { + org: 'orgname', + user: 'username', + role: 'developer', + opts: npm.flatOptions, + }, 'received the correct arguments') + t.strictSame(output, [], 'prints no output') +}) + +t.test('npm org rm', async t => { + t.teardown(() => { + orgRmArgs = null + orgLsArgs = null + output.length = 0 + }) + + await org.exec(['rm', 'orgname', 'username']) + + t.strictSame(orgRmArgs, { + org: 'orgname', + user: 'username', + opts: npm.flatOptions, + }, 'libnpmorg.rm received the correct args') + t.strictSame(orgLsArgs, { + org: 'orgname', + opts: npm.flatOptions, + }, 'libnpmorg.ls received the correct args') + t.equal(output[0], 'Successfully removed username from orgname. You now have 0 members in this org.', 'printed the correct output') +}) + +t.test('npm org rm - no org', async t => { + t.teardown(() => { + orgRmArgs = null + orgLsArgs = null + output.length = 0 + }) + + await t.rejects( + org.exec(['rm', '', 'username']), + /`orgname` is required/, + 'threw the correct error' + ) +}) + +t.test('npm org rm - no user', async t => { + t.teardown(() => { + orgRmArgs = null + orgLsArgs = null + output.length = 0 + }) + + await t.rejects( + org.exec(['rm', 'orgname']), + /`username` is required/, + 'threw the correct error' + ) +}) + +t.test('npm org rm - one user left', async t => { + orgList = { + one: 'developer', + } + + t.teardown(() => { + orgList = {} + orgRmArgs = null + orgLsArgs = null + output.length = 0 + }) + + await org.exec(['rm', 'orgname', 'username']) + + t.strictSame(orgRmArgs, { + org: 'orgname', + user: 'username', + opts: npm.flatOptions, + }, 'libnpmorg.rm received the correct args') + t.strictSame(orgLsArgs, { + org: 'orgname', + opts: npm.flatOptions, + }, 'libnpmorg.ls received the correct args') + t.equal(output[0], 'Successfully removed username from orgname. You now have 1 member in this org.', 'printed the correct output') +}) + +t.test('npm org rm - json output', async t => { + npm.flatOptions.json = true + t.teardown(() => { + npm.flatOptions.json = false + orgRmArgs = null + orgLsArgs = null + output.length = 0 + }) + + await org.exec(['rm', 'orgname', 'username']) + + t.strictSame(orgRmArgs, { + org: 'orgname', + user: 'username', + opts: npm.flatOptions, + }, 'libnpmorg.rm received the correct args') + t.strictSame(orgLsArgs, { + org: 'orgname', + opts: npm.flatOptions, + }, 'libnpmorg.ls received the correct args') + t.strictSame(JSON.parse(output[0]), { + user: 'username', + org: 'orgname', + userCount: 0, + deleted: true, + }, 'printed the correct output') +}) + +t.test('npm org rm - parseable output', async t => { + npm.flatOptions.parseable = true + t.teardown(() => { + npm.flatOptions.parseable = false + orgRmArgs = null + orgLsArgs = null + output.length = 0 + }) + + await org.exec(['rm', 'orgname', 'username']) + + t.strictSame(orgRmArgs, { + org: 'orgname', + user: 'username', + opts: npm.flatOptions, + }, 'libnpmorg.rm received the correct args') + t.strictSame(orgLsArgs, { + org: 'orgname', + opts: npm.flatOptions, + }, 'libnpmorg.ls received the correct args') + t.strictSame(output.map(line => line.split(/\t/)), [ + ['user', 'org', 'userCount', 'deleted'], + ['username', 'orgname', '0', 'true'], + ], 'printed the correct output') +}) + +t.test('npm org rm - silent output', async t => { + npm.flatOptions.silent = true + t.teardown(() => { + npm.flatOptions.silent = false + orgRmArgs = null + orgLsArgs = null + output.length = 0 + }) + + await org.exec(['rm', 'orgname', 'username']) + + t.strictSame(orgRmArgs, { + org: 'orgname', + user: 'username', + opts: npm.flatOptions, + }, 'libnpmorg.rm received the correct args') + t.strictSame(orgLsArgs, { + org: 'orgname', + opts: npm.flatOptions, + }, 'libnpmorg.ls received the correct args') + t.strictSame(output, [], 'printed no output') +}) + +t.test('npm org ls', async t => { + orgList = { + one: 'developer', + two: 'admin', + three: 'owner', + } + t.teardown(() => { + orgList = {} + orgLsArgs = null + output.length = 0 + }) + + await org.exec(['ls', 'orgname']) + + t.strictSame(orgLsArgs, { + org: 'orgname', + opts: npm.flatOptions, + }, 'receieved the correct args') + const out = ansiTrim(output[0]) + t.match(out, /one.*developer/, 'contains the developer member') + t.match(out, /two.*admin/, 'contains the admin member') + t.match(out, /three.*owner/, 'contains the owner member') +}) + +t.test('npm org ls - user filter', async t => { + orgList = { + username: 'admin', + missing: 'admin', + } + t.teardown(() => { + orgList = {} + orgLsArgs = null + output.length = 0 + }) + + await org.exec(['ls', 'orgname', 'username']) + + t.strictSame(orgLsArgs, { + org: 'orgname', + opts: npm.flatOptions, + }, 'receieved the correct args') + const out = ansiTrim(output[0]) + t.match(out, /username.*admin/, 'contains the filtered member') + t.notMatch(out, /missing.*admin/, 'does not contain other members') +}) + +t.test('npm org ls - user filter, missing user', async t => { + orgList = { + missing: 'admin', + } + t.teardown(() => { + orgList = {} + orgLsArgs = null + output.length = 0 + }) + + await org.exec(['ls', 'orgname', 'username']) + + t.strictSame(orgLsArgs, { + org: 'orgname', + opts: npm.flatOptions, + }, 'receieved the correct args') + const out = ansiTrim(output[0]) + t.notMatch(out, /username/, 'does not contain the requested member') + t.notMatch(out, /missing.*admin/, 'does not contain other members') +}) + +t.test('npm org ls - no org', async t => { + t.teardown(() => { + orgLsArgs = null + output.length = 0 + }) + + await t.rejects( + org.exec(['ls']), + /`orgname` is required/, + 'throws the correct error' + ) +}) + +t.test('npm org ls - json output', async t => { + npm.flatOptions.json = true + orgList = { + one: 'developer', + two: 'admin', + three: 'owner', + } + t.teardown(() => { + npm.flatOptions.json = false + orgList = {} + orgLsArgs = null + output.length = 0 + }) + + await org.exec(['ls', 'orgname']) + + t.strictSame(orgLsArgs, { + org: 'orgname', + opts: npm.flatOptions, + }, 'receieved the correct args') + t.strictSame(JSON.parse(output[0]), orgList, 'prints the correct output') +}) + +t.test('npm org ls - parseable output', async t => { + npm.flatOptions.parseable = true + orgList = { + one: 'developer', + two: 'admin', + three: 'owner', + } + t.teardown(() => { + npm.flatOptions.parseable = false + orgList = {} + orgLsArgs = null + output.length = 0 + }) + + await org.exec(['ls', 'orgname']) + + t.strictSame(orgLsArgs, { + org: 'orgname', + opts: npm.flatOptions, + }, 'receieved the correct args') + t.strictSame(output.map(line => line.split(/\t/)), [ + ['user', 'role'], + ['one', 'developer'], + ['two', 'admin'], + ['three', 'owner'], + ], 'printed the correct output') +}) + +t.test('npm org ls - silent output', async t => { + npm.flatOptions.silent = true + orgList = { + one: 'developer', + two: 'admin', + three: 'owner', + } + t.teardown(() => { + npm.flatOptions.silent = false + orgList = {} + orgLsArgs = null + output.length = 0 + }) + + await org.exec(['ls', 'orgname']) + + t.strictSame(orgLsArgs, { + org: 'orgname', + opts: npm.flatOptions, + }, 'receieved the correct args') + t.strictSame(output, [], 'printed no output') +}) diff --git a/deps/npm/test/lib/outdated.js b/deps/npm/test/lib/commands/outdated.js similarity index 55% rename from deps/npm/test/lib/outdated.js rename to deps/npm/test/lib/commands/outdated.js index acd5c25e89969f..1841ea9b17c853 100644 --- a/deps/npm/test/lib/outdated.js +++ b/deps/npm/test/lib/commands/outdated.js @@ -1,5 +1,5 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') const packument = spec => { const mocks = { @@ -89,7 +89,7 @@ const flatOptions = { const outdated = (dir, opts) => { logs = '' - const Outdated = t.mock('../../lib/outdated.js', { + const Outdated = t.mock('../../../lib/commands/outdated.js', { pacote: { packument, }, @@ -180,166 +180,142 @@ t.test('should display outdated deps', t => { }, }) - t.test('outdated global', t => { - outdated(null, { + t.test('outdated global', async t => { + await outdated(null, { config: { global: true }, - }).exec([], () => { - t.equal(process.exitCode, 1) - t.matchSnapshot(logs) - t.end() - }) + }).exec([]) + t.equal(process.exitCode, 1) + t.matchSnapshot(logs) }) - t.test('outdated', t => { - outdated(testDir, { + t.test('outdated', async t => { + await outdated(testDir, { config: { global: false, }, color: true, - }).exec([], () => { - t.equal(process.exitCode, 1) - t.matchSnapshot(logs) - t.end() - }) + }).exec([]) + t.equal(process.exitCode, 1) + t.matchSnapshot(logs) }) - t.test('outdated --omit=dev', t => { - outdated(testDir, { + t.test('outdated --omit=dev', async t => { + await outdated(testDir, { config: { global: false, omit: ['dev'], }, color: true, - }).exec([], () => { - t.equal(process.exitCode, 1) - t.matchSnapshot(logs) - t.end() - }) + }).exec([]) + t.equal(process.exitCode, 1) + t.matchSnapshot(logs) }) - t.test('outdated --omit=dev --omit=peer', t => { - outdated(testDir, { + t.test('outdated --omit=dev --omit=peer', async t => { + await outdated(testDir, { config: { global: false, omit: ['dev', 'peer'], }, color: true, - }).exec([], () => { - t.equal(process.exitCode, 1) - t.matchSnapshot(logs) - t.end() - }) + }).exec([]) + t.equal(process.exitCode, 1) + t.matchSnapshot(logs) }) - t.test('outdated --omit=prod', t => { - outdated(testDir, { + t.test('outdated --omit=prod', async t => { + await outdated(testDir, { config: { global: false, omit: ['prod'], }, color: true, - }).exec([], () => { - t.equal(process.exitCode, 1) - t.matchSnapshot(logs) - t.end() - }) + }).exec([]) + t.equal(process.exitCode, 1) + t.matchSnapshot(logs) }) - t.test('outdated --long', t => { - outdated(testDir, { + t.test('outdated --long', async t => { + await outdated(testDir, { config: { global: false, long: true, }, - }).exec([], () => { - t.equal(process.exitCode, 1) - t.matchSnapshot(logs) - t.end() - }) + }).exec([]) + t.equal(process.exitCode, 1) + t.matchSnapshot(logs) }) - t.test('outdated --json', t => { - outdated(testDir, { + t.test('outdated --json', async t => { + await outdated(testDir, { config: { global: false, json: true, }, - }).exec([], () => { - t.equal(process.exitCode, 1) - t.matchSnapshot(logs) - t.end() - }) + }).exec([]) + t.equal(process.exitCode, 1) + t.matchSnapshot(logs) }) - t.test('outdated --json --long', t => { - outdated(testDir, { + t.test('outdated --json --long', async t => { + await outdated(testDir, { config: { global: false, json: true, long: true, }, - }).exec([], () => { - t.equal(process.exitCode, 1) - t.matchSnapshot(logs) - t.end() - }) + }).exec([]) + t.equal(process.exitCode, 1) + t.matchSnapshot(logs) }) - t.test('outdated --parseable', t => { - outdated(testDir, { + t.test('outdated --parseable', async t => { + await outdated(testDir, { config: { global: false, parseable: true, }, - }).exec([], () => { - t.equal(process.exitCode, 1) - t.matchSnapshot(logs) - t.end() - }) + }).exec([]) + t.equal(process.exitCode, 1) + t.matchSnapshot(logs) }) - t.test('outdated --parseable --long', t => { - outdated(testDir, { + t.test('outdated --parseable --long', async t => { + await outdated(testDir, { config: { global: false, parseable: true, long: true, }, - }).exec([], () => { - t.equal(process.exitCode, 1) - t.matchSnapshot(logs) - t.end() - }) + }).exec([]) + t.equal(process.exitCode, 1) + t.matchSnapshot(logs) }) - t.test('outdated --all', t => { - outdated(testDir, { + t.test('outdated --all', async t => { + await outdated(testDir, { config: { all: true, }, - }).exec([], () => { - t.equal(process.exitCode, 1) - t.matchSnapshot(logs) - t.end() - }) + }).exec([]) + t.equal(process.exitCode, 1) + t.matchSnapshot(logs) }) - t.test('outdated specific dep', t => { - outdated(testDir, { + t.test('outdated specific dep', async t => { + await outdated(testDir, { config: { global: false, }, - }).exec(['cat'], () => { - t.equal(process.exitCode, 1) - t.matchSnapshot(logs) - t.end() - }) + }).exec(['cat']) + t.equal(process.exitCode, 1) + t.matchSnapshot(logs) }) t.end() }) -t.test('should return if no outdated deps', t => { +t.test('should return if no outdated deps', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'delta', @@ -358,15 +334,13 @@ t.test('should return if no outdated deps', t => { }, }) - outdated(testDir, { + await outdated(testDir, { global: false, - }).exec([], () => { - t.equal(logs.length, 0, 'no logs') - t.end() - }) + }).exec([]) + t.equal(logs.length, 0, 'no logs') }) -t.test('throws if error with a dep', t => { +t.test('throws if error with a dep', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'delta', @@ -385,15 +359,15 @@ t.test('throws if error with a dep', t => { }, }) - outdated(testDir, { - global: false, - }).exec([], (err) => { - t.equal(err.message, 'There is an error with this package.') - t.end() - }) + await t.rejects( + outdated(testDir, { + global: false, + }).exec([]), + 'There is an error with this package.' + ) }) -t.test('should skip missing non-prod deps', t => { +t.test('should skip missing non-prod deps', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'delta', @@ -405,15 +379,13 @@ t.test('should skip missing non-prod deps', t => { node_modules: {}, }) - outdated(testDir, { + await outdated(testDir, { global: false, - }).exec([], () => { - t.equal(logs.length, 0, 'no logs') - t.end() - }) + }).exec([]) + t.equal(logs.length, 0, 'no logs') }) -t.test('should skip invalid pkg ranges', t => { +t.test('should skip invalid pkg ranges', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'delta', @@ -432,13 +404,11 @@ t.test('should skip invalid pkg ranges', t => { }, }) - outdated(testDir, {}).exec([], () => { - t.equal(logs.length, 0, 'no logs') - t.end() - }) + await outdated(testDir, {}).exec([]) + t.equal(logs.length, 0, 'no logs') }) -t.test('should skip git specs', t => { +t.test('should skip git specs', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'delta', @@ -457,10 +427,8 @@ t.test('should skip git specs', t => { }, }) - outdated(testDir, {}).exec([], () => { - t.equal(logs.length, 0, 'no logs') - t.end() - }) + await outdated(testDir, {}).exec([]) + t.equal(logs.length, 0, 'no logs') }) t.test('workspaces', async t => { @@ -555,167 +523,88 @@ t.test('workspaces', async t => { }, }) - await new Promise((res, rej) => { - outdated(testDir, {}).exec([], err => { - if (err) - rej(err) - - t.matchSnapshot(logs, 'should display ws outdated deps human output') - t.equal(process.exitCode, 1) - res() - }) - }) - - await new Promise((res, rej) => { - flatOptions.workspacesEnabled = false - outdated(testDir, {}).exec([], err => { - if (err) - rej(err) - - // TODO: This should display dog, but doesn't because arborist filters - // workspace deps even if they're also root deps - // This will be fixed in a future arborist version - t.matchSnapshot(logs, 'should display only root outdated when ws disabled') - flatOptions.workspacesEnabled = true - res() - }) - }) - - await new Promise((res, rej) => { - outdated(testDir, { - config: { - json: true, - }, - }).exec([], err => { - if (err) - rej(err) - - t.matchSnapshot(logs, 'should display ws outdated deps json output') - t.equal(process.exitCode, 1) - res() - }) - }) + await outdated(testDir, {}).exec([]) - await new Promise((res, rej) => { - outdated(testDir, { - config: { - parseable: true, - }, - }).exec([], err => { - if (err) - rej(err) + t.matchSnapshot(logs, 'should display ws outdated deps human output') + t.equal(process.exitCode, 1) - t.matchSnapshot(logs, 'should display ws outdated deps parseable output') - t.equal(process.exitCode, 1) - res() - }) - }) + flatOptions.workspacesEnabled = false + await outdated(testDir, {}).exec([]) - await new Promise((res, rej) => { - outdated(testDir, { - config: { - all: true, - }, - }).exec([], err => { - if (err) - rej(err) + // TODO: This should display dog, but doesn't because arborist filters + // workspace deps even if they're also root deps + // This will be fixed in a future arborist version + t.matchSnapshot(logs, 'should display only root outdated when ws disabled') + flatOptions.workspacesEnabled = true - t.matchSnapshot(logs, 'should display all dependencies') - t.equal(process.exitCode, 1) - res() - }) - }) + await outdated(testDir, { + config: { + json: true, + }, + }).exec([]) + t.matchSnapshot(logs, 'should display ws outdated deps json output') + t.equal(process.exitCode, 1) - await new Promise((res, rej) => { - outdated(testDir, { - color: true, - }).exec([], err => { - if (err) - rej(err) - - t.matchSnapshot(logs, 'should highlight ws in dependend by section') - t.equal(process.exitCode, 1) - res() - }) - }) + await outdated(testDir, { + config: { + parseable: true, + }, + }).exec([]) - await new Promise((res, rej) => { - outdated(testDir, {}).execWorkspaces([], ['a'], err => { - if (err) - rej(err) + t.matchSnapshot(logs, 'should display ws outdated deps parseable output') + t.equal(process.exitCode, 1) - t.matchSnapshot(logs, 'should display results filtered by ws') - t.equal(process.exitCode, 1) - res() - }) - }) + await outdated(testDir, { + config: { + all: true, + }, + }).exec([]) - await new Promise((res, rej) => { - outdated(testDir, { - config: { - json: true, - }, - }).execWorkspaces([], ['a'], err => { - if (err) - rej(err) + t.matchSnapshot(logs, 'should display all dependencies') + t.equal(process.exitCode, 1) - t.matchSnapshot(logs, 'should display json results filtered by ws') - t.equal(process.exitCode, 1) - res() - }) - }) + await outdated(testDir, { + color: true, + }).exec([]) - await new Promise((res, rej) => { - outdated(testDir, { - config: { - parseable: true, - }, - }).execWorkspaces([], ['a'], err => { - if (err) - rej(err) + t.matchSnapshot(logs, 'should highlight ws in dependend by section') + t.equal(process.exitCode, 1) - t.matchSnapshot(logs, 'should display parseable results filtered by ws') - t.equal(process.exitCode, 1) - res() - }) - }) + await outdated(testDir, {}).execWorkspaces([], ['a']) + t.matchSnapshot(logs, 'should display results filtered by ws') + t.equal(process.exitCode, 1) - await new Promise((res, rej) => { - outdated(testDir, { - config: { - all: true, - }, - }).execWorkspaces([], ['a'], err => { - if (err) - rej(err) + await outdated(testDir, { + config: { + json: true, + }, + }).execWorkspaces([], ['a']) + t.matchSnapshot(logs, 'should display json results filtered by ws') + t.equal(process.exitCode, 1) - t.matchSnapshot(logs, - 'should display nested deps when filtering by ws and using --all') - t.equal(process.exitCode, 1) - res() - }) - }) + await outdated(testDir, { + config: { + parseable: true, + }, + }).execWorkspaces([], ['a']) + t.matchSnapshot(logs, 'should display parseable results filtered by ws') + t.equal(process.exitCode, 1) - await new Promise((res, rej) => { - outdated(testDir, {}).execWorkspaces([], ['b'], err => { - if (err) - rej(err) + await outdated(testDir, { + config: { + all: true, + }, + }).execWorkspaces([], ['a']) - t.matchSnapshot(logs, - 'should display no results if ws has no deps to display') - res() - }) - }) + t.matchSnapshot(logs, + 'should display nested deps when filtering by ws and using --all') + t.equal(process.exitCode, 1) - await new Promise((res, rej) => { - outdated(testDir, {}).execWorkspaces([], ['c'], err => { - if (err) - rej(err) + await outdated(testDir, {}).execWorkspaces([], ['b']) + t.matchSnapshot(logs, + 'should display no results if ws has no deps to display') - t.matchSnapshot(logs, - 'should display missing deps when filtering by ws') - t.equal(process.exitCode, 1) - res() - }) - }) + await outdated(testDir, {}).execWorkspaces([], ['c']) + t.matchSnapshot(logs, + 'should display missing deps when filtering by ws') }) diff --git a/deps/npm/test/lib/owner.js b/deps/npm/test/lib/commands/owner.js similarity index 72% rename from deps/npm/test/lib/owner.js rename to deps/npm/test/lib/commands/owner.js index 32944a84edbc40..c9d936d47becea 100644 --- a/deps/npm/test/lib/owner.js +++ b/deps/npm/test/lib/commands/owner.js @@ -1,5 +1,5 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm.js') +const { fake: mockNpm } = require('../../fixtures/mock-npm.js') let result = '' let readPackageNamePrefix = null @@ -21,12 +21,12 @@ const mocks = { npmlog, 'npm-registry-fetch': npmFetch, pacote, - '../../lib/utils/otplease.js': async (opts, fn) => fn({ otp: '123456', opts }), - '../../lib/utils/read-package-name.js': async (prefix) => { + '../../../lib/utils/otplease.js': async (opts, fn) => fn({ otp: '123456', opts }), + '../../../lib/utils/read-package-name.js': async (prefix) => { readPackageNamePrefix = prefix return readPackageNameResponse }, - '../../lib/utils/usage.js': () => 'usage instructions', + '../../../lib/utils/usage.js': () => 'usage instructions', } const npmcliMaintainers = [ @@ -36,23 +36,22 @@ const npmcliMaintainers = [ { email: 'i@izs.me', name: 'isaacs' }, ] -const Owner = t.mock('../../lib/owner.js', mocks) +const Owner = t.mock('../../../lib/commands/owner.js', mocks) const owner = new Owner(npm) -t.test('owner no args', t => { +t.test('owner no args', async t => { result = '' t.teardown(() => { result = '' }) - owner.exec([], err => { - t.match(err, /usage instructions/, 'should not error out on empty locations') - t.end() - }) + await t.rejects( + owner.exec([]), + owner.usage) }) -t.test('owner ls no args', t => { - t.plan(5) +t.test('owner ls no args', async t => { + t.plan(4) result = '' @@ -77,39 +76,37 @@ t.test('owner ls no args', t => { }) npm.prefix = 'test-npm-prefix' - owner.exec(['ls'], err => { - t.error(err, 'npm owner ls no args') - t.matchSnapshot(result, 'should output owners of cwd package') - t.equal(readPackageNamePrefix, 'test-npm-prefix', 'read-package-name gets npm.prefix') - }) + await owner.exec(['ls']) + t.matchSnapshot(result, 'should output owners of cwd package') + t.equal(readPackageNamePrefix, 'test-npm-prefix', 'read-package-name gets npm.prefix') }) -t.test('owner ls global', t => { +t.test('owner ls global', async t => { t.teardown(() => { npm.config.set('global', false) }) npm.config.set('global', true) - owner.exec(['ls'], err => { - t.match(err, /usage instructions/, 'should throw usage instructions if no cwd package available') - t.end() - }) + await t.rejects( + owner.exec(['ls']), + owner.usage + ) }) -t.test('owner ls no args no cwd package', t => { +t.test('owner ls no args no cwd package', async t => { result = '' t.teardown(() => { result = '' npmlog.error = noop }) - owner.exec(['ls'], err => { - t.match(err, /usage instructions/, 'should throw usage instructions if no cwd package available') - t.end() - }) + await t.rejects( + owner.exec(['ls']), + owner.usage + ) }) -t.test('owner ls fails to retrieve packument', t => { +t.test('owner ls fails to retrieve packument', async t => { t.plan(4) result = '' @@ -128,17 +125,15 @@ t.test('owner ls fails to retrieve packument', t => { pacote.packument = noop }) - owner.exec(['ls'], err => { - t.match( - err, - /ERR/, - 'should throw unknown error' - ) - }) + await t.rejects( + owner.exec(['ls']), + /ERR/, + 'should throw unknown error' + ) }) -t.test('owner ls ', t => { - t.plan(4) +t.test('owner ls ', async t => { + t.plan(3) result = '' pacote.packument = async (spec, opts) => { @@ -158,13 +153,11 @@ t.test('owner ls ', t => { pacote.packument = noop }) - owner.exec(['ls', '@npmcli/map-workspaces'], err => { - t.error(err, 'npm owner ls ') - t.matchSnapshot(result, 'should output owners of ') - }) + await owner.exec(['ls', '@npmcli/map-workspaces']) + t.matchSnapshot(result, 'should output owners of ') }) -t.test('owner ls no maintainers', t => { +t.test('owner ls no maintainers', async t => { result = '' pacote.packument = async (spec, opts) => { return { maintainers: [] } @@ -174,15 +167,12 @@ t.test('owner ls no maintainers', t => { pacote.packument = noop }) - owner.exec(['ls', '@npmcli/map-workspaces'], err => { - t.error(err, 'npm owner ls no maintainers') - t.equal(result, 'no admin found', 'should output no admint found msg') - t.end() - }) + await owner.exec(['ls', '@npmcli/map-workspaces']) + t.equal(result, 'no admin found', 'should output no admint found msg') }) -t.test('owner add ', t => { - t.plan(9) +t.test('owner add ', async t => { + t.plan(8) result = '' npmFetch.json = async (uri, opts) => { @@ -245,13 +235,11 @@ t.test('owner add ', t => { pacote.packument = noop }) - owner.exec(['add', 'foo', '@npmcli/map-workspaces'], err => { - t.error(err, 'npm owner add ') - t.equal(result, '+ foo (@npmcli/map-workspaces)', 'should output add result') - }) + await owner.exec(['add', 'foo', '@npmcli/map-workspaces']) + t.equal(result, '+ foo (@npmcli/map-workspaces)', 'should output add result') }) -t.test('owner add cwd package', t => { +t.test('owner add cwd package', async t => { result = '' readPackageNameResponse = '@npmcli/map-workspaces' npmFetch.json = async (uri, opts) => { @@ -278,15 +266,12 @@ t.test('owner add cwd package', t => { pacote.packument = noop }) - owner.exec(['add', 'foo'], err => { - t.error(err, 'npm owner add cwd package') - t.equal(result, '+ foo (@npmcli/map-workspaces)', 'should output add result') - t.end() - }) + await owner.exec(['add', 'foo']) + t.equal(result, '+ foo (@npmcli/map-workspaces)', 'should output add result') }) -t.test('owner add already an owner', t => { - t.plan(3) +t.test('owner add already an owner', async t => { + t.plan(2) result = '' npmlog.info = (title, msg) => { @@ -321,12 +306,10 @@ t.test('owner add already an owner', t => { pacote.packument = noop }) - owner.exec(['add', 'ruyadorno', '@npmcli/map-workspaces'], err => { - t.error(err, 'npm owner add already an owner') - }) + await owner.exec(['add', 'ruyadorno', '@npmcli/map-workspaces']) }) -t.test('owner add fails to retrieve user', t => { +t.test('owner add fails to retrieve user', async t => { result = '' readPackageNameResponse = npmFetch.json = async (uri, opts) => { @@ -349,18 +332,14 @@ t.test('owner add fails to retrieve user', t => { pacote.packument = noop }) - owner.exec(['add', 'foo', '@npmcli/map-workspaces'], err => { - t.match( - err, - /Error: Couldn't get user data for foo: {"ok":false}/, - 'should throw user data error' - ) - t.equal(err.code, 'EOWNERUSER', 'should have expected error code') - t.end() - }) + await t.rejects( + owner.exec(['add', 'foo', '@npmcli/map-workspaces']), + { code: 'EOWNERUSER', message: /Couldn't get user data for foo: {"ok":false}/ }, + 'should throw user data error' + ) }) -t.test('owner add fails to PUT updates', t => { +t.test('owner add fails to PUT updates', async t => { result = '' npmFetch.json = async (uri, opts) => { // retrieve user info from couchdb request @@ -390,18 +369,14 @@ t.test('owner add fails to PUT updates', t => { pacote.packument = noop }) - owner.exec(['add', 'foo', '@npmcli/map-workspaces'], err => { - t.match( - err.message, - /Failed to update package/, - 'should throw failed to update package error' - ) - t.equal(err.code, 'EOWNERMUTATE', 'should have expected error code') - t.end() - }) + await t.rejects( + owner.exec(['add', 'foo', '@npmcli/map-workspaces']), + { code: 'EOWNERMUTATE', message: /Failed to update package/ }, + 'should throw failed to update package error' + ) }) -t.test('owner add fails to retrieve user info', t => { +t.test('owner add fails to retrieve user info', async t => { t.plan(3) result = '' @@ -430,16 +405,14 @@ t.test('owner add fails to retrieve user info', t => { pacote.packument = noop }) - owner.exec(['add', 'foo', '@npmcli/map-workspaces'], err => { - t.match( - err.message, - "I'm a teapot", - 'should throw server error response' - ) - }) + await t.rejects( + owner.exec(['add', 'foo', '@npmcli/map-workspaces']), + "I'm a teapot", + 'should throw server error response' + ) }) -t.test('owner add no previous maintainers property from server', t => { +t.test('owner add no previous maintainers property from server', async t => { result = '' npmFetch.json = async (uri, opts) => { // retrieve user info from couchdb request @@ -466,51 +439,48 @@ t.test('owner add no previous maintainers property from server', t pacote.packument = noop }) - owner.exec(['add', 'foo', '@npmcli/no-owners-pkg'], err => { - t.error(err, 'npm owner add ') - t.equal(result, '+ foo (@npmcli/no-owners-pkg)', 'should output add result') - t.end() - }) + await owner.exec(['add', 'foo', '@npmcli/no-owners-pkg']) + t.equal(result, '+ foo (@npmcli/no-owners-pkg)', 'should output add result') }) -t.test('owner add no user', t => { +t.test('owner add no user', async t => { result = '' t.teardown(() => { result = '' }) - owner.exec(['add'], err => { - t.match(err, /usage instructions/, 'should throw usage instructions if user provided') - t.end() - }) + await t.rejects( + owner.exec(['add']), + owner.usage + ) }) -t.test('owner add no pkg global', t => { +t.test('owner add no pkg global', async t => { t.teardown(() => { npm.config.set('global', false) }) npm.config.set('global', true) - owner.exec(['add', 'gar'], err => { - t.match(err, /usage instructions/, 'should throw usage instructions if user provided') - t.end() - }) + await t.rejects( + owner.exec(['add', 'gar']), + owner.usage + ) }) -t.test('owner add no cwd package', t => { +t.test('owner add no cwd package', async t => { result = '' t.teardown(() => { result = '' }) - owner.exec(['add', 'foo'], err => { - t.match(err, /usage instructions/, 'should throw usage instructions if no user provided') - t.end() - }) + await t.rejects( + owner.exec(['add', 'foo']), + owner.usage + ) }) -t.test('owner rm ', t => { - t.plan(9) +t.test('owner rm ', async t => { + t.plan(8) result = '' npmFetch.json = async (uri, opts) => { @@ -566,14 +536,12 @@ t.test('owner rm ', t => { pacote.packument = noop }) - owner.exec(['rm', 'ruyadorno', '@npmcli/map-workspaces'], err => { - t.error(err, 'npm owner rm ') - t.equal(result, '- ruyadorno (@npmcli/map-workspaces)', 'should output rm result') - }) + await owner.exec(['rm', 'ruyadorno', '@npmcli/map-workspaces']) + t.equal(result, '- ruyadorno (@npmcli/map-workspaces)', 'should output rm result') }) -t.test('owner rm not a current owner', t => { - t.plan(3) +t.test('owner rm not a current owner', async t => { + t.plan(2) result = '' npmlog.info = (title, msg) => { @@ -606,12 +574,10 @@ t.test('owner rm not a current owner', t => { pacote.packument = noop }) - owner.exec(['rm', 'foo', '@npmcli/map-workspaces'], err => { - t.error(err, 'npm owner rm not a current owner') - }) + await owner.exec(['rm', 'foo', '@npmcli/map-workspaces']) }) -t.test('owner rm cwd package', t => { +t.test('owner rm cwd package', async t => { result = '' readPackageNameResponse = '@npmcli/map-workspaces' npmFetch.json = async (uri, opts) => { @@ -638,14 +604,11 @@ t.test('owner rm cwd package', t => { pacote.packument = noop }) - owner.exec(['rm', 'ruyadorno'], err => { - t.error(err, 'npm owner rm cwd package') - t.equal(result, '- ruyadorno (@npmcli/map-workspaces)', 'should output rm result') - t.end() - }) + await owner.exec(['rm', 'ruyadorno']) + t.equal(result, '- ruyadorno (@npmcli/map-workspaces)', 'should output rm result') }) -t.test('owner rm only user', t => { +t.test('owner rm only user', async t => { result = '' readPackageNameResponse = 'ipt' npmFetch.json = async (uri, opts) => { @@ -673,51 +636,47 @@ t.test('owner rm only user', t => { pacote.packument = noop }) - owner.exec(['rm', 'ruyadorno'], err => { - t.equal( - err.message, - 'Cannot remove all owners of a package. Add someone else first.', - 'should throw unable to remove unique owner message' - ) - t.equal(err.code, 'EOWNERRM', 'should have expected error code') - t.end() - }) + await t.rejects( + owner.exec(['rm', 'ruyadorno']), + { code: 'EOWNERRM', message: 'Cannot remove all owners of a package. Add someone else first.' }, + 'should throw unable to remove unique owner message' + ) }) -t.test('owner rm no user', t => { +t.test('owner rm no user', async t => { result = '' t.teardown(() => { result = '' }) - owner.exec(['rm'], err => { - t.match(err, /usage instructions/, 'should throw usage instructions if no user provided to rm') - t.end() - }) + await t.rejects( + owner.exec(['rm']), + owner.usage + ) }) -t.test('owner rm no pkg global', t => { +t.test('owner rm no pkg global', async t => { t.teardown(() => { npm.config.set('global', false) }) npm.config.set('global', true) - owner.exec(['rm', 'gar'], err => { - t.match(err, /usage instructions/, 'should throw usage instructions if user provided') - t.end() - }) + await t.rejects( + owner.exec(['rm', 'foo']), + owner.usage + ) }) -t.test('owner rm no cwd package', t => { +t.test('owner rm no cwd package', async t => { result = '' t.teardown(() => { result = '' }) - owner.exec(['rm', 'foo'], err => { - t.match(err, /usage instructions/, 'should throw usage instructions if no user provided to rm') - t.end() - }) + await t.rejects( + owner.exec(['rm', 'foo']), + owner.usage + ) }) t.test('completion', async t => { diff --git a/deps/npm/test/lib/pack.js b/deps/npm/test/lib/commands/pack.js similarity index 61% rename from deps/npm/test/lib/pack.js rename to deps/npm/test/lib/commands/pack.js index 3d61abdaf74ca5..6a5749623c4372 100644 --- a/deps/npm/test/lib/pack.js +++ b/deps/npm/test/lib/commands/pack.js @@ -1,5 +1,5 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') const pacote = require('pacote') const path = require('path') @@ -27,9 +27,9 @@ const mockPacote = { t.afterEach(() => OUTPUT.length = 0) -t.test('should pack current directory with no arguments', (t) => { +t.test('should pack current directory with no arguments', async t => { let tarballFileName - const Pack = t.mock('../../lib/pack.js', { + const Pack = t.mock('../../../lib/commands/pack.js', { libnpmpack, npmlog: { notice: () => {}, @@ -48,19 +48,15 @@ t.test('should pack current directory with no arguments', (t) => { }) const pack = new Pack(npm) - pack.exec([], err => { - t.error(err, { bail: true }) - - const filename = `npm-${require('../../package.json').version}.tgz` - t.strictSame(OUTPUT, [[filename]]) - t.strictSame(tarballFileName, path.resolve(filename)) - t.end() - }) + await pack.exec([]) + const filename = `npm-${require('../../../package.json').version}.tgz` + t.strictSame(OUTPUT, [[filename]]) + t.strictSame(tarballFileName, path.resolve(filename)) }) -t.test('follows pack-destination config', (t) => { +t.test('follows pack-destination config', async t => { let tarballFileName - const Pack = t.mock('../../lib/pack.js', { + const Pack = t.mock('../../../lib/commands/pack.js', { libnpmpack, npmlog: { notice: () => {}, @@ -82,16 +78,14 @@ t.test('follows pack-destination config', (t) => { }) const pack = new Pack(npm) - pack.exec([], err => { - t.error(err, { bail: true }) + await pack.exec([]) - const filename = `npm-${require('../../package.json').version}.tgz` - t.strictSame(OUTPUT, [[filename]]) - t.strictSame(tarballFileName, path.resolve('/tmp/test', filename)) - t.end() - }) + const filename = `npm-${require('../../../package.json').version}.tgz` + t.strictSame(OUTPUT, [[filename]]) + t.strictSame(tarballFileName, path.resolve('/tmp/test', filename)) }) -t.test('should pack given directory', (t) => { + +t.test('should pack given directory', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'my-cool-pkg', @@ -99,7 +93,7 @@ t.test('should pack given directory', (t) => { }, null, 2), }) - const Pack = t.mock('../../lib/pack.js', { + const Pack = t.mock('../../../lib/commands/pack.js', { libnpmpack, npmlog: { notice: () => {}, @@ -120,16 +114,13 @@ t.test('should pack given directory', (t) => { }) const pack = new Pack(npm) - pack.exec([testDir], err => { - t.error(err, { bail: true }) + await pack.exec([testDir]) - const filename = 'my-cool-pkg-1.0.0.tgz' - t.strictSame(OUTPUT, [[filename]]) - t.end() - }) + const filename = 'my-cool-pkg-1.0.0.tgz' + t.strictSame(OUTPUT, [[filename]]) }) -t.test('should pack given directory for scoped package', (t) => { +t.test('should pack given directory for scoped package', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: '@cool/my-pkg', @@ -137,7 +128,7 @@ t.test('should pack given directory for scoped package', (t) => { }, null, 2), }) - const Pack = t.mock('../../lib/pack.js', { + const Pack = t.mock('../../../lib/commands/pack.js', { libnpmpack, npmlog: { notice: () => {}, @@ -158,19 +149,16 @@ t.test('should pack given directory for scoped package', (t) => { }) const pack = new Pack(npm) - return pack.exec([testDir], err => { - t.error(err, { bail: true }) + await pack.exec([testDir]) - const filename = 'cool-my-pkg-1.0.0.tgz' - t.strictSame(OUTPUT, [[filename]]) - t.end() - }) + const filename = 'cool-my-pkg-1.0.0.tgz' + t.strictSame(OUTPUT, [[filename]]) }) -t.test('should log pack contents', (t) => { - const Pack = t.mock('../../lib/pack.js', { - '../../lib/utils/tar.js': { - ...require('../../lib/utils/tar.js'), +t.test('should log pack contents', async t => { + const Pack = t.mock('../../../lib/commands/pack.js', { + '../../../lib/utils/tar.js': { + ...require('../../../lib/utils/tar.js'), logTar: () => { t.ok(true, 'logTar is called') }, @@ -195,16 +183,13 @@ t.test('should log pack contents', (t) => { }) const pack = new Pack(npm) - pack.exec([], err => { - t.error(err, { bail: true }) + await pack.exec([]) - const filename = `npm-${require('../../package.json').version}.tgz` - t.strictSame(OUTPUT, [[filename]]) - t.end() - }) + const filename = `npm-${require('../../../package.json').version}.tgz` + t.strictSame(OUTPUT, [[filename]]) }) -t.test('should log output as valid json', (t) => { +t.test('should log output as valid json', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'my-cool-pkg', @@ -215,9 +200,9 @@ t.test('should log output as valid json', (t) => { 'index.js': 'void', }) - const Pack = t.mock('../../lib/pack.js', { + const Pack = t.mock('../../../lib/commands/pack.js', { libnpmpack, - '../../lib/utils/tar.js': { + '../../../lib/utils/tar.js': { getContents: async () => ({ id: '@ruyadorno/redact@1.0.0', name: '@ruyadorno/redact', @@ -269,38 +254,34 @@ t.test('should log output as valid json', (t) => { }) const pack = new Pack(npm) - pack.exec([testDir], err => { - t.error(err, { bail: true }) - - t.match(JSON.parse(OUTPUT), [{ - id: '@ruyadorno/redact@1.0.0', - name: '@ruyadorno/redact', - version: '1.0.0', - size: 2450, - unpackedSize: 4911, - shasum: '044c7574639b923076069d6e801e2d1866430f17', - integrity: 'sha512-JSdyskeR2qonBUaQ4vdlU/vQGSfgCxSq5O+vH+d2yVWRqzso4O3gUzd6QX/V7OWV//zU7kA5o63Zf433jUnOtQ==', - filename: '@ruyadorno/redact-1.0.0.tgz', - files: [ - { path: 'LICENSE' }, - { path: 'README.md' }, - { path: 'index.js' }, - { path: 'package.json' }, - ], - entryCount: 4, - }], 'pack details output as valid json') - - t.end() - }) + await pack.exec([testDir]) + + t.match(JSON.parse(OUTPUT), [{ + id: '@ruyadorno/redact@1.0.0', + name: '@ruyadorno/redact', + version: '1.0.0', + size: 2450, + unpackedSize: 4911, + shasum: '044c7574639b923076069d6e801e2d1866430f17', + integrity: 'sha512-JSdyskeR2qonBUaQ4vdlU/vQGSfgCxSq5O+vH+d2yVWRqzso4O3gUzd6QX/V7OWV//zU7kA5o63Zf433jUnOtQ==', + filename: '@ruyadorno/redact-1.0.0.tgz', + files: [ + { path: 'LICENSE' }, + { path: 'README.md' }, + { path: 'index.js' }, + { path: 'package.json' }, + ], + entryCount: 4, + }], 'pack details output as valid json') }) -t.test('invalid packument', (t) => { +t.test('invalid packument', async t => { const mockPacote = { manifest: () => { return {} }, } - const Pack = t.mock('../../lib/pack.js', { + const Pack = t.mock('../../../lib/commands/pack.js', { libnpmpack, pacote: mockPacote, npmlog: { @@ -321,12 +302,11 @@ t.test('invalid packument', (t) => { output, }) const pack = new Pack(npm) - pack.exec([], err => { - t.match(err, { message: 'Invalid package, must have name and version' }) - - t.strictSame(OUTPUT, []) - t.end() - }) + await t.rejects( + pack.exec([]), + 'Invalid package, must have name and version' + ) + t.strictSame(OUTPUT, []) }) t.test('workspaces', (t) => { @@ -349,7 +329,7 @@ t.test('workspaces', (t) => { }), }, }) - const Pack = t.mock('../../lib/pack.js', { + const Pack = t.mock('../../../lib/commands/pack.js', { libnpmpack, pacote: mockPacote, npmlog: { @@ -372,50 +352,38 @@ t.test('workspaces', (t) => { }) const pack = new Pack(npm) - t.test('all workspaces', (t) => { - pack.execWorkspaces([], [], err => { - t.error(err, { bail: true }) + t.test('all workspaces', async t => { + await pack.execWorkspaces([], []) - t.strictSame(OUTPUT, [ - ['workspace-a-1.0.0.tgz'], - ['workspace-b-1.0.0.tgz'], - ]) - t.end() - }) + t.strictSame(OUTPUT, [ + ['workspace-a-1.0.0.tgz'], + ['workspace-b-1.0.0.tgz'], + ]) }) - t.test('all workspaces, `.` first arg', (t) => { - pack.execWorkspaces(['.'], [], err => { - t.error(err, { bail: true }) + t.test('all workspaces, `.` first arg', async t => { + await pack.execWorkspaces(['.'], []) - t.strictSame(OUTPUT, [ - ['workspace-a-1.0.0.tgz'], - ['workspace-b-1.0.0.tgz'], - ]) - t.end() - }) + t.strictSame(OUTPUT, [ + ['workspace-a-1.0.0.tgz'], + ['workspace-b-1.0.0.tgz'], + ]) }) - t.test('one workspace', (t) => { - pack.execWorkspaces([], ['workspace-a'], err => { - t.error(err, { bail: true }) + t.test('one workspace', async t => { + await pack.execWorkspaces([], ['workspace-a']) - t.strictSame(OUTPUT, [ - ['workspace-a-1.0.0.tgz'], - ]) - t.end() - }) + t.strictSame(OUTPUT, [ + ['workspace-a-1.0.0.tgz'], + ]) }) - t.test('specific package', (t) => { - pack.execWorkspaces(['abbrev'], [], err => { - t.error(err, { bail: true }) + t.test('specific package', async t => { + await pack.execWorkspaces(['abbrev'], []) - t.strictSame(OUTPUT, [ - ['abbrev-1.0.0-test.tgz'], - ]) - t.end() - }) + t.strictSame(OUTPUT, [ + ['abbrev-1.0.0-test.tgz'], + ]) }) t.end() }) diff --git a/deps/npm/test/lib/ping.js b/deps/npm/test/lib/commands/ping.js similarity index 73% rename from deps/npm/test/lib/ping.js rename to deps/npm/test/lib/commands/ping.js index f0a10718c46d02..7011c709b0bacf 100644 --- a/deps/npm/test/lib/ping.js +++ b/deps/npm/test/lib/commands/ping.js @@ -1,13 +1,13 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') -t.test('pings', (t) => { - t.plan(8) +t.test('pings', async t => { + t.plan(6) const registry = 'https://registry.npmjs.org' let noticeCalls = 0 - const Ping = t.mock('../../lib/ping.js', { - '../../lib/utils/ping.js': function (spec) { + const Ping = t.mock('../../../lib/commands/ping.js', { + '../../../lib/utils/ping.js': function (spec) { t.equal(spec.registry, registry, 'passes flatOptions') return {} }, @@ -30,21 +30,18 @@ t.test('pings', (t) => { }) const ping = new Ping(npm) - ping.exec([], (err) => { - t.equal(noticeCalls, 2, 'should have logged 2 lines') - t.error(err, 'npm ping') - t.ok('should be able to ping') - }) + await ping.exec([]) + t.equal(noticeCalls, 2, 'should have logged 2 lines') }) -t.test('pings and logs details', (t) => { - t.plan(10) +t.test('pings and logs details', async t => { + t.plan(8) const registry = 'https://registry.npmjs.org' const details = { extra: 'data' } let noticeCalls = 0 - const Ping = t.mock('../../lib/ping.js', { - '../../lib/utils/ping.js': function (spec) { + const Ping = t.mock('../../../lib/commands/ping.js', { + '../../../lib/utils/ping.js': function (spec) { t.equal(spec.registry, registry, 'passes flatOptions') return details }, @@ -71,21 +68,18 @@ t.test('pings and logs details', (t) => { }) const ping = new Ping(npm) - ping.exec([], (err) => { - t.equal(noticeCalls, 3, 'should have logged 3 lines') - t.error(err, 'npm ping') - t.ok('should be able to ping') - }) + await ping.exec([]) + t.equal(noticeCalls, 3, 'should have logged 3 lines') }) -t.test('pings and returns json', (t) => { - t.plan(11) +t.test('pings and returns json', async t => { + t.plan(9) const registry = 'https://registry.npmjs.org' const details = { extra: 'data' } let noticeCalls = 0 - const Ping = t.mock('../../lib/ping.js', { - '../../lib/utils/ping.js': function (spec) { + const Ping = t.mock('../../../lib/commands/ping.js', { + '../../../lib/utils/ping.js': function (spec) { t.equal(spec.registry, registry, 'passes flatOptions') return details }, @@ -114,9 +108,6 @@ t.test('pings and returns json', (t) => { }) const ping = new Ping(npm) - ping.exec([], (err) => { - t.equal(noticeCalls, 2, 'should have logged 2 lines') - t.error(err, 'npm ping') - t.ok('should be able to ping') - }) + await ping.exec([]) + t.equal(noticeCalls, 2, 'should have logged 2 lines') }) diff --git a/deps/npm/test/lib/commands/pkg.js b/deps/npm/test/lib/commands/pkg.js new file mode 100644 index 00000000000000..49234e4cce3230 --- /dev/null +++ b/deps/npm/test/lib/commands/pkg.js @@ -0,0 +1,594 @@ +const { resolve } = require('path') +const { readFileSync } = require('fs') +const t = require('tap') +const { fake: mockNpm } = require('../../fixtures/mock-npm') + +const redactCwd = (path) => { + const normalizePath = p => p + .replace(/\\+/g, '/') + .replace(/\r\n/g, '\n') + return normalizePath(path) + .replace(new RegExp(normalizePath(process.cwd()), 'g'), '{CWD}') +} + +t.cleanSnapshot = (str) => redactCwd(str) + +let OUTPUT = '' +const config = { + global: false, + force: false, + 'pkg-cast': 'string', +} +const npm = mockNpm({ + localPrefix: t.testdirName, + config, + output: (str) => { + OUTPUT += str + }, +}) + +const Pkg = require('../../../lib/commands/pkg.js') +const pkg = new Pkg(npm) + +const readPackageJson = (path) => { + path = path || npm.localPrefix + return JSON.parse(readFileSync(resolve(path, 'package.json'), 'utf8')) +} + +t.afterEach(() => { + config.global = false + config.json = false + npm.localPrefix = t.testdirName + OUTPUT = '' +}) + +t.test('no args', async t => { + await t.rejects( + pkg.exec([]), + { code: 'EUSAGE' }, + 'should throw usage error' + ) +}) + +t.test('no global mode', async t => { + config.global = true + await t.rejects( + pkg.exec(['get', 'foo']), + { code: 'EPKGGLOBAL' }, + 'should throw no global mode error' + ) +}) + +t.test('get no args', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + }), + }) + + await pkg.exec(['get']) + + t.strictSame( + JSON.parse(OUTPUT), + { + name: 'foo', + version: '1.1.1', + }, + 'should print package.json content' + ) +}) + +t.test('get single arg', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + }), + }) + + await pkg.exec(['get', 'version']) + + t.strictSame( + JSON.parse(OUTPUT), + '1.1.1', + 'should print retrieved package.json field' + ) +}) + +t.test('get nested arg', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + scripts: { + test: 'node test.js', + }, + }), + }) + + await pkg.exec(['get', 'scripts.test']) + + t.strictSame( + JSON.parse(OUTPUT), + 'node test.js', + 'should print retrieved nested field' + ) +}) + +t.test('get array field', async t => { + const files = [ + 'index.js', + 'cli.js', + ] + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + files, + }), + }) + + await pkg.exec(['get', 'files']) + + t.strictSame( + JSON.parse(OUTPUT), + files, + 'should print retrieved array field' + ) +}) + +t.test('get array item', async t => { + const files = [ + 'index.js', + 'cli.js', + ] + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + files, + }), + }) + + await pkg.exec(['get', 'files[0]']) + + t.strictSame( + JSON.parse(OUTPUT), + 'index.js', + 'should print retrieved array field' + ) +}) + +t.test('get array nested items notation', async t => { + const contributors = [ + { + name: 'Ruy', + url: 'http://example.com/ruy', + }, + { + name: 'Gar', + url: 'http://example.com/gar', + }, + ] + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + contributors, + }), + }) + + await pkg.exec(['get', 'contributors.name']) + t.strictSame( + JSON.parse(OUTPUT), + { + 'contributors[0].name': 'Ruy', + 'contributors[1].name': 'Gar', + }, + 'should print json result containing matching results' + ) +}) + +t.test('set no args', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ name: 'foo' }), + }) + await t.rejects( + pkg.exec(['set']), + { code: 'EUSAGE' }, + 'should throw an error if no args' + ) +}) + +t.test('set missing value', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ name: 'foo' }), + }) + await t.rejects( + pkg.exec(['set', 'key=']), + { code: 'EUSAGE' }, + 'should throw an error if missing value' + ) +}) + +t.test('set missing key', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ name: 'foo' }), + }) + await t.rejects( + pkg.exec(['set', '=value']), + { code: 'EUSAGE' }, + 'should throw an error if missing key' + ) +}) + +t.test('set single field', async t => { + const json = { + name: 'foo', + version: '1.1.1', + } + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify(json), + }) + + await pkg.exec(['set', 'description=Awesome stuff']) + t.strictSame( + readPackageJson(), + { + ...json, + description: 'Awesome stuff', + }, + 'should add single field to package.json' + ) +}) + +t.test('push to array syntax', async t => { + const json = { + name: 'foo', + version: '1.1.1', + keywords: [ + 'foo', + ], + } + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify(json), + }) + + await pkg.exec(['set', 'keywords[]=bar', 'keywords[]=baz']) + t.strictSame( + readPackageJson(), + { + ...json, + keywords: [ + 'foo', + 'bar', + 'baz', + ], + }, + 'should append to arrays using empty bracket syntax' + ) +}) + +t.test('set multiple fields', async t => { + const json = { + name: 'foo', + version: '1.1.1', + } + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify(json), + }) + + await pkg.exec(['set', 'bin.foo=foo.js', 'scripts.test=node test.js']) + t.strictSame( + readPackageJson(), + { + ...json, + bin: { + foo: 'foo.js', + }, + scripts: { + test: 'node test.js', + }, + }, + 'should add single field to package.json' + ) +}) + +t.test('set = separate value', async t => { + const json = { + name: 'foo', + version: '1.1.1', + } + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify(json), + }) + + await pkg.exec(['set', 'tap[test-env][0]=LC_ALL=sk']) + t.strictSame( + readPackageJson(), + { + ...json, + tap: { + 'test-env': [ + 'LC_ALL=sk', + ], + }, + }, + 'should add single field to package.json' + ) +}) + +t.test('set --json', async t => { + config.json = true + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.1.1', + }), + }) + + await pkg.exec(['set', 'private=true']) + t.strictSame( + readPackageJson(), + { + name: 'foo', + version: '1.1.1', + private: true, + }, + 'should add boolean field to package.json' + ) + + await pkg.exec(['set', 'tap.timeout=60']) + t.strictSame( + readPackageJson(), + { + name: 'foo', + version: '1.1.1', + private: true, + tap: { + timeout: 60, + }, + }, + 'should add number field to package.json' + ) + + await pkg.exec(['set', 'foo={ "bar": { "baz": "BAZ" } }']) + t.strictSame( + readPackageJson(), + { + name: 'foo', + version: '1.1.1', + private: true, + tap: { + timeout: 60, + }, + foo: { + bar: { + baz: 'BAZ', + }, + }, + }, + 'should add object field to package.json' + ) + + await pkg.exec(['set', 'workspaces=["packages/*"]']) + t.strictSame( + readPackageJson(), + { + name: 'foo', + version: '1.1.1', + private: true, + workspaces: [ + 'packages/*', + ], + tap: { + timeout: 60, + }, + foo: { + bar: { + baz: 'BAZ', + }, + }, + }, + 'should add object field to package.json' + ) + + await pkg.exec(['set', 'description="awesome"']) + t.strictSame( + readPackageJson(), + { + name: 'foo', + version: '1.1.1', + description: 'awesome', + private: true, + workspaces: [ + 'packages/*', + ], + tap: { + timeout: 60, + }, + foo: { + bar: { + baz: 'BAZ', + }, + }, + }, + 'should add object field to package.json' + ) +}) + +t.test('delete no args', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ name: 'foo' }), + }) + await t.rejects( + pkg.exec(['delete']), + { code: 'EUSAGE' }, + 'should throw an error if deleting no args' + ) +}) + +t.test('delete invalid key', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ name: 'foo' }), + }) + await t.rejects( + pkg.exec(['delete', '']), + { code: 'EUSAGE' }, + 'should throw an error if deleting invalid args' + ) +}) + +t.test('delete single field', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + }), + }) + await pkg.exec(['delete', 'version']) + t.strictSame( + readPackageJson(), + { + name: 'foo', + }, + 'should delete single field from package.json' + ) +}) + +t.test('delete multiple field', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + description: 'awesome', + }), + }) + await pkg.exec(['delete', 'version', 'description']) + t.strictSame( + readPackageJson(), + { + name: 'foo', + }, + 'should delete multiple fields from package.json' + ) +}) + +t.test('delete nested field', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + info: { + foo: { + bar: [ + { + baz: 'deleteme', + }, + ], + }, + }, + }), + }) + await pkg.exec(['delete', 'info.foo.bar[0].baz']) + t.strictSame( + readPackageJson(), + { + name: 'foo', + version: '1.0.0', + info: { + foo: { + bar: [ + {}, + ], + }, + }, + }, + 'should delete nested fields from package.json' + ) +}) + +t.test('workspaces', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'root', + version: '1.0.0', + workspaces: [ + 'packages/*', + ], + }), + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.2.3', + }), + }, + }, + }) + + await pkg.execWorkspaces(['get', 'name', 'version'], []) + + t.strictSame( + JSON.parse(OUTPUT), + { + a: { + name: 'a', + version: '1.0.0', + }, + b: { + name: 'b', + version: '1.2.3', + }, + }, + 'should return expected result for configured workspaces' + ) + + await pkg.execWorkspaces(['set', 'funding=http://example.com'], []) + + t.strictSame( + readPackageJson(resolve(npm.localPrefix, 'packages/a')), + { + name: 'a', + version: '1.0.0', + funding: 'http://example.com', + }, + 'should add field to workspace a' + ) + + t.strictSame( + readPackageJson(resolve(npm.localPrefix, 'packages/b')), + { + name: 'b', + version: '1.2.3', + funding: 'http://example.com', + }, + 'should add field to workspace b' + ) + + await pkg.execWorkspaces(['delete', 'version'], []) + t.strictSame( + readPackageJson(resolve(npm.localPrefix, 'packages/a')), + { + name: 'a', + funding: 'http://example.com', + }, + 'should delete version field from workspace a' + ) + + t.strictSame( + readPackageJson(resolve(npm.localPrefix, 'packages/b')), + { + name: 'b', + funding: 'http://example.com', + }, + 'should delete version field from workspace b' + ) +}) diff --git a/deps/npm/test/lib/commands/prefix.js b/deps/npm/test/lib/commands/prefix.js new file mode 100644 index 00000000000000..6f059e73a7ec5b --- /dev/null +++ b/deps/npm/test/lib/commands/prefix.js @@ -0,0 +1,13 @@ +const t = require('tap') +const { real: mockNpm } = require('../../fixtures/mock-npm') + +t.test('prefix', async t => { + const { joinedOutput, Npm } = mockNpm(t) + const npm = new Npm() + await npm.exec('prefix', []) + t.equal( + joinedOutput(), + npm.prefix, + 'outputs npm.prefix' + ) +}) diff --git a/deps/npm/test/lib/profile.js b/deps/npm/test/lib/commands/profile.js similarity index 58% rename from deps/npm/test/lib/profile.js rename to deps/npm/test/lib/commands/profile.js index 112aa5c3b75e19..0a3680cf155f89 100644 --- a/deps/npm/test/lib/profile.js +++ b/deps/npm/test/lib/commands/profile.js @@ -1,5 +1,5 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') let result = '' const config = { @@ -41,12 +41,12 @@ const mocks = { .join('\n') } }, - '../../lib/utils/pulse-till-done.js': { + '../../../lib/utils/pulse-till-done.js': { withPromise: async a => a, }, - '../../lib/utils/otplease.js': async (opts, fn) => fn(opts), - '../../lib/utils/usage.js': () => 'usage instructions', - '../../lib/utils/read-user-info.js': { + '../../../lib/utils/otplease.js': async (opts, fn) => fn(opts), + '../../../lib/utils/usage.js': () => 'usage instructions', + '../../../lib/utils/read-user-info.js': { async password () {}, async otp () {}, }, @@ -74,18 +74,14 @@ t.afterEach(() => { config.registry = 'https://registry.npmjs.org/' }) -const Profile = t.mock('../../lib/profile.js', mocks) +const Profile = t.mock('../../../lib/commands/profile.js', mocks) const profile = new Profile(npm) -t.test('no args', t => { - profile.exec([], err => { - t.match( - err, - /usage instructions/, - 'should throw usage instructions' - ) - t.end() - }) +t.test('no args', async t => { + await t.rejects( + profile.exec([]), + profile.usage + ) }) t.test('profile get no args', t => { @@ -95,57 +91,44 @@ t.test('profile get no args', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, }) const profile = new Profile(npm) - t.test('default output', t => { - profile.exec(['get'], err => { - if (err) - throw err + t.test('default output', async t => { + await profile.exec(['get']) - t.matchSnapshot( - result, - 'should output table with contents' - ) - t.end() - }) + t.matchSnapshot( + result, + 'should output table with contents' + ) }) - t.test('--json', t => { + t.test('--json', async t => { config.json = true - profile.exec(['get'], err => { - if (err) - throw err + await profile.exec(['get']) - t.same( - JSON.parse(result), - userProfile, - 'should output json profile result' - ) - t.end() - }) + t.same( + JSON.parse(result), + userProfile, + 'should output json profile result' + ) }) - t.test('--parseable', t => { + t.test('--parseable', async t => { config.parseable = true - profile.exec(['get'], err => { - if (err) - throw err - - t.matchSnapshot( - result, - 'should output all profile info as parseable result' - ) - t.end() - }) + await profile.exec(['get']) + t.matchSnapshot( + result, + 'should output all profile info as parseable result' + ) }) - t.test('no tfa enabled', t => { + t.test('no tfa enabled', async t => { const npmProfile = { async get () { return { @@ -155,25 +138,20 @@ t.test('profile get no args', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, }) const profile = new Profile(npm) - profile.exec(['get'], err => { - if (err) - throw err - - t.matchSnapshot( - result, - 'should output expected profile values' - ) - t.end() - }) + await profile.exec(['get']) + t.matchSnapshot( + result, + 'should output expected profile values' + ) }) - t.test('unverified email', t => { + t.test('unverified email', async t => { const npmProfile = { async get () { return { @@ -183,25 +161,21 @@ t.test('profile get no args', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, }) const profile = new Profile(npm) - profile.exec(['get'], err => { - if (err) - throw err + await profile.exec(['get']) - t.matchSnapshot( - result, - 'should output table with contents' - ) - t.end() - }) + t.matchSnapshot( + result, + 'should output table with contents' + ) }) - t.test('profile has cidr_whitelist item', t => { + t.test('profile has cidr_whitelist item', async t => { const npmProfile = { async get () { return { @@ -211,22 +185,18 @@ t.test('profile get no args', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, }) const profile = new Profile(npm) - profile.exec(['get'], err => { - if (err) - throw err + await profile.exec(['get']) - t.matchSnapshot( - result, - 'should output table with contents' - ) - t.end() - }) + t.matchSnapshot( + result, + 'should output table with contents' + ) }) t.end() @@ -239,55 +209,43 @@ t.test('profile get ', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, }) const profile = new Profile(npm) - t.test('default output', t => { - profile.exec(['get', 'name'], err => { - if (err) - throw err + t.test('default output', async t => { + await profile.exec(['get', 'name']) - t.equal( - result, - 'foo', - 'should output value result' - ) - t.end() - }) + t.equal( + result, + 'foo', + 'should output value result' + ) }) - t.test('--json', t => { + t.test('--json', async t => { config.json = true - profile.exec(['get', 'name'], err => { - if (err) - throw err + await profile.exec(['get', 'name']) - t.same( - JSON.parse(result), - userProfile, - 'should output json profile result ignoring args filter' - ) - t.end() - }) + t.same( + JSON.parse(result), + userProfile, + 'should output json profile result ignoring args filter' + ) }) - t.test('--parseable', t => { + t.test('--parseable', async t => { config.parseable = true - profile.exec(['get', 'name'], err => { - if (err) - throw err + await profile.exec(['get', 'name']) - t.matchSnapshot( - result, - 'should output parseable result value' - ) - t.end() - }) + t.matchSnapshot( + result, + 'should output parseable result value' + ) }) t.end() @@ -300,67 +258,51 @@ t.test('profile get multiple args', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, }) const profile = new Profile(npm) - t.test('default output', t => { - profile.exec(['get', 'name', 'email', 'github'], err => { - if (err) - throw err + t.test('default output', async t => { + await profile.exec(['get', 'name', 'email', 'github']) - t.matchSnapshot( - result, - 'should output all keys' - ) - t.end() - }) + t.matchSnapshot( + result, + 'should output all keys' + ) }) - t.test('--json', t => { + t.test('--json', async t => { config.json = true - profile.exec(['get', 'name', 'email', 'github'], err => { - if (err) - throw err + await profile.exec(['get', 'name', 'email', 'github']) - t.same( - JSON.parse(result), - userProfile, - 'should output json profile result and ignore args' - ) - t.end() - }) + t.same( + JSON.parse(result), + userProfile, + 'should output json profile result and ignore args' + ) }) - t.test('--parseable', t => { + t.test('--parseable', async t => { config.parseable = true - profile.exec(['get', 'name', 'email', 'github'], err => { - if (err) - throw err + await profile.exec(['get', 'name', 'email', 'github']) - t.matchSnapshot( - result, - 'should output parseable profile value results' - ) - t.end() - }) + t.matchSnapshot( + result, + 'should output parseable profile value results' + ) }) - t.test('comma separated', t => { - profile.exec(['get', 'name,email,github'], err => { - if (err) - throw err + t.test('comma separated', async t => { + await profile.exec(['get', 'name,email,github']) - t.matchSnapshot( - result, - 'should output all keys' - ) - t.end() - }) + t.matchSnapshot( + result, + 'should output all keys' + ) }) t.end() @@ -386,123 +328,101 @@ t.test('profile set ', t => { }, }) - t.test('no key', t => { - profile.exec(['set'], err => { - t.match( - err, - /npm profile set /, - 'should throw proper usage message' - ) - t.end() - }) + t.test('no key', async t => { + await t.rejects( + profile.exec(['set']), + /npm profile set /, + 'should throw proper usage message' + ) }) - t.test('no value', t => { - profile.exec(['set', 'email'], err => { - t.match( - err, - /npm profile set /, - 'should throw proper usage message' - ) - t.end() - }) + t.test('no value', async t => { + await t.rejects( + profile.exec(['set', 'email']), + /npm profile set /, + 'should throw proper usage message' + ) }) - t.test('set password', t => { - profile.exec(['set', 'password', '1234'], err => { - t.match( - err, - /Do not include your current or new passwords on the command line./, - 'should throw an error refusing to set password from args' - ) - t.end() - }) + t.test('set password', async t => { + await t.rejects( + profile.exec(['set', 'password', '1234']), + /Do not include your current or new passwords on the command line./, + 'should throw an error refusing to set password from args' + ) }) - t.test('unwritable key', t => { - profile.exec(['set', 'name', 'foo'], err => { - t.match( - err, - /"name" is not a property we can set./, - 'should throw the unwritable key error' - ) - t.end() - }) + t.test('unwritable key', async t => { + await await t.rejects( + profile.exec(['set', 'name', 'foo']), + /"name" is not a property we can set./, + 'should throw the unwritable key error' + ) }) t.test('writable key', t => { - t.test('default output', t => { + t.test('default output', async t => { t.plan(2) - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile(t), }) const profile = new Profile(npm) - profile.exec(['set', 'fullname', 'Lorem Ipsum'], err => { - if (err) - throw err - - t.equal( - result, - 'Set\nfullname\nto\nLorem Ipsum', - 'should output set key success msg' - ) - }) + await profile.exec(['set', 'fullname', 'Lorem Ipsum']) + t.equal( + result, + 'Set\nfullname\nto\nLorem Ipsum', + 'should output set key success msg' + ) }) - t.test('--json', t => { + t.test('--json', async t => { t.plan(2) config.json = true - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile(t), }) const profile = new Profile(npm) - profile.exec(['set', 'fullname', 'Lorem Ipsum'], err => { - if (err) - throw err + await profile.exec(['set', 'fullname', 'Lorem Ipsum']) - t.same( - JSON.parse(result), - { - fullname: 'Lorem Ipsum', - }, - 'should output json set key success msg' - ) - }) + t.same( + JSON.parse(result), + { + fullname: 'Lorem Ipsum', + }, + 'should output json set key success msg' + ) }) - t.test('--parseable', t => { + t.test('--parseable', async t => { t.plan(2) config.parseable = true - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile(t), }) const profile = new Profile(npm) - profile.exec(['set', 'fullname', 'Lorem Ipsum'], err => { - if (err) - throw err + await profile.exec(['set', 'fullname', 'Lorem Ipsum']) - t.matchSnapshot( - result, - 'should output parseable set key success msg' - ) - }) + t.matchSnapshot( + result, + 'should output parseable set key success msg' + ) }) t.end() }) - t.test('write new email', t => { + t.test('write new email', async t => { t.plan(3) const npmProfile = { @@ -529,25 +449,21 @@ t.test('profile set ', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, }) const profile = new Profile(npm) - profile.exec(['set', 'email', 'foo@npmjs.com'], err => { - if (err) - throw err - - t.equal( - result, - 'Set\nemail\nto\nfoo@npmjs.com', - 'should output set key success msg' - ) - }) + await profile.exec(['set', 'email', 'foo@npmjs.com']) + t.equal( + result, + 'Set\nemail\nto\nfoo@npmjs.com', + 'should output set key success msg' + ) }) - t.test('change password', t => { + t.test('change password', async t => { t.plan(6) const npmProfile = { @@ -593,27 +509,23 @@ t.test('profile set ', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, - '../../lib/utils/read-user-info.js': readUserInfo, + '../../../lib/utils/read-user-info.js': readUserInfo, }) const profile = new Profile(npm) - profile.exec(['set', 'password'], err => { - if (err) - throw err + await profile.exec(['set', 'password']) - t.equal( - result, - 'Set\npassword', - 'should output set password success msg' - ) - t.end() - }) + t.equal( + result, + 'Set\npassword', + 'should output set password success msg' + ) }) - t.test('password confirmation mismatch', t => { + t.test('password confirmation mismatch', async t => { t.plan(3) let passwordPromptCount = 0 @@ -661,82 +573,66 @@ t.test('profile set ', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, npmlog, 'npm-profile': npmProfile, - '../../lib/utils/read-user-info.js': readUserInfo, + '../../../lib/utils/read-user-info.js': readUserInfo, }) const profile = new Profile(npm) - profile.exec(['set', 'password'], err => { - if (err) - throw err + await profile.exec(['set', 'password']) - t.equal( - result, - 'Set\npassword', - 'should output set password success msg' - ) - t.end() - }) + t.equal( + result, + 'Set\npassword', + 'should output set password success msg' + ) }) t.end() }) t.test('enable-2fa', t => { - t.test('invalid args', t => { - profile.exec(['enable-2fa', 'foo', 'bar'], err => { - t.match( - err, - /npm profile enable-2fa \[auth-and-writes|auth-only\]/, - 'should throw usage error' - ) - t.end() - }) + t.test('invalid args', async t => { + await t.rejects( + profile.exec(['enable-2fa', 'foo', 'bar']), + /npm profile enable-2fa \[auth-and-writes|auth-only\]/, + 'should throw usage error' + ) }) - t.test('invalid two factor auth mode', t => { - profile.exec(['enable-2fa', 'foo'], err => { - t.match( - err, - /Invalid two-factor authentication mode "foo"/, - 'should throw invalid auth mode error' - ) - t.end() - }) + t.test('invalid two factor auth mode', async t => { + await t.rejects( + profile.exec(['enable-2fa', 'foo']), + /Invalid two-factor authentication mode "foo"/, + 'should throw invalid auth mode error' + ) }) - t.test('no support for --json output', t => { + t.test('no support for --json output', async t => { config.json = true - profile.exec(['enable-2fa', 'auth-only'], err => { - t.match( - err.message, - 'Enabling two-factor authentication is an interactive ' + - 'operation and JSON output mode is not available', - 'should throw no support msg' - ) - t.end() - }) + await t.rejects( + profile.exec(['enable-2fa', 'auth-only']), + 'Enabling two-factor authentication is an interactive ' + + 'operation and JSON output mode is not available', + 'should throw no support msg' + ) }) - t.test('no support for --parseable output', t => { + t.test('no support for --parseable output', async t => { config.parseable = true - profile.exec(['enable-2fa', 'auth-only'], err => { - t.match( - err.message, - 'Enabling two-factor authentication is an interactive ' + - 'operation and parseable output mode is not available', - 'should throw no support msg' - ) - t.end() - }) + await t.rejects( + profile.exec(['enable-2fa', 'auth-only']), + 'Enabling two-factor authentication is an interactive ' + + 'operation and parseable output mode is not available', + 'should throw no support msg' + ) }) - t.test('no bearer tokens returned by registry', t => { + t.test('no bearer tokens returned by registry', async t => { t.plan(3) // mock legacy basic auth style @@ -752,24 +648,22 @@ t.test('enable-2fa', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, }) const profile = new Profile(npm) - profile.exec(['enable-2fa', 'auth-only'], err => { - t.match( - err.message, - 'Your registry https://registry.npmjs.org/ does ' + - 'not seem to support bearer tokens. Bearer tokens ' + - 'are required for two-factor authentication', - 'should throw no support msg' - ) - }) + await t.rejects( + profile.exec(['enable-2fa', 'auth-only']), + 'Your registry https://registry.npmjs.org/ does ' + + 'not seem to support bearer tokens. Bearer tokens ' + + 'are required for two-factor authentication', + 'should throw no support msg' + ) }) - t.test('from basic username/password auth', t => { + t.test('from basic username/password auth', async t => { // mock legacy basic auth style with user/pass npm.config.getCredentialsByURI = () => { return { username: 'foo', password: 'bar' } @@ -781,43 +675,37 @@ t.test('enable-2fa', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, }) const profile = new Profile(npm) - profile.exec(['enable-2fa', 'auth-only'], err => { - t.match( - err.message, - 'Your registry https://registry.npmjs.org/ does ' + - 'not seem to support bearer tokens. Bearer tokens ' + - 'are required for two-factor authentication', - 'should throw no support msg' - ) - t.end() - }) + await t.rejects( + profile.exec(['enable-2fa', 'auth-only']), + 'Your registry https://registry.npmjs.org/ does ' + + 'not seem to support bearer tokens. Bearer tokens ' + + 'are required for two-factor authentication', + 'should throw no support msg' + ) }) - t.test('no auth found', t => { + t.test('no auth found', async t => { npm.config.getCredentialsByURI = () => ({}) - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, }) const profile = new Profile(npm) - profile.exec(['enable-2fa', 'auth-only'], err => { - t.match( - err.message, - 'You need to be logged in to registry ' + - 'https://registry.npmjs.org/ in order to enable 2fa' - ) - t.end() - }) + await t.rejects( + profile.exec(['enable-2fa', 'auth-only']), + 'You need to be logged in to registry ' + + 'https://registry.npmjs.org/ in order to enable 2fa' + ) }) - t.test('from basic auth, asks for otp', t => { + t.test('from basic auth, asks for otp', async t => { t.plan(10) // mock legacy basic auth style @@ -881,26 +769,22 @@ t.test('enable-2fa', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, - '../../lib/utils/read-user-info.js': readUserInfo, + '../../../lib/utils/read-user-info.js': readUserInfo, }) const profile = new Profile(npm) - profile.exec(['enable-2fa', 'auth-only'], err => { - if (err) - throw err - - t.equal( - result, - 'Two factor authentication mode changed to: auth-only', - 'should output success msg' - ) - }) + await profile.exec(['enable-2fa', 'auth-only']) + t.equal( + result, + 'Two factor authentication mode changed to: auth-only', + 'should output success msg' + ) }) - t.test('from token and set otp, retries on pending and verifies with qrcode', t => { + t.test('from token and set otp, retries on pending and verifies with qrcode', async t => { t.plan(4) flatOptions.otp = '1234' @@ -983,26 +867,23 @@ t.test('enable-2fa', t => { generate: (url, cb) => cb('qrcode'), } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, 'qrcode-terminal': qrcode, - '../../lib/utils/read-user-info.js': readUserInfo, + '../../../lib/utils/read-user-info.js': readUserInfo, }) const profile = new Profile(npm) - profile.exec(['enable-2fa', 'auth-only'], err => { - if (err) - throw err + await profile.exec(['enable-2fa', 'auth-only']) - t.matchSnapshot( - result, - 'should output 2fa enablement success msgs' - ) - }) + t.matchSnapshot( + result, + 'should output 2fa enablement success msgs' + ) }) - t.test('from token and set otp, retrieves invalid otp', t => { + t.test('from token and set otp, retrieves invalid otp', async t => { flatOptions.otp = '1234' npm.config.getCredentialsByURI = () => { @@ -1035,24 +916,21 @@ t.test('enable-2fa', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, - '../../lib/utils/read-user-info.js': readUserInfo, + '../../../lib/utils/read-user-info.js': readUserInfo, }) const profile = new Profile(npm) - profile.exec(['enable-2fa', 'auth-only'], err => { - t.match( - err, - /Unknown error enabling two-factor authentication./, - 'should throw invalid 2fa auth url error' - ) - t.end() - }) + await t.rejects( + profile.exec(['enable-2fa', 'auth-only']), + /Unknown error enabling two-factor authentication./, + 'should throw invalid 2fa auth url error' + ) }) - t.test('from token auth provides --otp config arg', t => { + t.test('from token auth provides --otp config arg', async t => { flatOptions.otp = '123456' flatOptions.otp = '123456' @@ -1081,27 +959,23 @@ t.test('enable-2fa', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, - '../../lib/utils/read-user-info.js': readUserInfo, + '../../../lib/utils/read-user-info.js': readUserInfo, }) const profile = new Profile(npm) - profile.exec(['enable-2fa', 'auth-and-writes'], err => { - if (err) - throw err + await profile.exec(['enable-2fa', 'auth-and-writes']) - t.equal( - result, - 'Two factor authentication mode changed to: auth-and-writes', - 'should output success msg' - ) - t.end() - }) + t.equal( + result, + 'Two factor authentication mode changed to: auth-and-writes', + 'should output success msg' + ) }) - t.test('missing tfa from user profile', t => { + t.test('missing tfa from user profile', async t => { npm.config.getCredentialsByURI = (reg) => { return { token: 'token' } } @@ -1130,27 +1004,23 @@ t.test('enable-2fa', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, - '../../lib/utils/read-user-info.js': readUserInfo, + '../../../lib/utils/read-user-info.js': readUserInfo, }) const profile = new Profile(npm) - profile.exec(['enable-2fa', 'auth-only'], err => { - if (err) - throw err + await profile.exec(['enable-2fa', 'auth-only']) - t.equal( - result, - 'Two factor authentication mode changed to: auth-only', - 'should output success msg' - ) - t.end() - }) + t.equal( + result, + 'Two factor authentication mode changed to: auth-only', + 'should output success msg' + ) }) - t.test('defaults to auth-and-writes permission if no mode specified', t => { + t.test('defaults to auth-and-writes permission if no mode specified', async t => { npm.config.getCredentialsByURI = (reg) => { return { token: 'token' } } @@ -1179,31 +1049,26 @@ t.test('enable-2fa', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, - '../../lib/utils/read-user-info.js': readUserInfo, + '../../../lib/utils/read-user-info.js': readUserInfo, }) const profile = new Profile(npm) - profile.exec(['enable-2fa'], err => { - if (err) - throw err - - t.equal( - result, - 'Two factor authentication mode changed to: auth-and-writes', - 'should enable 2fa with auth-and-writes permission' - ) - t.end() - }) + await profile.exec(['enable-2fa']) + t.equal( + result, + 'Two factor authentication mode changed to: auth-and-writes', + 'should enable 2fa with auth-and-writes permission' + ) }) t.end() }) t.test('disable-2fa', t => { - t.test('no tfa enabled', t => { + t.test('no tfa enabled', async t => { const npmProfile = { async get () { return { @@ -1213,23 +1078,18 @@ t.test('disable-2fa', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, }) const profile = new Profile(npm) - profile.exec(['disable-2fa'], err => { - if (err) - throw err - - t.equal( - result, - 'Two factor authentication not enabled.', - 'should output already disalbed msg' - ) - t.end() - }) + await profile.exec(['disable-2fa']) + t.equal( + result, + 'Two factor authentication not enabled.', + 'should output already disalbed msg' + ) }) t.test('requests otp', t => { @@ -1274,77 +1134,64 @@ t.test('disable-2fa', t => { }, }) - t.test('default output', t => { - const Profile = t.mock('../../lib/profile.js', { + t.test('default output', async t => { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile(t), - '../../lib/utils/read-user-info.js': readUserInfo(t), + '../../../lib/utils/read-user-info.js': readUserInfo(t), }) const profile = new Profile(npm) - profile.exec(['disable-2fa'], err => { - if (err) - throw err - - t.equal( - result, - 'Two factor authentication disabled.', - 'should output already disabled msg' - ) - t.end() - }) + await profile.exec(['disable-2fa']) + t.equal( + result, + 'Two factor authentication disabled.', + 'should output already disabled msg' + ) }) - t.test('--json', t => { + t.test('--json', async t => { config.json = true - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile(t), - '../../lib/utils/read-user-info.js': readUserInfo(t), + '../../../lib/utils/read-user-info.js': readUserInfo(t), }) const profile = new Profile(npm) - profile.exec(['disable-2fa'], err => { - if (err) - throw err + await profile.exec(['disable-2fa']) - t.same( - JSON.parse(result), - { tfa: false }, - 'should output json already disabled msg' - ) - t.end() - }) + t.same( + JSON.parse(result), + { tfa: false }, + 'should output json already disabled msg' + ) }) - t.test('--parseable', t => { + t.test('--parseable', async t => { config.parseable = true - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile(t), - '../../lib/utils/read-user-info.js': readUserInfo(t), + '../../../lib/utils/read-user-info.js': readUserInfo(t), }) const profile = new Profile(npm) - profile.exec(['disable-2fa'], err => { - if (err) - throw err + await profile.exec(['disable-2fa']) - t.equal( - result, - 'tfa\tfalse', - 'should output parseable already disabled msg' - ) - t.end() - }) + t.equal( + result, + 'tfa\tfalse', + 'should output parseable already disabled msg' + ) }) t.end() }) - t.test('--otp config already set', t => { + t.test('--otp config already set', async t => { t.plan(3) flatOptions.otp = '123456' @@ -1384,37 +1231,31 @@ t.test('disable-2fa', t => { }, } - const Profile = t.mock('../../lib/profile.js', { + const Profile = t.mock('../../../lib/commands/profile.js', { ...mocks, 'npm-profile': npmProfile, - '../../lib/utils/read-user-info.js': readUserInfo, + '../../../lib/utils/read-user-info.js': readUserInfo, }) const profile = new Profile(npm) - profile.exec(['disable-2fa'], err => { - if (err) - throw err + await profile.exec(['disable-2fa']) - t.equal( - result, - 'Two factor authentication disabled.', - 'should output already disalbed msg' - ) - }) + t.equal( + result, + 'Two factor authentication disabled.', + 'should output already disalbed msg' + ) }) t.end() }) -t.test('unknown subcommand', t => { - profile.exec(['asfd'], err => { - t.match( - err, - /Unknown profile command: asfd/, - 'should throw unknown cmd error' - ) - t.end() - }) +t.test('unknown subcommand', async t => { + await t.rejects( + profile.exec(['asfd']), + /Unknown profile command: asfd/, + 'should throw unknown cmd error' + ) }) t.test('completion', t => { diff --git a/deps/npm/test/lib/prune.js b/deps/npm/test/lib/commands/prune.js similarity index 73% rename from deps/npm/test/lib/prune.js rename to deps/npm/test/lib/commands/prune.js index 3e47feb4613942..49d5ab9be35145 100644 --- a/deps/npm/test/lib/prune.js +++ b/deps/npm/test/lib/commands/prune.js @@ -1,9 +1,9 @@ const t = require('tap') -const { real: mockNpm } = require('../fixtures/mock-npm') +const { real: mockNpm } = require('../../fixtures/mock-npm') t.test('should prune using Arborist', async (t) => { t.plan(4) - const { command, npm } = mockNpm(t, { + const { Npm } = mockNpm(t, { '@npmcli/arborist': function (args) { t.ok(args, 'gets options object') t.ok(args.path, 'gets path option') @@ -15,6 +15,6 @@ t.test('should prune using Arborist', async (t) => { t.ok(arb, 'gets arborist tree') }, }) - await npm.load() - await command('prune') + const npm = new Npm() + await npm.exec('prune', []) }) diff --git a/deps/npm/test/lib/publish.js b/deps/npm/test/lib/commands/publish.js similarity index 72% rename from deps/npm/test/lib/publish.js rename to deps/npm/test/lib/commands/publish.js index 6b0021db683501..6c444e5f7fb0c9 100644 --- a/deps/npm/test/lib/publish.js +++ b/deps/npm/test/lib/commands/publish.js @@ -1,5 +1,5 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') const fs = require('fs') // The way we set loglevel is kind of convoluted, and there is no way to affect @@ -13,7 +13,7 @@ t.cleanSnapshot = (data) => { return data.replace(/^ *"gitHead": .*$\n/gm, '') } -const {definitions} = require('../../lib/utils/config') +const {definitions} = require('../../../lib/utils/config') const defaults = Object.entries(definitions).reduce((defaults, [key, def]) => { defaults[key] = def.default return defaults @@ -21,8 +21,8 @@ const defaults = Object.entries(definitions).reduce((defaults, [key, def]) => { t.afterEach(() => log.level = 'silent') -t.test('should publish with libnpmpublish, passing through flatOptions and respecting publishConfig.registry', (t) => { - t.plan(7) +t.test('should publish with libnpmpublish, passing through flatOptions and respecting publishConfig.registry', async t => { + t.plan(6) const registry = 'https://some.registry' const publishConfig = { registry } @@ -34,7 +34,7 @@ t.test('should publish with libnpmpublish, passing through flatOptions and respe }, null, 2), }) - const Publish = t.mock('../../lib/publish.js', { + const Publish = t.mock('../../../lib/commands/publish.js', { // verify that we do NOT remove publishConfig if it was there originally // and then removed during the script/pack process libnpmpack: async () => { @@ -66,16 +66,11 @@ t.test('should publish with libnpmpublish, passing through flatOptions and respe } const publish = new Publish(npm) - publish.exec([testDir], (er) => { - if (er) - throw er - t.pass('got to callback') - t.end() - }) + await publish.exec([testDir]) }) -t.test('re-loads publishConfig.registry if added during script process', (t) => { - t.plan(6) +t.test('re-loads publishConfig.registry if added during script process', async t => { + t.plan(5) const registry = 'https://some.registry' const publishConfig = { registry } const testDir = t.testdir({ @@ -85,7 +80,7 @@ t.test('re-loads publishConfig.registry if added during script process', (t) => }, null, 2), }) - const Publish = t.mock('../../lib/publish.js', { + const Publish = t.mock('../../../lib/commands/publish.js', { libnpmpack: async () => { fs.writeFileSync(`${testDir}/package.json`, JSON.stringify({ name: 'my-cool-pkg', @@ -110,16 +105,11 @@ t.test('re-loads publishConfig.registry if added during script process', (t) => } const publish = new Publish(npm) - publish.exec([testDir], (er) => { - if (er) - throw er - t.pass('got to callback') - t.end() - }) + await publish.exec([testDir]) }) -t.test('if loglevel=info and json, should not output package contents', (t) => { - t.plan(4) +t.test('if loglevel=info and json, should not output package contents', async t => { + t.plan(3) const testDir = t.testdir({ 'package.json': JSON.stringify({ @@ -129,8 +119,8 @@ t.test('if loglevel=info and json, should not output package contents', (t) => { }) log.level = 'info' - const Publish = t.mock('../../lib/publish.js', { - '../../lib/utils/tar.js': { + const Publish = t.mock('../../../lib/commands/publish.js', { + '../../../lib/utils/tar.js': { getContents: () => ({ id: 'someid', }), @@ -156,16 +146,11 @@ t.test('if loglevel=info and json, should not output package contents', (t) => { } const publish = new Publish(npm) - publish.exec([testDir], (er) => { - if (er) - throw er - t.pass('got to callback') - t.end() - }) + await publish.exec([testDir]) }) -t.test('if loglevel=silent and dry-run, should not output package contents or publish or validate credentials, should log tarball contents', (t) => { - t.plan(2) +t.test('if loglevel=silent and dry-run, should not output package contents or publish or validate credentials, should log tarball contents', async t => { + t.plan(1) const testDir = t.testdir({ 'package.json': JSON.stringify({ @@ -175,8 +160,8 @@ t.test('if loglevel=silent and dry-run, should not output package contents or pu }) log.level = 'silent' - const Publish = t.mock('../../lib/publish.js', { - '../../lib/utils/tar.js': { + const Publish = t.mock('../../../lib/commands/publish.js', { + '../../../lib/utils/tar.js': { getContents: () => ({ id: 'someid', }), @@ -202,16 +187,11 @@ t.test('if loglevel=silent and dry-run, should not output package contents or pu const publish = new Publish(npm) - publish.exec([testDir], (er) => { - if (er) - throw er - t.pass('got to callback') - t.end() - }) + await publish.exec([testDir]) }) -t.test('if loglevel=info and dry-run, should not publish, should log package contents and log tarball contents', (t) => { - t.plan(3) +t.test('if loglevel=info and dry-run, should not publish, should log package contents and log tarball contents', async t => { + t.plan(2) const testDir = t.testdir({ 'package.json': JSON.stringify({ @@ -221,8 +201,8 @@ t.test('if loglevel=info and dry-run, should not publish, should log package con }) log.level = 'info' - const Publish = t.mock('../../lib/publish.js', { - '../../lib/utils/tar.js': { + const Publish = t.mock('../../../lib/commands/publish.js', { + '../../../lib/utils/tar.js': { getContents: () => ({ id: 'someid', }), @@ -247,44 +227,38 @@ t.test('if loglevel=info and dry-run, should not publish, should log package con } const publish = new Publish(npm) - publish.exec([testDir], (er) => { - if (er) - throw er - t.pass('got to callback') - t.end() - }) + await publish.exec([testDir]) }) -t.test('shows usage with wrong set of arguments', (t) => { +t.test('shows usage with wrong set of arguments', async t => { t.plan(1) - const Publish = t.mock('../../lib/publish.js') + const Publish = t.mock('../../../lib/commands/publish.js') const publish = new Publish({}) - publish.exec(['a', 'b', 'c'], (er) => { - t.matchSnapshot(er, 'should print usage') - t.end() - }) + await t.rejects( + publish.exec(['a', 'b', 'c']), + publish.usage + ) }) -t.test('throws when invalid tag', (t) => { +t.test('throws when invalid tag', async t => { t.plan(1) - const Publish = t.mock('../../lib/publish.js') + const Publish = t.mock('../../../lib/commands/publish.js') const npm = mockNpm({ config: { tag: '0.0.13' }, }) const publish = new Publish(npm) - publish.exec([], (err) => { - t.match(err, { - message: /Tag name must not be a valid SemVer range: /, - }, 'throws when tag name is a valid SemVer range') - t.end() - }) + await t.rejects( + publish.exec([]), + /Tag name must not be a valid SemVer range: /, + 'throws when tag name is a valid SemVer range' + ) }) -t.test('can publish a tarball', t => { - t.plan(4) +t.test('can publish a tarball', async t => { + t.plan(3) const testDir = t.testdir({ tarball: {}, @@ -303,7 +277,7 @@ t.test('can publish a tarball', t => { }, ['package']) const tarFile = fs.readFileSync(`${testDir}/tarball/package.tgz`) - const Publish = t.mock('../../lib/publish.js', { + const Publish = t.mock('../../../lib/commands/publish.js', { libnpmpublish: { publish: (manifest, tarData, opts) => { t.match(manifest, { @@ -321,17 +295,12 @@ t.test('can publish a tarball', t => { } const publish = new Publish(npm) - publish.exec([`${testDir}/tarball/package.tgz`], (er) => { - if (er) - throw er - t.pass('got to callback') - t.end() - }) + await publish.exec([`${testDir}/tarball/package.tgz`]) }) -t.test('should check auth for default registry', t => { +t.test('should check auth for default registry', async t => { t.plan(2) - const Publish = t.mock('../../lib/publish.js') + const Publish = t.mock('../../../lib/commands/publish.js') const npm = mockNpm() npm.config.getCredentialsByURI = (uri) => { t.same(uri, npm.config.get('registry'), 'gets credentials for expected registry') @@ -339,19 +308,17 @@ t.test('should check auth for default registry', t => { } const publish = new Publish(npm) - publish.exec([], (err) => { - t.match(err, { - message: 'This command requires you to be logged in.', - code: 'ENEEDAUTH', - }, 'throws when not logged in') - t.end() - }) + await t.rejects( + publish.exec([]), + { message: 'This command requires you to be logged in.', code: 'ENEEDAUTH' }, + 'throws when not logged in' + ) }) -t.test('should check auth for configured registry', t => { +t.test('should check auth for configured registry', async t => { t.plan(2) const registry = 'https://some.registry' - const Publish = t.mock('../../lib/publish.js') + const Publish = t.mock('../../../lib/commands/publish.js') const npm = mockNpm({ flatOptions: { registry }, }) @@ -361,16 +328,14 @@ t.test('should check auth for configured registry', t => { } const publish = new Publish(npm) - publish.exec([], (err) => { - t.match(err, { - message: 'This command requires you to be logged in.', - code: 'ENEEDAUTH', - }, 'throws when not logged in') - t.end() - }) + await t.rejects( + publish.exec([]), + { message: 'This command requires you to be logged in.', code: 'ENEEDAUTH' }, + 'throws when not logged in' + ) }) -t.test('should check auth for scope specific registry', t => { +t.test('should check auth for scope specific registry', async t => { t.plan(2) const registry = 'https://some.registry' const testDir = t.testdir({ @@ -380,7 +345,7 @@ t.test('should check auth for scope specific registry', t => { }, null, 2), }) - const Publish = t.mock('../../lib/publish.js') + const Publish = t.mock('../../../lib/commands/publish.js') const npm = mockNpm({ flatOptions: { '@npm:registry': registry }, }) @@ -390,17 +355,15 @@ t.test('should check auth for scope specific registry', t => { } const publish = new Publish(npm) - publish.exec([testDir], (err) => { - t.match(err, { - message: 'This command requires you to be logged in.', - code: 'ENEEDAUTH', - }, 'throws when not logged in') - t.end() - }) + await t.rejects( + publish.exec([testDir]), + { message: 'This command requires you to be logged in.', code: 'ENEEDAUTH' }, + 'throws when not logged in' + ) }) -t.test('should use auth for scope specific registry', t => { - t.plan(4) +t.test('should use auth for scope specific registry', async t => { + t.plan(3) const registry = 'https://some.registry' const testDir = t.testdir({ 'package.json': JSON.stringify({ @@ -409,7 +372,7 @@ t.test('should use auth for scope specific registry', t => { }, null, 2), }) - const Publish = t.mock('../../lib/publish.js', { + const Publish = t.mock('../../../lib/commands/publish.js', { libnpmpublish: { publish: (manifest, tarData, opts) => { t.ok(opts, 'gets opts object') @@ -426,16 +389,11 @@ t.test('should use auth for scope specific registry', t => { } const publish = new Publish(npm) - publish.exec([testDir], (er) => { - if (er) - throw er - t.pass('got to callback') - t.end() - }) + await publish.exec([testDir]) }) -t.test('read registry only from publishConfig', t => { - t.plan(4) +t.test('read registry only from publishConfig', async t => { + t.plan(3) const registry = 'https://some.registry' const publishConfig = { registry } @@ -447,7 +405,7 @@ t.test('read registry only from publishConfig', t => { }, null, 2), }) - const Publish = t.mock('../../lib/publish.js', { + const Publish = t.mock('../../../lib/commands/publish.js', { libnpmpublish: { publish: (manifest, tarData, opts) => { t.match(manifest, { name: 'my-cool-pkg', version: '1.0.0' }, 'gets manifest') @@ -462,16 +420,11 @@ t.test('read registry only from publishConfig', t => { } const publish = new Publish(npm) - publish.exec([testDir], (er) => { - if (er) - throw er - t.pass('got to callback') - t.end() - }) + await publish.exec([testDir]) }) -t.test('able to publish after if encountered multiple configs', t => { - t.plan(3) +t.test('able to publish after if encountered multiple configs', async t => { + t.plan(2) const registry = 'https://some.registry' const tag = 'better-tag' @@ -491,7 +444,7 @@ t.test('able to publish after if encountered multiple configs', t => { })) configList.unshift(Object.assign(Object.create(configList[0]), { tag })) - const Publish = t.mock('../../lib/publish.js', { + const Publish = t.mock('../../../lib/commands/publish.js', { libnpmpublish: { publish: (manifest, tarData, opts) => { t.same(opts.defaultTag, tag, 'gets option for expected tag') @@ -514,12 +467,7 @@ t.test('able to publish after if encountered multiple configs', t => { }, }) - publish.exec([testDir], (er) => { - if (er) - throw er - t.pass('got to callback') - t.end() - }) + await publish.exec([testDir]) }) t.test('workspaces', (t) => { @@ -558,8 +506,8 @@ t.test('workspaces', (t) => { outputs.length = 0 publishes.length = 0 }) - const Publish = t.mock('../../lib/publish.js', { - '../../lib/utils/tar.js': { + const Publish = t.mock('../../../lib/commands/publish.js', { + '../../../lib/utils/tar.js': { getContents: (manifest) => ({ id: manifest._id, }), @@ -582,48 +530,42 @@ t.test('workspaces', (t) => { } const publish = new Publish(npm) - t.test('all workspaces', (t) => { + t.test('all workspaces', async t => { log.level = 'info' - publish.execWorkspaces([], [], (err) => { - t.notOk(err) - t.matchSnapshot(publishes, 'should publish all workspaces') - t.matchSnapshot(outputs, 'should output all publishes') - t.end() - }) + await publish.execWorkspaces([], []) + t.matchSnapshot(publishes, 'should publish all workspaces') + t.matchSnapshot(outputs, 'should output all publishes') }) - t.test('one workspace', t => { + t.test('one workspace', async t => { log.level = 'info' - publish.execWorkspaces([], ['workspace-a'], (err) => { - t.notOk(err) - t.matchSnapshot(publishes, 'should publish given workspace') - t.matchSnapshot(outputs, 'should output one publish') - t.end() - }) + await publish.execWorkspaces([], ['workspace-a']) + t.matchSnapshot(publishes, 'should publish given workspace') + t.matchSnapshot(outputs, 'should output one publish') }) - t.test('invalid workspace', t => { - publish.execWorkspaces([], ['workspace-x'], (err) => { - t.match(err, /No workspaces found/) - t.match(err, /workspace-x/) - t.end() - }) + t.test('invalid workspace', async t => { + await t.rejects( + publish.execWorkspaces([], ['workspace-x']), + /No workspaces found/ + ) + await t.rejects( + publish.execWorkspaces([], ['workspace-x']), + /workspace-x/ + ) }) - t.test('json', t => { + t.test('json', async t => { log.level = 'info' npm.config.set('json', true) - publish.execWorkspaces([], [], (err) => { - t.notOk(err) - t.matchSnapshot(publishes, 'should publish all workspaces') - t.matchSnapshot(outputs, 'should output all publishes as json') - t.end() - }) + await publish.execWorkspaces([], []) + t.matchSnapshot(publishes, 'should publish all workspaces') + t.matchSnapshot(outputs, 'should output all publishes as json') }) t.end() }) -t.test('private workspaces', (t) => { +t.test('private workspaces', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'workspaces-project', @@ -655,7 +597,7 @@ t.test('private workspaces', (t) => { publishes.length = 0 }) const mocks = { - '../../lib/utils/tar.js': { + '../../../lib/utils/tar.js': { getContents: (manifest) => ({ id: manifest._id, }), @@ -683,8 +625,8 @@ t.test('private workspaces', (t) => { return { token: 'some.registry.token' } } - t.test('with color', t => { - const Publish = t.mock('../../lib/publish.js', { + t.test('with color', async t => { + const Publish = t.mock('../../../lib/commands/publish.js', { ...mocks, npmlog: { notice () {}, @@ -702,17 +644,14 @@ t.test('private workspaces', (t) => { const publish = new Publish(npm) npm.color = true - publish.execWorkspaces([], [], (err) => { - t.notOk(err) - t.matchSnapshot(publishes, 'should publish all non-private workspaces') - t.matchSnapshot(outputs, 'should output all publishes') - npm.color = false - t.end() - }) + await publish.execWorkspaces([], []) + t.matchSnapshot(publishes, 'should publish all non-private workspaces') + t.matchSnapshot(outputs, 'should output all publishes') + npm.color = false }) - t.test('colorless', t => { - const Publish = t.mock('../../lib/publish.js', { + t.test('colorless', async t => { + const Publish = t.mock('../../../lib/commands/publish.js', { ...mocks, npmlog: { notice () {}, @@ -729,16 +668,13 @@ t.test('private workspaces', (t) => { }) const publish = new Publish(npm) - publish.execWorkspaces([], [], (err) => { - t.notOk(err) - t.matchSnapshot(publishes, 'should publish all non-private workspaces') - t.matchSnapshot(outputs, 'should output all publishes') - t.end() - }) + await publish.execWorkspaces([], []) + t.matchSnapshot(publishes, 'should publish all non-private workspaces') + t.matchSnapshot(outputs, 'should output all publishes') }) - t.test('unexpected error', t => { - const Publish = t.mock('../../lib/publish.js', { + t.test('unexpected error', async t => { + const Publish = t.mock('../../../lib/commands/publish.js', { ...mocks, libnpmpublish: { publish: (manifest, tarballData, opts) => { @@ -755,20 +691,17 @@ t.test('private workspaces', (t) => { }) const publish = new Publish(npm) - publish.execWorkspaces([], [], (err) => { - t.match( - err, - /ERR/, - 'should throw unexpected error' - ) - t.end() - }) + await t.rejects( + publish.execWorkspaces([], []), + /ERR/, + 'should throw unexpected error' + ) }) t.end() }) -t.test('runs correct lifecycle scripts', t => { +t.test('runs correct lifecycle scripts', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'my-cool-pkg', @@ -783,11 +716,11 @@ t.test('runs correct lifecycle scripts', t => { }) const scripts = [] - const Publish = t.mock('../../lib/publish.js', { + const Publish = t.mock('../../../lib/commands/publish.js', { '@npmcli/run-script': (args) => { scripts.push(args) }, - '../../lib/utils/tar.js': { + '../../../lib/utils/tar.js': { getContents: () => ({ id: 'someid', }), @@ -811,19 +744,15 @@ t.test('runs correct lifecycle scripts', t => { return { token: 'some.registry.token' } } const publish = new Publish(npm) - publish.exec([testDir], (er) => { - if (er) - throw er - t.same( - scripts.map(s => s.event), - ['prepublishOnly', 'publish', 'postpublish'], - 'runs only expected scripts, in order' - ) - t.end() - }) + await publish.exec([testDir]) + t.same( + scripts.map(s => s.event), + ['prepublishOnly', 'publish', 'postpublish'], + 'runs only expected scripts, in order' + ) }) -t.test('does not run scripts on --ignore-scripts', t => { +t.test('does not run scripts on --ignore-scripts', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'my-cool-pkg', @@ -831,11 +760,11 @@ t.test('does not run scripts on --ignore-scripts', t => { }, null, 2), }) - const Publish = t.mock('../../lib/publish.js', { + const Publish = t.mock('../../../lib/commands/publish.js', { '@npmcli/run-script': () => { t.fail('should not call run-script') }, - '../../lib/utils/tar.js': { + '../../../lib/utils/tar.js': { getContents: () => ({ id: 'someid', }), @@ -860,10 +789,5 @@ t.test('does not run scripts on --ignore-scripts', t => { return { token: 'some.registry.token' } } const publish = new Publish(npm) - publish.exec([testDir], (er) => { - if (er) - throw er - t.pass('got to callback') - t.end() - }) + await publish.exec([testDir]) }) diff --git a/deps/npm/test/lib/rebuild.js b/deps/npm/test/lib/commands/rebuild.js similarity index 67% rename from deps/npm/test/lib/rebuild.js rename to deps/npm/test/lib/commands/rebuild.js index 81768a21fb3b7a..3bfd3707f588c7 100644 --- a/deps/npm/test/lib/rebuild.js +++ b/deps/npm/test/lib/commands/rebuild.js @@ -1,7 +1,7 @@ const t = require('tap') const fs = require('fs') const { resolve } = require('path') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') let result = '' @@ -16,7 +16,7 @@ const npm = mockNpm({ result += msg.join('\n') }, }) -const Rebuild = require('../../lib/rebuild.js') +const Rebuild = require('../../../lib/commands/rebuild.js') const rebuild = new Rebuild(npm) t.afterEach(() => { @@ -26,7 +26,7 @@ t.afterEach(() => { result = '' }) -t.test('no args', t => { +t.test('no args', async t => { const path = t.testdir({ node_modules: { a: { @@ -63,26 +63,21 @@ t.test('no args', t => { npm.prefix = path - rebuild.exec([], err => { - if (err) - throw err + await rebuild.exec([]) - t.ok(() => fs.statSync(aBuildFile)) - t.ok(() => fs.statSync(bBuildFile)) - t.ok(() => fs.statSync(aBinFile)) - t.ok(() => fs.statSync(bBinFile)) + t.ok(() => fs.statSync(aBuildFile)) + t.ok(() => fs.statSync(bBuildFile)) + t.ok(() => fs.statSync(aBinFile)) + t.ok(() => fs.statSync(bBinFile)) - t.equal( - result, - 'rebuilt dependencies successfully', - 'should output success msg' - ) - - t.end() - }) + t.equal( + result, + 'rebuilt dependencies successfully', + 'should output success msg' + ) }) -t.test('filter by pkg name', t => { +t.test('filter by pkg name', async t => { const path = t.testdir({ node_modules: { a: { @@ -111,18 +106,13 @@ t.test('filter by pkg name', t => { t.throws(() => fs.statSync(aBinFile)) t.throws(() => fs.statSync(bBinFile)) - rebuild.exec(['b'], err => { - if (err) - throw err + await rebuild.exec(['b']) - t.throws(() => fs.statSync(aBinFile), 'should not link a bin') - t.ok(() => fs.statSync(bBinFile), 'should link filtered pkg bin') - - t.end() - }) + t.throws(() => fs.statSync(aBinFile), 'should not link a bin') + t.ok(() => fs.statSync(bBinFile), 'should link filtered pkg bin') }) -t.test('filter by pkg@', t => { +t.test('filter by pkg@', async t => { const path = t.testdir({ node_modules: { a: { @@ -159,18 +149,13 @@ t.test('filter by pkg@', t => { const bBinFile = resolve(path, 'node_modules/.bin/b') const nestedBinFile = resolve(path, 'node_modules/a/node_modules/.bin/b') - rebuild.exec(['b@2'], err => { - if (err) - throw err + await rebuild.exec(['b@2']) - t.throws(() => fs.statSync(bBinFile), 'should not link b bin') - t.ok(() => fs.statSync(nestedBinFile), 'should link filtered pkg bin') - - t.end() - }) + t.throws(() => fs.statSync(bBinFile), 'should not link b bin') + t.ok(() => fs.statSync(nestedBinFile), 'should link filtered pkg bin') }) -t.test('filter by directory', t => { +t.test('filter by directory', async t => { const path = t.testdir({ node_modules: { a: { @@ -199,30 +184,21 @@ t.test('filter by directory', t => { t.throws(() => fs.statSync(aBinFile)) t.throws(() => fs.statSync(bBinFile)) - rebuild.exec(['file:node_modules/b'], err => { - if (err) - throw err - - t.throws(() => fs.statSync(aBinFile), 'should not link a bin') - t.ok(() => fs.statSync(bBinFile), 'should link filtered pkg bin') + await rebuild.exec(['file:node_modules/b']) - t.end() - }) + t.throws(() => fs.statSync(aBinFile), 'should not link a bin') + t.ok(() => fs.statSync(bBinFile), 'should link filtered pkg bin') }) -t.test('filter must be a semver version/range, or directory', t => { - rebuild.exec(['git+ssh://github.com/npm/arborist'], err => { - t.match( - err, - /Error: `npm rebuild` only supports SemVer version\/range specifiers/, - 'should throw type error' - ) - - t.end() - }) +t.test('filter must be a semver version/range, or directory', async t => { + await t.rejects( + rebuild.exec(['git+ssh://github.com/npm/arborist']), + /`npm rebuild` only supports SemVer version\/range specifiers/, + 'should throw type error' + ) }) -t.test('global prefix', t => { +t.test('global prefix', async t => { const globalPath = t.testdir({ lib: { node_modules: { @@ -241,18 +217,12 @@ t.test('global prefix', t => { config.global = true npm.globalDir = resolve(globalPath, 'lib', 'node_modules') - rebuild.exec([], err => { - if (err) - throw err + await rebuild.exec([]) + t.ok(() => fs.statSync(resolve(globalPath, 'lib/node_modules/.bin/a'))) - t.ok(() => fs.statSync(resolve(globalPath, 'lib/node_modules/.bin/a'))) - - t.equal( - result, - 'rebuilt dependencies successfully', - 'should output success msg' - ) - - t.end() - }) + t.equal( + result, + 'rebuilt dependencies successfully', + 'should output success msg' + ) }) diff --git a/deps/npm/test/lib/repo.js b/deps/npm/test/lib/commands/repo.js similarity index 95% rename from deps/npm/test/lib/repo.js rename to deps/npm/test/lib/commands/repo.js index 41bff27447f1dd..9a7c4a95096cd7 100644 --- a/deps/npm/test/lib/repo.js +++ b/deps/npm/test/lib/commands/repo.js @@ -1,5 +1,5 @@ const t = require('tap') -const { real: mockNpm } = require('../fixtures/mock-npm.js') +const { real: mockNpm } = require('../../fixtures/mock-npm.js') const { join, sep } = require('path') const pkgDirs = t.testdir({ @@ -186,9 +186,11 @@ const openUrl = async (npm, url, errMsg) => { opened[url]++ } -const { command, npm } = mockNpm(t, { +const { Npm } = mockNpm(t, { '../../lib/utils/open-url.js': openUrl, }) +const npm = new Npm() + t.before(async () => { await npm.load() }) @@ -227,7 +229,7 @@ t.test('open repo urls', t => { t.plan(keys.length) keys.forEach(pkg => { t.test(pkg, async t => { - await command('repo', [['.', pkg].join(sep)]) + await npm.exec('repo', [['.', pkg].join(sep)]) const url = expect[pkg] t.match({ [url]: 1, @@ -251,7 +253,7 @@ t.test('fail if cannot figure out repo url', t => { cases.forEach(pkg => { t.test(pkg, async t => { t.rejects( - command('repo', [['.', pkg].join(sep)]), + npm.exec('repo', [['.', pkg].join(sep)]), { pkgid: pkg } ) }) @@ -260,7 +262,7 @@ t.test('fail if cannot figure out repo url', t => { t.test('open default package if none specified', async t => { npm.localPrefix = pkgDirs - await command('repo', []) + await npm.exec('repo', []) t.equal(opened['https://example.com/thispkg'], 1, 'opened expected url', {opened}) }) @@ -276,7 +278,7 @@ t.test('workspaces', t => { t.test('include workspace root', async (t) => { npm.config.set('workspaces', true) npm.config.set('include-workspace-root', true) - await command('repo', []) + await npm.exec('repo', []) t.match({ 'https://github.com/npm/workspaces-test': 1, 'https://repo.workspace-a/': 1, // Gets translated to https! @@ -286,7 +288,7 @@ t.test('workspaces', t => { t.test('all workspaces', async (t) => { npm.config.set('workspaces', true) - await command('repo', []) + await npm.exec('repo', []) t.match({ 'https://repo.workspace-a/': 1, // Gets translated to https! 'https://github.com/npm/workspace-b': 1, @@ -295,7 +297,7 @@ t.test('workspaces', t => { t.test('one workspace', async (t) => { npm.config.set('workspace', ['workspace-a']) - await command('repo', []) + await npm.exec('repo', []) t.match({ 'https://repo.workspace-a/': 1, }, opened, 'opened one requested repo urls') @@ -304,7 +306,7 @@ t.test('workspaces', t => { t.test('invalid workspace', async (t) => { npm.config.set('workspace', ['workspace-x']) await t.rejects( - command('repo', []), + npm.exec('repo', []), /workspace-x/ ) t.match({}, opened, 'opened no repo urls') diff --git a/deps/npm/test/lib/restart.js b/deps/npm/test/lib/commands/restart.js similarity index 86% rename from deps/npm/test/lib/restart.js rename to deps/npm/test/lib/commands/restart.js index 153c31447282cd..608de0331deefe 100644 --- a/deps/npm/test/lib/restart.js +++ b/deps/npm/test/lib/commands/restart.js @@ -1,6 +1,6 @@ const t = require('tap') const spawk = require('spawk') -const { real: mockNpm } = require('../fixtures/mock-npm') +const { real: mockNpm } = require('../../fixtures/mock-npm') spawk.preventUnmatched() t.teardown(() => { @@ -22,7 +22,8 @@ t.test('should run stop script from package.json', async t => { }, }), }) - const { command, npm } = mockNpm(t) + const { Npm } = mockNpm(t) + const npm = new Npm() await npm.load() npm.log.level = 'silent' npm.localPrefix = prefix @@ -31,6 +32,6 @@ t.test('should run stop script from package.json', async t => { t.ok(args.includes('node ./test-restart.js "foo"'), 'ran stop script with extra args') return true }) - await command('restart', ['foo']) + await npm.exec('restart', ['foo']) t.ok(script.called, 'script ran') }) diff --git a/deps/npm/test/lib/commands/root.js b/deps/npm/test/lib/commands/root.js new file mode 100644 index 00000000000000..9871ddb25dc675 --- /dev/null +++ b/deps/npm/test/lib/commands/root.js @@ -0,0 +1,13 @@ +const t = require('tap') +const { real: mockNpm } = require('../../fixtures/mock-npm') + +t.test('prefix', async (t) => { + const { joinedOutput, Npm } = mockNpm(t) + const npm = new Npm() + await npm.exec('root', []) + t.equal( + joinedOutput(), + npm.dir, + 'outputs npm.dir' + ) +}) diff --git a/deps/npm/test/lib/commands/run-script.js b/deps/npm/test/lib/commands/run-script.js new file mode 100644 index 00000000000000..6b3b40055c3621 --- /dev/null +++ b/deps/npm/test/lib/commands/run-script.js @@ -0,0 +1,892 @@ +const t = require('tap') +const { resolve } = require('path') +const { fake: mockNpm } = require('../../fixtures/mock-npm') + +const normalizePath = p => p + .replace(/\\+/g, '/') + .replace(/\r\n/g, '\n') + +const cleanOutput = (str) => normalizePath(str) + .replace(normalizePath(process.cwd()), '{CWD}') + +const RUN_SCRIPTS = [] +const flatOptions = { + scriptShell: undefined, +} +const config = { + json: false, + parseable: false, + 'if-present': false, +} + +const npm = mockNpm({ + localPrefix: __dirname, + flatOptions, + config, + cmd: (c) => { + return { description: `test ${c} description` } + }, + output: (...msg) => output.push(msg), +}) + +const output = [] + +const npmlog = { + disableProgress: () => null, + level: 'warn', + error: () => null, +} + +t.afterEach(() => { + npm.color = false + npmlog.level = 'warn' + npmlog.error = () => null + output.length = 0 + RUN_SCRIPTS.length = 0 + config['if-present'] = false + config.json = false + config.parseable = false +}) + +const getRS = windows => { + const RunScript = t.mock('../../../lib/commands/run-script.js', { + '@npmcli/run-script': Object.assign(async opts => { + RUN_SCRIPTS.push(opts) + }, { + isServerPackage: require('@npmcli/run-script').isServerPackage, + }), + npmlog, + '../../../lib/utils/is-windows-shell.js': windows, + }) + return new RunScript(npm) +} + +const runScript = getRS(false) +const runScriptWin = getRS(true) + +const { writeFileSync } = require('fs') +t.test('completion', t => { + const dir = t.testdir() + npm.localPrefix = dir + t.test('already have a script name', async t => { + const res = await runScript.completion({conf: {argv: {remain: ['npm', 'run', 'x']}}}) + t.equal(res, undefined) + t.end() + }) + t.test('no package.json', async t => { + const res = await runScript.completion({conf: {argv: {remain: ['npm', 'run']}}}) + t.strictSame(res, []) + t.end() + }) + t.test('has package.json, no scripts', async t => { + writeFileSync(`${dir}/package.json`, JSON.stringify({})) + const res = await runScript.completion({conf: {argv: {remain: ['npm', 'run']}}}) + t.strictSame(res, []) + t.end() + }) + t.test('has package.json, with scripts', async t => { + writeFileSync(`${dir}/package.json`, JSON.stringify({ + scripts: { hello: 'echo hello', world: 'echo world' }, + })) + const res = await runScript.completion({conf: {argv: {remain: ['npm', 'run']}}}) + t.strictSame(res, ['hello', 'world']) + t.end() + }) + t.end() +}) + +t.test('fail if no package.json', async t => { + t.plan(2) + npm.localPrefix = t.testdir() + await t.rejects( + runScript.exec([]), + { code: 'ENOENT' } + ) + await t.rejects( + runScript.exec(['test']), + { code: 'ENOENT' } + ) +}) + +t.test('default env, start, and restart scripts', t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ name: 'x', version: '1.2.3' }), + 'server.js': 'console.log("hello, world")', + }) + + t.test('start', async t => { + await runScript.exec(['start']) + t.match(RUN_SCRIPTS, [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { name: 'x', version: '1.2.3', _id: 'x@1.2.3', scripts: {}}, + event: 'start', + }, + ]) + }) + + t.test('env', async t => { + await runScript.exec(['env']) + t.match(RUN_SCRIPTS, [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { + name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + env: 'env', + }, + }, + event: 'env', + }, + ]) + }) + + t.test('windows env', async t => { + await runScriptWin.exec(['env']) + t.match(RUN_SCRIPTS, [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + env: 'SET', + } }, + event: 'env', + }, + ]) + }) + + t.test('restart', async t => { + await runScript.exec(['restart']) + + t.match(RUN_SCRIPTS, [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + restart: 'npm stop --if-present && npm start', + } }, + event: 'restart', + }, + ]) + }) + t.end() +}) + +t.test('non-default env script', t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { + env: 'hello', + }, + }), + }) + + t.test('env', async t => { + await runScript.exec(['env']) + t.match(RUN_SCRIPTS, [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { + name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + env: 'hello', + }, + }, + event: 'env', + }, + ]) + }) + + t.test('env windows', async t => { + await runScriptWin.exec(['env']) + t.match(RUN_SCRIPTS, [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + env: 'hello', + }, + }, + event: 'env', + }, + ]) + }) + t.end() +}) + +t.test('try to run missing script', t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + scripts: { hello: 'world' }, + bin: { goodnight: 'moon' }, + }), + }) + t.test('no suggestions', async t => { + await t.rejects( + runScript.exec(['notevenclose']), + 'Missing script: "notevenclose"' + ) + }) + t.test('script suggestions', async t => { + await t.rejects( + runScript.exec(['helo']), + /Missing script: "helo"/ + ) + await t.rejects( + runScript.exec(['helo']), + /npm run hello/ + ) + }) + t.test('bin suggestions', async t => { + await t.rejects( + runScript.exec(['goodneght']), + /Missing script: "goodneght"/ + ) + await t.rejects( + runScript.exec(['goodneght']), + /npm exec goodnight/ + ) + }) + t.test('with --if-present', async t => { + config['if-present'] = true + await runScript.exec(['goodbye']) + t.strictSame(RUN_SCRIPTS, [], 'did not try to run anything') + }) + t.end() +}) + +t.test('run pre/post hooks', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { + preenv: 'echo before the env', + postenv: 'echo after the env', + }, + }), + }) + + await runScript.exec(['env']) + + t.match(RUN_SCRIPTS, [ + { event: 'preenv' }, + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + env: 'env', + } }, + event: 'env', + }, + { event: 'postenv' }, + ]) +}) + +t.test('skip pre/post hooks when using ignoreScripts', async t => { + config['ignore-scripts'] = true + + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { + preenv: 'echo before the env', + postenv: 'echo after the env', + }, + }), + }) + + await runScript.exec(['env']) + + t.same(RUN_SCRIPTS, [ + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + preenv: 'echo before the env', + postenv: 'echo after the env', + env: 'env', + } }, + banner: true, + event: 'env', + }, + ]) + delete config['ignore-scripts'] +}) + +t.test('run silent', async t => { + npmlog.level = 'silent' + t.teardown(() => { + npmlog.level = 'warn' + }) + + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { + preenv: 'echo before the env', + postenv: 'echo after the env', + }, + }), + }) + + await runScript.exec(['env']) + t.match(RUN_SCRIPTS, [ + { + event: 'preenv', + stdio: 'inherit', + }, + { + path: npm.localPrefix, + args: [], + scriptShell: undefined, + stdio: 'inherit', + stdioString: true, + pkg: { name: 'x', + version: '1.2.3', + _id: 'x@1.2.3', + scripts: { + env: 'env', + } }, + event: 'env', + banner: false, + }, + { + event: 'postenv', + stdio: 'inherit', + }, + ]) +}) + +t.test('list scripts', t => { + const scripts = { + test: 'exit 2', + start: 'node server.js', + stop: 'node kill-server.js', + preenv: 'echo before the env', + postenv: 'echo after the env', + } + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts, + }), + }) + + t.test('no args', async t => { + await runScript.exec([]) + t.strictSame(output, [ + ['Lifecycle scripts included in x@1.2.3:'], + [' test\n exit 2'], + [' start\n node server.js'], + [' stop\n node kill-server.js'], + ['\navailable via `npm run-script`:'], + [' preenv\n echo before the env'], + [' postenv\n echo after the env'], + [''], + ], 'basic report') + }) + + t.test('silent', async t => { + npmlog.level = 'silent' + await runScript.exec([]) + t.strictSame(output, []) + }) + t.test('warn json', async t => { + npmlog.level = 'warn' + config.json = true + await runScript.exec([]) + t.strictSame(output, [[JSON.stringify(scripts, 0, 2)]], 'json report') + }) + + t.test('parseable', async t => { + config.parseable = true + await runScript.exec([]) + t.strictSame(output, [ + ['test:exit 2'], + ['start:node server.js'], + ['stop:node kill-server.js'], + ['preenv:echo before the env'], + ['postenv:echo after the env'], + ]) + }) + t.end() +}) + +t.test('list scripts when no scripts', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + }), + }) + + await runScript.exec([]) + t.strictSame(output, [], 'nothing to report') +}) + +t.test('list scripts, only commands', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { preversion: 'echo doing the version dance' }, + }), + }) + + await runScript.exec([]) + t.strictSame(output, [ + ['Lifecycle scripts included in x@1.2.3:'], + [' preversion\n echo doing the version dance'], + [''], + ]) +}) + +t.test('list scripts, only non-commands', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + scripts: { glorp: 'echo doing the glerp glop' }, + }), + }) + + await runScript.exec([]) + t.strictSame(output, [ + ['Scripts available in x@1.2.3 via `npm run-script`:'], + [' glorp\n echo doing the glerp glop'], + [''], + ]) +}) + +t.test('workspaces', t => { + npm.localPrefix = t.testdir({ + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + scripts: { glorp: 'echo a doing the glerp glop' }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '2.0.0', + scripts: { glorp: 'echo b doing the glerp glop' }, + }), + }, + c: { + 'package.json': JSON.stringify({ + name: 'c', + version: '1.0.0', + scripts: { + test: 'exit 0', + posttest: 'echo posttest', + lorem: 'echo c lorem', + }, + }), + }, + d: { + 'package.json': JSON.stringify({ + name: 'd', + version: '1.0.0', + scripts: { + test: 'exit 0', + posttest: 'echo posttest', + }, + }), + }, + e: { + 'package.json': JSON.stringify({ + name: 'e', + scripts: { test: 'exit 0', start: 'echo start something' }, + }), + }, + noscripts: { + 'package.json': JSON.stringify({ + name: 'noscripts', + version: '1.0.0', + }), + }, + }, + 'package.json': JSON.stringify({ + name: 'x', + version: '1.2.3', + workspaces: ['packages/*'], + }), + }) + + t.test('list all scripts', async t => { + await runScript.execWorkspaces([], []) + t.strictSame(output, [ + ['Scripts available in a@1.0.0 via `npm run-script`:'], + [' glorp\n echo a doing the glerp glop'], + [''], + ['Scripts available in b@2.0.0 via `npm run-script`:'], + [' glorp\n echo b doing the glerp glop'], + [''], + ['Lifecycle scripts included in c@1.0.0:'], + [' test\n exit 0'], + [' posttest\n echo posttest'], + ['\navailable via `npm run-script`:'], + [' lorem\n echo c lorem'], + [''], + ['Lifecycle scripts included in d@1.0.0:'], + [' test\n exit 0'], + [' posttest\n echo posttest'], + [''], + ['Lifecycle scripts included in e:'], + [' test\n exit 0'], + [' start\n echo start something'], + [''], + ]) + }) + + t.test('list regular scripts, filtered by name', async t => { + await runScript.execWorkspaces([], ['a', 'b']) + t.strictSame(output, [ + ['Scripts available in a@1.0.0 via `npm run-script`:'], + [' glorp\n echo a doing the glerp glop'], + [''], + ['Scripts available in b@2.0.0 via `npm run-script`:'], + [' glorp\n echo b doing the glerp glop'], + [''], + ]) + }) + + t.test('list regular scripts, filtered by path', async t => { + await runScript.execWorkspaces([], ['./packages/a']) + t.strictSame(output, [ + ['Scripts available in a@1.0.0 via `npm run-script`:'], + [' glorp\n echo a doing the glerp glop'], + [''], + ]) + }) + + t.test('list regular scripts, filtered by parent folder', async t => { + await runScript.execWorkspaces([], ['./packages']) + t.strictSame(output, [ + ['Scripts available in a@1.0.0 via `npm run-script`:'], + [' glorp\n echo a doing the glerp glop'], + [''], + ['Scripts available in b@2.0.0 via `npm run-script`:'], + [' glorp\n echo b doing the glerp glop'], + [''], + ['Lifecycle scripts included in c@1.0.0:'], + [' test\n exit 0'], + [' posttest\n echo posttest'], + ['\navailable via `npm run-script`:'], + [' lorem\n echo c lorem'], + [''], + ['Lifecycle scripts included in d@1.0.0:'], + [' test\n exit 0'], + [' posttest\n echo posttest'], + [''], + ['Lifecycle scripts included in e:'], + [' test\n exit 0'], + [' start\n echo start something'], + [''], + ]) + }) + + t.test('list all scripts with colors', async t => { + npm.color = true + await runScript.execWorkspaces([], []) + t.strictSame(output, [ + [ + '\u001b[1mScripts\u001b[22m available in \x1B[32ma@1.0.0\x1B[39m via `\x1B[34mnpm run-script\x1B[39m`:', + ], + [' glorp\n \x1B[2mecho a doing the glerp glop\x1B[22m'], + [''], + [ + '\u001b[1mScripts\u001b[22m available in \x1B[32mb@2.0.0\x1B[39m via `\x1B[34mnpm run-script\x1B[39m`:', + ], + [' glorp\n \x1B[2mecho b doing the glerp glop\x1B[22m'], + [''], + [ + '\x1B[0m\x1B[1mLifecycle scripts\x1B[22m\x1B[0m included in \x1B[32mc@1.0.0\x1B[39m:', + ], + [' test\n \x1B[2mexit 0\x1B[22m'], + [' posttest\n \x1B[2mecho posttest\x1B[22m'], + ['\navailable via `\x1B[34mnpm run-script\x1B[39m`:'], + [' lorem\n \x1B[2mecho c lorem\x1B[22m'], + [''], + [ + '\x1B[0m\x1B[1mLifecycle scripts\x1B[22m\x1B[0m included in \x1B[32md@1.0.0\x1B[39m:', + ], + [' test\n \x1B[2mexit 0\x1B[22m'], + [' posttest\n \x1B[2mecho posttest\x1B[22m'], + [''], + [ + '\x1B[0m\x1B[1mLifecycle scripts\x1B[22m\x1B[0m included in \x1B[32me\x1B[39m:', + ], + [' test\n \x1B[2mexit 0\x1B[22m'], + [' start\n \x1B[2mecho start something\x1B[22m'], + [''], + ]) + }) + + t.test('list all scripts --json', async t => { + config.json = true + await runScript.execWorkspaces([], []) + t.strictSame(output, [ + [ + '{\n' + + ' "a": {\n' + + ' "glorp": "echo a doing the glerp glop"\n' + + ' },\n' + + ' "b": {\n' + + ' "glorp": "echo b doing the glerp glop"\n' + + ' },\n' + + ' "c": {\n' + + ' "test": "exit 0",\n' + + ' "posttest": "echo posttest",\n' + + ' "lorem": "echo c lorem"\n' + + ' },\n' + + ' "d": {\n' + + ' "test": "exit 0",\n' + + ' "posttest": "echo posttest"\n' + + ' },\n' + + ' "e": {\n' + + ' "test": "exit 0",\n' + + ' "start": "echo start something"\n' + + ' },\n' + + ' "noscripts": {}\n' + + '}', + ], + ]) + }) + + t.test('list all scripts --parseable', async t => { + config.parseable = true + await runScript.execWorkspaces([], []) + t.strictSame(output, [ + ['a:glorp:echo a doing the glerp glop'], + ['b:glorp:echo b doing the glerp glop'], + ['c:test:exit 0'], + ['c:posttest:echo posttest'], + ['c:lorem:echo c lorem'], + ['d:test:exit 0'], + ['d:posttest:echo posttest'], + ['e:test:exit 0'], + ['e:start:echo start something'], + ]) + }) + + t.test('list no scripts --loglevel=silent', async t => { + npmlog.level = 'silent' + await runScript.execWorkspaces([], []) + t.strictSame(output, []) + }) + + t.test('run scripts across all workspaces', async t => { + await runScript.execWorkspaces(['test'], []) + + t.match(RUN_SCRIPTS, [ + { + path: resolve(npm.localPrefix, 'packages/c'), + pkg: { name: 'c', version: '1.0.0' }, + event: 'test', + }, + { + path: resolve(npm.localPrefix, 'packages/c'), + pkg: { name: 'c', version: '1.0.0' }, + event: 'posttest', + }, + { + path: resolve(npm.localPrefix, 'packages/d'), + pkg: { name: 'd', version: '1.0.0' }, + event: 'test', + }, + { + path: resolve(npm.localPrefix, 'packages/d'), + pkg: { name: 'd', version: '1.0.0' }, + event: 'posttest', + }, + { + path: resolve(npm.localPrefix, 'packages/e'), + pkg: { name: 'e' }, + event: 'test', + }, + ]) + }) + + t.test('missing scripts in all workspaces', async t => { + const LOG = [] + npmlog.error = (err) => { + LOG.push(String(err)) + } + await t.rejects( + runScript.execWorkspaces(['missing-script'], []), + /Missing script: missing-script/, + 'should throw missing script error' + ) + + process.exitCode = 0 // clean exit code + + t.match(RUN_SCRIPTS, []) + t.strictSame(LOG.map(cleanOutput), [ + 'Lifecycle script `missing-script` failed with error:', + 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', + ' in workspace: a@1.0.0', + ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/a', + 'Lifecycle script `missing-script` failed with error:', + 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', + ' in workspace: b@2.0.0', + ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/b', + 'Lifecycle script `missing-script` failed with error:', + 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', + ' in workspace: c@1.0.0', + ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/c', + 'Lifecycle script `missing-script` failed with error:', + 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', + ' in workspace: d@1.0.0', + ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/d', + 'Lifecycle script `missing-script` failed with error:', + 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', + ' in workspace: e', + ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/e', + 'Lifecycle script `missing-script` failed with error:', + 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', + ' in workspace: noscripts@1.0.0', + ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/noscripts', + ], 'should log error msgs for each workspace script') + }) + + t.test('missing scripts in some workspaces', async t => { + const LOG = [] + npmlog.error = (err) => { + LOG.push(String(err)) + } + await runScript.execWorkspaces(['test'], ['a', 'b', 'c', 'd']) + t.match(RUN_SCRIPTS, []) + t.strictSame(LOG.map(cleanOutput), [ + 'Lifecycle script `test` failed with error:', + 'Error: Missing script: "test"\n\nTo see a list of scripts, run:\n npm run', + ' in workspace: a@1.0.0', + ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/a', + 'Lifecycle script `test` failed with error:', + 'Error: Missing script: "test"\n\nTo see a list of scripts, run:\n npm run', + ' in workspace: b@2.0.0', + ' at location: {CWD}/test/lib/commands/tap-testdir-run-script-workspaces/packages/b', + ], 'should log error msgs for each workspace script') + }) + + t.test('no workspaces when filtering by user args', async t => { + await t.rejects( + runScript.execWorkspaces([], ['foo', 'bar']), + 'No workspaces found:\n --workspace=foo --workspace=bar', + 'should throw error msg' + ) + }) + + t.test('no workspaces', async t => { + const _prevPrefix = npm.localPrefix + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.0.0', + }), + }) + + await t.rejects( + runScript.execWorkspaces([], []), + /No workspaces found!/, + 'should throw error msg' + ) + npm.localPrefix = _prevPrefix + }) + + t.test('single failed workspace run', async t => { + const RunScript = t.mock('../../../lib/commands/run-script.js', { + '@npmcli/run-script': () => { + throw new Error('err') + }, + npmlog, + '../../../lib/utils/is-windows-shell.js': false, + }) + const runScript = new RunScript(npm) + + await runScript.execWorkspaces(['test'], ['c']) + process.exitCode = 0 // clean up exit code + }) + + t.test('failed workspace run with succeeded runs', async t => { + const RunScript = t.mock('../../../lib/commands/run-script.js', { + '@npmcli/run-script': async opts => { + if (opts.pkg.name === 'a') + throw new Error('ERR') + + RUN_SCRIPTS.push(opts) + }, + npmlog, + '../../../lib/utils/is-windows-shell.js': false, + }) + const runScript = new RunScript(npm) + + await runScript.execWorkspaces(['glorp'], ['a', 'b']) + t.match(RUN_SCRIPTS, [ + { + path: resolve(npm.localPrefix, 'packages/b'), + pkg: { name: 'b', version: '2.0.0' }, + event: 'glorp', + }, + ]) + + process.exitCode = 0 // clean up exit code + }) + + t.end() +}) diff --git a/deps/npm/test/lib/search.js b/deps/npm/test/lib/commands/search.js similarity index 57% rename from deps/npm/test/lib/search.js rename to deps/npm/test/lib/commands/search.js index 55b584b8aa7dc5..a58d5afb9d9945 100644 --- a/deps/npm/test/lib/search.js +++ b/deps/npm/test/lib/commands/search.js @@ -1,8 +1,8 @@ const t = require('tap') const Minipass = require('minipass') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') const libnpmsearchResultFixture = - require('../fixtures/libnpmsearch-stream-result.js') + require('../../fixtures/libnpmsearch-stream-result.js') let result = '' const flatOptions = { @@ -33,7 +33,7 @@ const libnpmsearch = { const mocks = { npmlog, libnpmsearch, - '../../lib/utils/usage.js': () => 'usage instructions', + '../../../lib/utils/usage.js': () => 'usage instructions', } t.afterEach(() => { @@ -43,21 +43,18 @@ t.afterEach(() => { npm.flatOptions = { ...flatOptions } }) -const Search = t.mock('../../lib/search.js', mocks) +const Search = t.mock('../../../lib/commands/search.js', mocks) const search = new Search(npm) -t.test('no args', t => { - search.exec([], err => { - t.match( - err, - /search must be called with arguments/, - 'should throw usage instructions' - ) - t.end() - }) +t.test('no args', async t => { + await t.rejects( + search.exec([]), + /search must be called with arguments/, + 'should throw usage instructions' + ) }) -t.test('search ', t => { +t.test('search ', async t => { const src = new Minipass() src.objectMode = true const libnpmsearch = { @@ -66,28 +63,22 @@ t.test('search ', t => { }, } - const Search = t.mock('../../lib/search.js', { + const Search = t.mock('../../../lib/commands/search.js', { ...mocks, libnpmsearch, }) const search = new Search(npm) - search.exec(['libnpm'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should have expected search results') - - t.end() - }) - for (const i of libnpmsearchResultFixture) src.write(i) src.end() + + await search.exec(['libnpm']) + t.matchSnapshot(result, 'should have expected search results') }) -t.test('search --json', (t) => { +t.test('search --json', async t => { const src = new Minipass() src.objectMode = true @@ -99,38 +90,33 @@ t.test('search --json', (t) => { }, } - const Search = t.mock('../../lib/search.js', { + const Search = t.mock('../../../lib/commands/search.js', { ...mocks, libnpmsearch, }) const search = new Search(npm) - search.exec(['libnpm'], (err) => { - if (err) - throw err - - const parsedResult = JSON.parse(result) - parsedResult.forEach((entry) => { - entry.date = new Date(entry.date) - }) + for (const i of libnpmsearchResultFixture) + src.write(i) - t.same( - parsedResult, - libnpmsearchResultFixture, - 'should have expected search results as json' - ) + src.end() + await search.exec(['libnpm']) - config.json = false - t.end() + const parsedResult = JSON.parse(result) + parsedResult.forEach((entry) => { + entry.date = new Date(entry.date) }) - for (const i of libnpmsearchResultFixture) - src.write(i) + t.same( + parsedResult, + libnpmsearchResultFixture, + 'should have expected search results as json' + ) - src.end() + config.json = false }) -t.test('search --json', (t) => { +t.test('search --json', async t => { const src = new Minipass() src.objectMode = true @@ -142,26 +128,21 @@ t.test('search --json', (t) => { }, } - const Search = t.mock('../../lib/search.js', { + const Search = t.mock('../../../lib/commands/search.js', { ...mocks, libnpmsearch, }) const search = new Search(npm) - search.exec(['foo'], (err) => { - if (err) - throw err - - t.equal(result, '\n[]\n', 'should have expected empty square brackets') + src.end() + await search.exec(['foo']) - config.json = false - t.end() - }) + t.equal(result, '\n[]\n', 'should have expected empty square brackets') - src.end() + config.json = false }) -t.test('search --searchexclude --searchopts', t => { +t.test('search --searchexclude --searchopts', async t => { npm.flatOptions.search = { ...flatOptions.search, exclude: '', @@ -175,21 +156,12 @@ t.test('search --searchexclude --searchopts', t => { }, } - const Search = t.mock('../../lib/search.js', { + const Search = t.mock('../../../lib/commands/search.js', { ...mocks, libnpmsearch, }) const search = new Search(npm) - search.exec(['foo'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should have filtered expected search results') - - t.end() - }) - src.write({ name: 'foo', scope: 'unscoped', @@ -218,9 +190,12 @@ t.test('search --searchexclude --searchopts', t => { }) src.end() + await search.exec(['foo']) + + t.matchSnapshot(result, 'should have filtered expected search results') }) -t.test('empty search results', t => { +t.test('empty search results', async t => { const src = new Minipass() src.objectMode = true const libnpmsearch = { @@ -229,25 +204,19 @@ t.test('empty search results', t => { }, } - const Search = t.mock('../../lib/search.js', { + const Search = t.mock('../../../lib/commands/search.js', { ...mocks, libnpmsearch, }) const search = new Search(npm) - search.exec(['foo'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should have expected search results') - - t.end() - }) - src.end() + await search.exec(['foo']) + + t.matchSnapshot(result, 'should have expected search results') }) -t.test('search api response error', t => { +t.test('search api response error', async t => { const src = new Minipass() src.objectMode = true const libnpmsearch = { @@ -256,23 +225,20 @@ t.test('search api response error', t => { }, } - const Search = t.mock('../../lib/search.js', { + const Search = t.mock('../../../lib/commands/search.js', { ...mocks, libnpmsearch, }) const search = new Search(npm) - search.exec(['foo'], err => { - t.match( - err, - /ERR/, - 'should throw response error' - ) - - t.end() + setImmediate(() => { + src.emit('error', new Error('ERR')) + src.end() }) - src.emit('error', new Error('ERR')) - - src.end() + await t.rejects( + search.exec(['foo']), + /ERR/, + 'should throw response error' + ) }) diff --git a/deps/npm/test/lib/commands/set-script.js b/deps/npm/test/lib/commands/set-script.js new file mode 100644 index 00000000000000..0684ed3a240d46 --- /dev/null +++ b/deps/npm/test/lib/commands/set-script.js @@ -0,0 +1,188 @@ +const t = require('tap') +const fs = require('fs') +const parseJSON = require('json-parse-even-better-errors') +const { fake: mockNpm } = require('../../fixtures/mock-npm') +const { resolve } = require('path') + +const flatOptions = {} +const npm = mockNpm(flatOptions) + +const ERROR_OUTPUT = [] +const WARN_OUTPUT = [] +const SetScript = t.mock('../../../lib/commands/set-script.js', { + npmlog: { + error: (...args) => { + ERROR_OUTPUT.push(args) + }, + warn: (...args) => { + WARN_OUTPUT.push(args) + }, + }, +}) +const setScript = new SetScript(npm) + +t.test('completion', t => { + t.test('already have a script name', async t => { + npm.localPrefix = t.testdir({}) + const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run', 'x']}}}) + t.equal(res, undefined) + t.end() + }) + + t.test('no package.json', async t => { + npm.localPrefix = t.testdir({}) + const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run']}}}) + t.strictSame(res, []) + t.end() + }) + + t.test('has package.json, no scripts', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({}), + }) + const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run']}}}) + t.strictSame(res, []) + t.end() + }) + + t.test('has package.json, with scripts', async t => { + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + scripts: { hello: 'echo hello', world: 'echo world' }, + }), + }) + const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run']}}}) + t.strictSame(res, ['hello', 'world']) + t.end() + }) + + t.end() +}) + +t.test('fails on invalid arguments', async t => { + t.plan(3) + await t.rejects( + setScript.exec(['arg1']), + /Expected 2 arguments: got 1/ + ) + await t.rejects( + setScript.exec(['arg1', 'arg2', 'arg3']), + /Expected 2 arguments: got 3/ + ) + await t.rejects( + setScript.exec(['arg1', 'arg2', 'arg3', 'arg4']), + /Expected 2 arguments: got 4/ + ) +}) + +t.test('fails if run in postinstall script', async t => { + const lifecycleEvent = process.env.npm_lifecycle_event + t.teardown(() => { + process.env.npm_lifecycle_event = lifecycleEvent + }) + + process.env.npm_lifecycle_event = 'postinstall' + t.plan(1) + await t.rejects( + setScript.exec(['arg1', 'arg2']), + /Scripts can’t set from the postinstall script/ + ) +}) + +t.test('fails when package.json not found', async t => { + t.plan(1) + await t.rejects( + setScript.exec(['arg1', 'arg2']), + /package.json not found/ + ) +}) + +t.test('fails on invalid JSON', async t => { + npm.localPrefix = t.testdir({ + 'package.json': 'iamnotjson', + }) + + t.plan(1) + await t.rejects( + setScript.exec(['arg1', 'arg2']), + /Invalid package.json: JSONParseError/ + ) +}) + +t.test('creates scripts object', async t => { + npm.localPrefix = t.testdir({ + 'package.json': '{}', + }) + + await setScript.exec(['arg1', 'arg2']) + const contents = fs.readFileSync(resolve(npm.localPrefix, 'package.json')) + t.ok(parseJSON(contents), {scripts: {arg1: 'arg2'}}) +}) + +t.test('warns when overwriting', async t => { + WARN_OUTPUT.length = 0 + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + scripts: { + arg1: 'blah', + }, + }), + }) + + await setScript.exec(['arg1', 'arg2']) + t.hasStrict(WARN_OUTPUT[0], ['set-script', 'Script "arg1" was overwritten'], 'warning was logged') +}) + +t.test('workspaces', async t => { + ERROR_OUTPUT.length = 0 + WARN_OUTPUT.length = 0 + npm.localPrefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'workspaces-test', + version: '1.0.0', + workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], + }), + 'workspace-a': { + 'package.json': '{}', + }, + 'workspace-b': { + 'package.json': '"notajsonobject"', + }, + 'workspace-c': { + 'package.json': JSON.stringify({ + scripts: { + arg1: 'test', + }, + }, null, ' '.repeat(6)).replace(/\n/g, '\r\n'), + }, + }) + + await setScript.execWorkspaces(['arg1', 'arg2'], []) + t.equal(process.exitCode, 1, 'did set the exitCode to 1') + // force the exitCode back to 0 to make tap happy + process.exitCode = 0 + + // workspace-a had the script added + const contentsA = fs.readFileSync(resolve(npm.localPrefix, 'workspace-a', 'package.json')) + const dataA = parseJSON(contentsA) + t.hasStrict(dataA, { scripts: { arg1: 'arg2' } }, 'defined the script') + + // workspace-b logged an error + t.strictSame(ERROR_OUTPUT, [ + ['set-script', `Can't update invalid package.json data`], + [' in workspace: workspace-b'], + [` at location: ${resolve(npm.localPrefix, 'workspace-b')}`], + ], 'logged workspace-b error') + + // workspace-c overwrite a script and logged a warning + const contentsC = fs.readFileSync(resolve(npm.localPrefix, 'workspace-c', 'package.json')) + const dataC = parseJSON(contentsC) + t.hasStrict(dataC, { scripts: { arg1: 'arg2' } }, 'defined the script') + t.equal(dataC[Symbol.for('indent')], ' '.repeat(6), 'kept the correct indent') + t.equal(dataC[Symbol.for('newline')], '\r\n', 'kept the correct newline') + t.match(WARN_OUTPUT, [ + ['set-script', 'Script "arg1" was overwritten'], + [' in workspace: workspace-c'], + [` at location: ${resolve(npm.localPrefix, 'workspace-c')}`], + ], 'logged workspace-c warning') +}) diff --git a/deps/npm/test/lib/set.js b/deps/npm/test/lib/commands/set.js similarity index 53% rename from deps/npm/test/lib/set.js rename to deps/npm/test/lib/commands/set.js index 14d094001b446a..f7d2841ea01564 100644 --- a/deps/npm/test/lib/set.js +++ b/deps/npm/test/lib/commands/set.js @@ -1,14 +1,15 @@ const t = require('tap') -// can't run this until npm set can save to npm.localPrefix +// can't run this until npm set can save to project level npmrc t.skip('npm set', async t => { - const { real: mockNpm } = require('../fixtures/mock-npm') - const { joinedOutput, command, npm } = mockNpm(t) + const { real: mockNpm } = require('../../fixtures/mock-npm') + const { joinedOutput, Npm } = mockNpm(t) + const npm = new Npm() await npm.load() t.test('no args', async t => { t.rejects( - command('set'), + npm.exec('set', []), /Usage:/, 'prints usage' ) @@ -19,7 +20,7 @@ t.skip('npm set', async t => { t.not(npm.config.get('test-config-item', 'project'), 'test config value', 'config is not already new value') // This will write to ~/.npmrc! // Don't unskip until we can write to project level - await command('set', ['test-config-item=test config value']) + await npm.exec('set', ['test-config-item=test config value']) t.equal(joinedOutput(), '', 'outputs nothing') t.equal(npm.config.get('test-config-item', 'project'), 'test config value', 'config is set to new value') }) @@ -29,30 +30,24 @@ t.skip('npm set', async t => { let configArgs = null const npm = { - commands: { - config: (args, cb) => { + exec: async (cmd, args) => { + if (cmd === 'config') configArgs = args - cb() - }, }, } -const Set = t.mock('../../lib/set.js') +const Set = t.mock('../../../lib/commands/set.js') const set = new Set(npm) -t.test('npm set - no args', t => { - set.exec([], (err) => { - t.match(err, /npm set/, 'prints usage') - t.end() - }) +t.test('npm set - no args', async t => { + await t.rejects( + set.exec([]), + set.usage + ) }) -t.test('npm set', t => { - set.exec(['email', 'me@me.me'], (err) => { - if (err) - throw err +t.test('npm set', async t => { + await set.exec(['email', 'me@me.me']) - t.strictSame(configArgs, ['set', 'email', 'me@me.me'], 'passed the correct arguments to config') - t.end() - }) + t.strictSame(configArgs, ['set', 'email', 'me@me.me'], 'passed the correct arguments to config') }) diff --git a/deps/npm/test/lib/commands/shrinkwrap.js b/deps/npm/test/lib/commands/shrinkwrap.js new file mode 100644 index 00000000000000..112aa0a28a29b1 --- /dev/null +++ b/deps/npm/test/lib/commands/shrinkwrap.js @@ -0,0 +1,207 @@ +const t = require('tap') +const fs = require('fs') +const { resolve } = require('path') +const { real: mockNpm } = require('../../fixtures/mock-npm') + +// Attempt to parse json values in snapshots before +// stringifying to remove escaped values like \\" +// This also doesn't reorder the keys of the object +// like tap does by default which is nice in this case +t.formatSnapshot = (obj) => JSON.stringify(obj, (k, v) => { + try { + return JSON.parse(v) + } catch (_) {} + return v +}, 2) + +// Run shrinkwrap against a specified testdir with config items +// and make some assertions that should always be true. Sets +// the results on t.context for use in child tests +const shrinkwrap = async ( + t, + testdir = {}, + config = {}, + mocks = {} +) => { + const { Npm, logs } = mockNpm(t, mocks) + const npm = new Npm() + await npm.load() + + npm.localPrefix = t.testdir(testdir) + if (config.lockfileVersion) + npm.config.set('lockfile-version', config.lockfileVersion) + if (config.global) + npm.config.set('global', config.global) + + await npm.exec('shrinkwrap', []) + + const newFile = resolve(npm.localPrefix, 'npm-shrinkwrap.json') + const oldFile = resolve(npm.localPrefix, 'package-lock.json') + const notices = logs + .filter(([title]) => title === 'notice') + .map(([,, msg]) => msg) + const warnings = logs + .filter(([title]) => title === 'warn') + .map(([,, msg]) => msg) + + t.notOk(fs.existsSync(oldFile), 'package-lock is always deleted') + t.same(warnings, [], 'no warnings') + t.teardown(() => delete t.context) + t.context = { + localPrefix: testdir, + config, + shrinkwrap: JSON.parse(fs.readFileSync(newFile)), + logs: notices, + } +} + +// Run shrinkwrap against all combinations of existing and config +// lockfile versions +const shrinkwrapMatrix = async (t, file, assertions) => { + const ancient = JSON.stringify({ lockfileVersion: 1 }) + const existing = JSON.stringify({ lockfileVersion: 2 }) + const upgrade = { lockfileVersion: 3 } + const downgrade = { lockfileVersion: 1 } + + let ancientDir = {} + let existingDir = null + if (file === 'package-lock') { + ancientDir = { 'package-lock.json': ancient } + existingDir = { 'package-lock.json': existing } + } else if (file === 'npm-shrinkwrap') { + ancientDir = { 'npm-shrinkwrap.json': ancient } + existingDir = { 'npm-shrinkwrap.json': existing } + } else if (file === 'hidden-lockfile') { + ancientDir = { node_modules: { '.package-lock.json': ancient } } + existingDir = { node_modules: { '.package-lock.json': existing } } + } + + await t.test('ancient', async (t) => { + await shrinkwrap(t, ancientDir) + t.match(t.context, assertions.ancient) + t.matchSnapshot(t.context) + }) + await t.test('ancient upgrade', async (t) => { + await shrinkwrap(t, ancientDir, upgrade) + t.match(t.context, assertions.ancientUpgrade) + t.matchSnapshot(t.context) + }) + + if (existingDir) { + await t.test('existing', async (t) => { + await shrinkwrap(t, existingDir) + t.match(t.context, assertions.existing) + t.matchSnapshot(t.context) + }) + await t.test('existing upgrade', async (t) => { + await shrinkwrap(t, existingDir, upgrade) + t.match(t.context, assertions.existingUpgrade) + t.matchSnapshot(t.context) + }) + await t.test('existing downgrade', async (t) => { + await shrinkwrap(t, existingDir, downgrade) + t.match(t.context, assertions.existingDowngrade) + t.matchSnapshot(t.context) + }) + } +} + +const NOTICES = { + CREATED: (v = '') => + [`created a lockfile as npm-shrinkwrap.json${v && ` with version ${v}`}`], + RENAMED: (v = '') => + [`package-lock.json has been renamed to npm-shrinkwrap.json${v && ` and updated to version ${v}`}`], + UPDATED: (v = '') => + [`npm-shrinkwrap.json updated to version ${v}`], + SAME: () => + [`npm-shrinkwrap.json up to date`], +} + +t.test('with nothing', t => shrinkwrapMatrix(t, null, { + ancient: { + shrinkwrap: { lockfileVersion: 2 }, + logs: NOTICES.CREATED(2), + }, + ancientUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.CREATED(3), + }, +})) + +t.test('with package-lock.json', t => shrinkwrapMatrix(t, 'package-lock', { + ancient: { + shrinkwrap: { lockfileVersion: 2 }, + logs: NOTICES.RENAMED(2), + }, + ancientUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.RENAMED(3), + }, + existing: { + shrinkwrap: { lockfileVersion: 2 }, + logs: NOTICES.RENAMED(), + }, + existingUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.RENAMED(3), + }, + existingDowngrade: { + shrinkwrap: { lockfileVersion: 1 }, + logs: NOTICES.RENAMED(1), + }, +})) + +t.test('with npm-shrinkwrap.json', t => shrinkwrapMatrix(t, 'npm-shrinkwrap', { + ancient: { + shrinkwrap: { lockfileVersion: 2 }, + logs: NOTICES.UPDATED(2), + }, + ancientUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.UPDATED(3), + }, + existing: { + shrinkwrap: { lockfileVersion: 2 }, + logs: NOTICES.SAME(), + }, + existingUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.UPDATED(3), + }, + existingDowngrade: { + shrinkwrap: { lockfileVersion: 1 }, + logs: NOTICES.UPDATED(1), + }, +})) + +t.test('with hidden lockfile', t => shrinkwrapMatrix(t, 'hidden-lockfile', { + ancient: { + shrinkwrap: { lockfileVersion: 1 }, + logs: NOTICES.CREATED(), + }, + ancientUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.CREATED(), + }, + existing: { + shrinkwrap: { lockfileVersion: 2 }, + logs: NOTICES.CREATED(), + }, + existingUpgrade: { + shrinkwrap: { lockfileVersion: 3 }, + logs: NOTICES.CREATED(3), + }, + existingDowngrade: { + shrinkwrap: { lockfileVersion: 1 }, + logs: NOTICES.CREATED(1), + }, +})) + +t.test('throws in global mode', async t => { + t.rejects(shrinkwrap(t, {}, { + global: true, + }), { + message: '`npm shrinkwrap` does not work for global packages', + code: 'ESHRINKWRAPGLOBAL', + }) +}) diff --git a/deps/npm/test/lib/star.js b/deps/npm/test/lib/commands/star.js similarity index 54% rename from deps/npm/test/lib/star.js rename to deps/npm/test/lib/commands/star.js index 8820d6e9cfb0b1..13838bb105afce 100644 --- a/deps/npm/test/lib/star.js +++ b/deps/npm/test/lib/commands/star.js @@ -1,5 +1,5 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') let result = '' @@ -19,11 +19,11 @@ const npmlog = { error: noop, info: noop, verbose: noop } const mocks = { npmlog, 'npm-registry-fetch': npmFetch, - '../../lib/utils/get-identity.js': async () => 'foo', - '../../lib/utils/usage.js': () => 'usage instructions', + '../../../lib/utils/get-identity.js': async () => 'foo', + '../../../lib/utils/usage.js': () => 'usage instructions', } -const Star = t.mock('../../lib/star.js', mocks) +const Star = t.mock('../../../lib/commands/star.js', mocks) const star = new Star(npm) t.afterEach(() => { @@ -33,18 +33,15 @@ t.afterEach(() => { result = '' }) -t.test('no args', t => { - star.exec([], err => { - t.match( - err, - /usage instructions/, - 'should throw usage instructions' - ) - t.end() - }) +t.test('no args', async t => { + await t.rejects( + star.exec([]), + /usage instructions/, + 'should throw usage instructions' + ) }) -t.test('star a package', t => { +t.test('star a package', async t => { t.plan(4) const pkgName = '@npmcli/arborist' npmFetch.json = async (uri, opts) => ({ @@ -61,18 +58,15 @@ t.test('star a package', t => { t.equal(msg, 'starring', 'should use expected msg') t.equal(id, pkgName, 'should use expected id') } - star.exec([pkgName], err => { - if (err) - throw err - t.equal( - result, - '(*) @npmcli/arborist', - 'should output starred package msg' - ) - }) + await star.exec([pkgName]) + t.equal( + result, + '(*) @npmcli/arborist', + 'should output starred package msg' + ) }) -t.test('unstar a package', t => { +t.test('unstar a package', async t => { t.plan(4) const pkgName = '@npmcli/arborist' config['star.unstar'] = true @@ -89,62 +83,48 @@ t.test('unstar a package', t => { t.equal(msg, 'unstarring', 'should use expected msg') t.equal(id, pkgName, 'should use expected id') } - star.exec([pkgName], err => { - if (err) - throw err - t.equal( - result, - '( ) @npmcli/arborist', - 'should output unstarred package msg' - ) - }) + await star.exec([pkgName]) + t.equal( + result, + '( ) @npmcli/arborist', + 'should output unstarred package msg' + ) }) t.test('unicode', async t => { - t.test('star a package', t => { + t.test('star a package', async t => { config.unicode = true npmFetch.json = async (uri, opts) => ({}) - star.exec(['pkg'], err => { - if (err) - throw err - t.equal( - result, - '\u2605 pkg', - 'should output unicode starred package msg' - ) - t.end() - }) + await star.exec(['pkg']) + t.equal( + result, + '\u2605 pkg', + 'should output unicode starred package msg' + ) }) - t.test('unstar a package', t => { + t.test('unstar a package', async t => { config.unicode = true config['star.unstar'] = true npmFetch.json = async (uri, opts) => ({}) - star.exec(['pkg'], err => { - if (err) - throw err - t.equal( - result, - '\u2606 pkg', - 'should output unstarred package msg' - ) - t.end() - }) + await star.exec(['pkg']) + t.equal( + result, + '\u2606 pkg', + 'should output unstarred package msg' + ) }) }) -t.test('logged out user', t => { - const Star = t.mock('../../lib/star.js', { +t.test('logged out user', async t => { + const Star = t.mock('../../../lib/commands/star.js', { ...mocks, - '../../lib/utils/get-identity.js': async () => undefined, + '../../../lib/utils/get-identity.js': async () => undefined, }) const star = new Star(npm) - star.exec(['@npmcli/arborist'], err => { - t.match( - err, - /You need to be logged in/, - 'should throw login required error' - ) - t.end() - }) + await t.rejects( + star.exec(['@npmcli/arborist']), + /You need to be logged in/, + 'should throw login required error' + ) }) diff --git a/deps/npm/test/lib/stars.js b/deps/npm/test/lib/commands/stars.js similarity index 64% rename from deps/npm/test/lib/stars.js rename to deps/npm/test/lib/commands/stars.js index bf345aeb4cf42d..4ed64385892fdf 100644 --- a/deps/npm/test/lib/stars.js +++ b/deps/npm/test/lib/commands/stars.js @@ -15,11 +15,11 @@ const npmlog = { warn: noop } const mocks = { npmlog, 'npm-registry-fetch': npmFetch, - '../../lib/utils/get-identity.js': async () => 'foo', - '../../lib/utils/usage.js': () => 'usage instructions', + '../../../lib/utils/get-identity.js': async () => 'foo', + '../../../lib/utils/usage.js': () => 'usage instructions', } -const Stars = t.mock('../../lib/stars.js', mocks) +const Stars = t.mock('../../../lib/commands/stars.js', mocks) const stars = new Stars(npm) t.afterEach(() => { @@ -28,7 +28,7 @@ t.afterEach(() => { result = '' }) -t.test('no args', t => { +t.test('no args', async t => { npmFetch.json = async (uri, opts) => { t.equal(uri, '/-/_view/starredByUser', 'should fetch from expected uri') t.equal(opts.query.key, '"foo"', 'should match logged in username') @@ -44,20 +44,15 @@ t.test('no args', t => { } } - stars.exec([], err => { - if (err) - throw err + await stars.exec([]) - t.matchSnapshot( - result, - 'should output a list of starred packages' - ) - - t.end() - }) + t.matchSnapshot( + result, + 'should output a list of starred packages' + ) }) -t.test('npm star ', t => { +t.test('npm star ', async t => { t.plan(3) npmFetch.json = async (uri, opts) => { t.equal(uri, '/-/_view/starredByUser', 'should fetch from expected uri') @@ -68,19 +63,16 @@ t.test('npm star ', t => { } } - stars.exec(['ruyadorno'], err => { - if (err) - throw err + await stars.exec(['ruyadorno']) - t.match( - result, - '@npmcli/arborist', - 'should output expected list of starred packages' - ) - }) + t.match( + result, + '@npmcli/arborist', + 'should output expected list of starred packages' + ) }) -t.test('unauthorized request', t => { +t.test('unauthorized request', async t => { t.plan(4) npmFetch.json = async () => { throw Object.assign( @@ -98,22 +90,20 @@ t.test('unauthorized request', t => { ) } - stars.exec([], err => { - t.match( - err, - /Not logged in/, - 'should throw unauthorized request msg' - ) - - t.equal( - result, - '', - 'should have empty output' - ) - }) + await t.rejects( + stars.exec([]), + /Not logged in/, + 'should throw unauthorized request msg' + ) + + t.equal( + result, + '', + 'should have empty output' + ) }) -t.test('unexpected error', t => { +t.test('unexpected error', async t => { npmFetch.json = async () => { throw new Error('ERROR') } @@ -122,17 +112,14 @@ t.test('unexpected error', t => { throw new Error('Should not output extra warning msgs') } - stars.exec([], err => { - t.match( - err, - /ERROR/, - 'should throw unexpected error message' - ) - t.end() - }) + await t.rejects( + stars.exec([]), + /ERROR/, + 'should throw unexpected error message' + ) }) -t.test('no pkg starred', t => { +t.test('no pkg starred', async t => { t.plan(2) npmFetch.json = async (uri, opts) => ({ rows: [] }) @@ -145,8 +132,5 @@ t.test('no pkg starred', t => { ) } - stars.exec([], err => { - if (err) - throw err - }) + await stars.exec([]) }) diff --git a/deps/npm/test/lib/start.js b/deps/npm/test/lib/commands/start.js similarity index 86% rename from deps/npm/test/lib/start.js rename to deps/npm/test/lib/commands/start.js index 5c38c71a9a6499..1f26f38ead0de9 100644 --- a/deps/npm/test/lib/start.js +++ b/deps/npm/test/lib/commands/start.js @@ -1,6 +1,6 @@ const t = require('tap') const spawk = require('spawk') -const { real: mockNpm } = require('../fixtures/mock-npm') +const { real: mockNpm } = require('../../fixtures/mock-npm') spawk.preventUnmatched() t.teardown(() => { @@ -22,7 +22,8 @@ t.test('should run stop script from package.json', async t => { }, }), }) - const { command, npm } = mockNpm(t) + const { Npm } = mockNpm(t) + const npm = new Npm() await npm.load() npm.log.level = 'silent' npm.localPrefix = prefix @@ -31,6 +32,6 @@ t.test('should run stop script from package.json', async t => { t.ok(args.includes('node ./test-start.js "foo"'), 'ran start script with extra args') return true }) - await command('start', ['foo']) + await npm.exec('start', ['foo']) t.ok(script.called, 'script ran') }) diff --git a/deps/npm/test/lib/stop.js b/deps/npm/test/lib/commands/stop.js similarity index 86% rename from deps/npm/test/lib/stop.js rename to deps/npm/test/lib/commands/stop.js index 04cdb4e5e7516e..4f189449ba077b 100644 --- a/deps/npm/test/lib/stop.js +++ b/deps/npm/test/lib/commands/stop.js @@ -1,6 +1,6 @@ const t = require('tap') const spawk = require('spawk') -const { real: mockNpm } = require('../fixtures/mock-npm') +const { real: mockNpm } = require('../../fixtures/mock-npm') spawk.preventUnmatched() t.teardown(() => { @@ -22,7 +22,8 @@ t.test('should run stop script from package.json', async t => { }, }), }) - const { command, npm } = mockNpm(t) + const { Npm } = mockNpm(t) + const npm = new Npm() await npm.load() npm.log.level = 'silent' npm.localPrefix = prefix @@ -31,6 +32,6 @@ t.test('should run stop script from package.json', async t => { t.ok(args.includes('node ./test-stop.js "foo"'), 'ran stop script with extra args') return true }) - await command('stop', ['foo']) + await npm.exec('stop', ['foo']) t.ok(script.called, 'script ran') }) diff --git a/deps/npm/test/lib/commands/team.js b/deps/npm/test/lib/commands/team.js new file mode 100644 index 00000000000000..c374d15d80c1ff --- /dev/null +++ b/deps/npm/test/lib/commands/team.js @@ -0,0 +1,399 @@ +const t = require('tap') + +let result = '' +const libnpmteam = { + async add () {}, + async create () {}, + async destroy () {}, + async lsTeams () {}, + async lsUsers () {}, + async rm () {}, +} +const npm = { + flatOptions: {}, + output: (...msg) => { + result += msg.join('\n') + }, +} +const mocks = { + libnpmteam, + 'cli-columns': a => a.join(' '), + '../../../lib/utils/otplease.js': async (opts, fn) => fn(opts), + '../../../lib/utils/usage.js': () => 'usage instructions', +} + +t.afterEach(() => { + result = '' + npm.flatOptions = {} +}) + +const Team = t.mock('../../../lib/commands/team.js', mocks) +const team = new Team(npm) + +t.test('no args', async t => { + await t.rejects( + team.exec([]), + 'usage instructions', + 'should throw usage instructions' + ) +}) + +t.test('team add ', async t => { + t.test('default output', async t => { + await team.exec(['add', '@npmcli:developers', 'foo']) + + t.matchSnapshot(result, 'should output success result for add user') + }) + + t.test('--parseable', async t => { + npm.flatOptions.parseable = true + + await team.exec(['add', '@npmcli:developers', 'foo']) + + t.matchSnapshot( + result, + 'should output success result for parseable add user' + ) + }) + + t.test('--json', async t => { + npm.flatOptions.json = true + + await team.exec(['add', '@npmcli:developers', 'foo']) + + t.same( + JSON.parse(result), + { + added: true, + team: 'npmcli:developers', + user: 'foo', + }, + 'should output success result for add user json' + ) + }) + + t.test('--silent', async t => { + npm.flatOptions.silent = true + + await team.exec(['add', '@npmcli:developers', 'foo']) + + t.same(result, '', 'should not output success if silent') + }) +}) + +t.test('team create ', async t => { + t.test('default output', async t => { + await team.exec(['create', '@npmcli:newteam']) + + t.matchSnapshot(result, 'should output success result for create team') + }) + + t.test('--parseable', async t => { + npm.flatOptions.parseable = true + + await team.exec(['create', '@npmcli:newteam']) + + t.matchSnapshot( + result, + 'should output parseable success result for create team' + ) + }) + + t.test('--json', async t => { + npm.flatOptions.json = true + + await team.exec(['create', '@npmcli:newteam']) + + t.same( + JSON.parse(result), + { + created: true, + team: 'npmcli:newteam', + }, + 'should output success result for create team' + ) + }) + + t.test('--silent', async t => { + npm.flatOptions.silent = true + + await team.exec(['create', '@npmcli:newteam']) + + t.same(result, '', 'should not output create success if silent') + }) +}) + +t.test('team destroy ', async t => { + t.test('default output', async t => { + await team.exec(['destroy', '@npmcli:newteam']) + t.matchSnapshot(result, 'should output success result for destroy team') + }) + + t.test('--parseable', async t => { + npm.flatOptions.parseable = true + await team.exec(['destroy', '@npmcli:newteam']) + t.matchSnapshot(result, 'should output parseable result for destroy team') + }) + + t.test('--json', async t => { + npm.flatOptions.json = true + await team.exec(['destroy', '@npmcli:newteam']) + t.same( + JSON.parse(result), + { + deleted: true, + team: 'npmcli:newteam', + }, + 'should output parseable result for destroy team' + ) + }) + + t.test('--silent', async t => { + npm.flatOptions.silent = true + await team.exec(['destroy', '@npmcli:newteam']) + t.same(result, '', 'should not output destroy if silent') + }) +}) + +t.test('team ls ', async t => { + const libnpmteam = { + async lsTeams () { + return [ + 'npmcli:developers', + 'npmcli:designers', + 'npmcli:product', + ] + }, + } + + const Team = t.mock('../../../lib/commands/team.js', { + ...mocks, + libnpmteam, + }) + const team = new Team(npm) + + t.test('default output', async t => { + await team.exec(['ls', '@npmcli']) + t.matchSnapshot(result, 'should list teams for a given scope') + }) + + t.test('--parseable', async t => { + npm.flatOptions.parseable = true + await team.exec(['ls', '@npmcli']) + t.matchSnapshot(result, 'should list teams for a parseable scope') + }) + + t.test('--json', async t => { + npm.flatOptions.json = true + await team.exec(['ls', '@npmcli']) + t.same( + JSON.parse(result), + [ + 'npmcli:designers', + 'npmcli:developers', + 'npmcli:product', + ], + 'should json list teams for a scope json' + ) + }) + + t.test('--silent', async t => { + npm.flatOptions.silent = true + await team.exec(['ls', '@npmcli']) + t.same(result, '', 'should not list teams if silent') + }) + + t.test('no teams', async t => { + const libnpmteam = { + async lsTeams () { + return [] + }, + } + + const Team = t.mock('../../../lib/commands/team.js', { + ...mocks, + libnpmteam, + }) + const team = new Team(npm) + + await team.exec(['ls', '@npmcli']) + + t.matchSnapshot(result, 'should list no teams for a given scope') + }) + + t.test('single team', async t => { + const libnpmteam = { + async lsTeams () { + return ['npmcli:developers'] + }, + } + + const Team = t.mock('../../../lib/commands/team.js', { + ...mocks, + libnpmteam, + }) + const team = new Team(npm) + + await team.exec(['ls', '@npmcli']) + t.matchSnapshot(result, 'should list single team for a given scope') + }) +}) + +t.test('team ls ', async t => { + const libnpmteam = { + async lsUsers () { + return ['nlf', 'ruyadorno', 'darcyclarke', 'isaacs'] + }, + } + const Team = t.mock('../../../lib/commands/team.js', { + ...mocks, + libnpmteam, + }) + const team = new Team(npm) + + t.test('default output', async t => { + await team.exec(['ls', '@npmcli:developers']) + t.matchSnapshot(result, 'should list users for a given scope:team') + }) + + t.test('--parseable', async t => { + npm.flatOptions.parseable = true + await team.exec(['ls', '@npmcli:developers']) + t.matchSnapshot(result, 'should list users for a parseable scope:team') + }) + + t.test('--json', async t => { + npm.flatOptions.json = true + await team.exec(['ls', '@npmcli:developers']) + t.same( + JSON.parse(result), + [ + 'darcyclarke', + 'isaacs', + 'nlf', + 'ruyadorno', + ], + 'should list users for a scope:team json' + ) + }) + + t.test('--silent', async t => { + npm.flatOptions.silent = true + await team.exec(['ls', '@npmcli:developers']) + t.same(result, '', 'should not output users if silent') + }) + + t.test('no users', async t => { + const libnpmteam = { + async lsUsers () { + return [] + }, + } + + const Team = t.mock('../../../lib/commands/team.js', { + ...mocks, + libnpmteam, + }) + const team = new Team(npm) + + await team.exec(['ls', '@npmcli:developers']) + t.matchSnapshot(result, 'should list no users for a given scope') + }) + + t.test('single user', async t => { + const libnpmteam = { + async lsUsers () { + return ['foo'] + }, + } + + const Team = t.mock('../../../lib/commands/team.js', { + ...mocks, + libnpmteam, + }) + const team = new Team(npm) + + await team.exec(['ls', '@npmcli:developers']) + t.matchSnapshot(result, 'should list single user for a given scope') + }) +}) + +t.test('team rm ', async t => { + t.test('default output', async t => { + await team.exec(['rm', '@npmcli:newteam', 'foo']) + t.matchSnapshot(result, 'should output success result for remove user') + }) + + t.test('--parseable', async t => { + npm.flatOptions.parseable = true + await team.exec(['rm', '@npmcli:newteam', 'foo']) + t.matchSnapshot(result, 'should output parseable result for remove user') + }) + + t.test('--json', async t => { + npm.flatOptions.json = true + await team.exec(['rm', '@npmcli:newteam', 'foo']) + t.same( + JSON.parse(result), + { + removed: true, + team: 'npmcli:newteam', + user: 'foo', + }, + 'should output json result for remove user' + ) + }) + + t.test('--silent', async t => { + npm.flatOptions.silent = true + await team.exec(['rm', '@npmcli:newteam', 'foo']) + t.same(result, '', 'should not output rm result if silent') + }) +}) + +t.test('completion', t => { + const { completion } = team + + t.test('npm team autocomplete', async t => { + const res = await completion({ + conf: { + argv: { + remain: ['npm', 'team'], + }, + }, + }) + t.strictSame( + res, + ['create', 'destroy', 'add', 'rm', 'ls'], + 'should auto complete with subcommands' + ) + t.end() + }) + + t.test('npm team autocomplete', async t => { + for (const subcmd of ['create', 'destroy', 'add', 'rm', 'ls']) { + const res = await completion({ + conf: { + argv: { + remain: ['npm', 'team', subcmd], + }, + }, + }) + t.strictSame( + res, + [], + `should not autocomplete ${subcmd} subcommand` + ) + } + }) + + t.test('npm team unknown subcommand autocomplete', async t => { + t.rejects(completion({conf: {argv: {remain: ['npm', 'team', 'missing-subcommand'] } } }), + {message: 'missing-subcommand not recognized'}, 'should throw a a not recognized error' + ) + + t.end() + }) + + t.end() +}) diff --git a/deps/npm/test/lib/test.js b/deps/npm/test/lib/commands/test.js similarity index 86% rename from deps/npm/test/lib/test.js rename to deps/npm/test/lib/commands/test.js index d597ba2743837e..4e5ce289bca9b1 100644 --- a/deps/npm/test/lib/test.js +++ b/deps/npm/test/lib/commands/test.js @@ -1,6 +1,6 @@ const t = require('tap') const spawk = require('spawk') -const { real: mockNpm } = require('../fixtures/mock-npm') +const { real: mockNpm } = require('../../fixtures/mock-npm') spawk.preventUnmatched() t.teardown(() => { @@ -22,7 +22,8 @@ t.test('should run stop script from package.json', async t => { }, }), }) - const { command, npm } = mockNpm(t) + const { Npm } = mockNpm(t) + const npm = new Npm() await npm.load() npm.log.level = 'silent' npm.localPrefix = prefix @@ -31,6 +32,6 @@ t.test('should run stop script from package.json', async t => { t.ok(args.includes('node ./test-test.js "foo"'), 'ran test script with extra args') return true }) - await command('test', ['foo']) + await npm.exec('test', ['foo']) t.ok(script.called, 'script ran') }) diff --git a/deps/npm/test/lib/token.js b/deps/npm/test/lib/commands/token.js similarity index 88% rename from deps/npm/test/lib/token.js rename to deps/npm/test/lib/commands/token.js index 94218824d8f744..c598c366cf374f 100644 --- a/deps/npm/test/lib/token.js +++ b/deps/npm/test/lib/commands/token.js @@ -10,11 +10,11 @@ const npm = { output: (...args) => mocks.output(...args), } -const Token = t.mock('../../lib/token.js', { - '../../lib/utils/otplease.js': (opts, fn) => { +const Token = t.mock('../../../lib/commands/token.js', { + '../../../lib/utils/otplease.js': (opts, fn) => { return Promise.resolve().then(() => fn(opts)) }, - '../../lib/utils/read-user-info.js': mocks.readUserInfo, + '../../../lib/utils/read-user-info.js': mocks.readUserInfo, 'npm-profile': mocks.profile, npmlog: mocks.log, }) @@ -70,7 +70,7 @@ t.test('completion', (t) => { ) }) -t.test('token foobar', (t) => { +t.test('token foobar', async t => { t.plan(2) const [, reset] = tokenWithMocks({ @@ -85,13 +85,14 @@ t.test('token foobar', (t) => { t.teardown(reset) - token.exec(['foobar'], (err) => { - t.match(err.message, 'foobar is not a recognized subcommand') - }) + await t.rejects( + token.exec(['foobar']), + /foobar is not a recognized subcommand/ + ) }) -t.test('token list', (t) => { - t.plan(15) +t.test('token list', async t => { + t.plan(14) const now = new Date().toISOString() const tokens = [{ @@ -153,13 +154,11 @@ t.test('token list', (t) => { t.teardown(reset) - token.exec([], (err) => { - t.error(err, 'npm token list') - }) + await token.exec([]) }) -t.test('token list json output', (t) => { - t.plan(8) +t.test('token list json output', async t => { + t.plan(7) const now = new Date().toISOString() const tokens = [{ @@ -207,13 +206,11 @@ t.test('token list json output', (t) => { t.teardown(reset) - token.exec(['list'], (err) => { - t.error(err, 'npm token list') - }) + await token.exec(['list']) }) -t.test('token list parseable output', (t) => { - t.plan(12) +t.test('token list parseable output', async t => { + t.plan(11) const now = new Date().toISOString() const tokens = [{ @@ -275,13 +272,11 @@ t.test('token list parseable output', (t) => { t.teardown(reset) - token.exec(['list'], (err) => { - t.error(err, 'npm token list') - }) + await token.exec(['list']) }) -t.test('token revoke', (t) => { - t.plan(10) +t.test('token revoke', async t => { + t.plan(9) const [token, reset] = tokenWithMocks({ npm: { @@ -328,13 +323,11 @@ t.test('token revoke', (t) => { t.teardown(reset) - token.exec(['rm', 'abcd'], (err) => { - t.error(err, 'npm token rm') - }) + await token.exec(['rm', 'abcd']) }) -t.test('token revoke multiple tokens', (t) => { - t.plan(10) +t.test('token revoke multiple tokens', async t => { + t.plan(9) const [token, reset] = tokenWithMocks({ npm: { @@ -380,13 +373,11 @@ t.test('token revoke multiple tokens', (t) => { t.teardown(reset) - token.exec(['revoke', 'abcd', 'efgh'], (err) => { - t.error(err, 'npm token rm') - }) + await token.exec(['revoke', 'abcd', 'efgh']) }) -t.test('token revoke json output', (t) => { - t.plan(10) +t.test('token revoke json output', async t => { + t.plan(9) const [token, reset] = tokenWithMocks({ npm: { @@ -432,13 +423,11 @@ t.test('token revoke json output', (t) => { t.teardown(reset) - token.exec(['delete', 'abcd'], (err) => { - t.error(err, 'npm token rm') - }) + await token.exec(['delete', 'abcd']) }) -t.test('token revoke parseable output', (t) => { - t.plan(9) +t.test('token revoke parseable output', async t => { + t.plan(8) const [token, reset] = tokenWithMocks({ npm: { @@ -482,13 +471,11 @@ t.test('token revoke parseable output', (t) => { t.teardown(reset) - token.exec(['remove', 'abcd'], (err) => { - t.error(err, 'npm token rm') - }) + await token.exec(['remove', 'abcd']) }) -t.test('token revoke by token', (t) => { - t.plan(9) +t.test('token revoke by token', async t => { + t.plan(8) const [token, reset] = tokenWithMocks({ npm: { @@ -532,12 +519,10 @@ t.test('token revoke by token', (t) => { t.teardown(reset) - token.exec(['rm', 'efgh5678'], (err) => { - t.error(err, 'npm token rm') - }) + await token.exec(['rm', 'efgh5678']) }) -t.test('token revoke requires an id', (t) => { +t.test('token revoke requires an id', async t => { t.plan(2) const [token, reset] = tokenWithMocks({ @@ -552,12 +537,13 @@ t.test('token revoke requires an id', (t) => { t.teardown(reset) - token.exec(['rm'], (err) => { - t.match(err.message, '`` argument is required') - }) + await t.rejects( + token.exec(['rm']), + /`` argument is required/ + ) }) -t.test('token revoke ambiguous id errors', (t) => { +t.test('token revoke ambiguous id errors', async t => { t.plan(7) const [token, reset] = tokenWithMocks({ @@ -597,12 +583,13 @@ t.test('token revoke ambiguous id errors', (t) => { t.teardown(reset) - token.exec(['rm', 'abcd'], (err) => { - t.match(err.message, 'Token ID "abcd" was ambiguous') - }) + await t.rejects( + token.exec(['rm', 'abcd']), + /Token ID "abcd" was ambiguous/ + ) }) -t.test('token revoke unknown id errors', (t) => { +t.test('token revoke unknown id errors', async t => { t.plan(7) const [token, reset] = tokenWithMocks({ @@ -641,13 +628,14 @@ t.test('token revoke unknown id errors', (t) => { t.teardown(reset) - token.exec(['rm', 'efgh'], (err) => { - t.match(err.message, 'Unknown token id or value "efgh".') - }) + await t.rejects( + token.exec(['rm', 'efgh']), + /Unknown token id or value "efgh"./ + ) }) -t.test('token create', (t) => { - t.plan(15) +t.test('token create', async t => { + t.plan(14) const now = new Date().toISOString() const password = 'thisisnotreallyapassword' @@ -705,13 +693,11 @@ t.test('token create', (t) => { t.teardown(reset) - token.exec(['create'], (err) => { - t.error(err, 'npm token create') - }) + await token.exec(['create']) }) -t.test('token create json output', (t) => { - t.plan(10) +t.test('token create json output', async t => { + t.plan(9) const now = new Date().toISOString() const password = 'thisisnotreallyapassword' @@ -764,13 +750,11 @@ t.test('token create json output', (t) => { t.teardown(reset) - token.exec(['create'], (err) => { - t.error(err, 'npm token create') - }) + await token.exec(['create']) }) -t.test('token create parseable output', (t) => { - t.plan(12) +t.test('token create parseable output', async t => { + t.plan(11) const now = new Date().toISOString() const password = 'thisisnotreallyapassword' @@ -830,13 +814,11 @@ t.test('token create parseable output', (t) => { t.teardown(reset) - token.exec(['create'], (err) => { - t.error(err, 'npm token create') - }) + await token.exec(['create']) }) -t.test('token create ipv6 cidr', (t) => { - t.plan(4) +t.test('token create ipv6 cidr', async t => { + t.plan(3) const password = 'thisisnotreallyapassword' @@ -864,14 +846,15 @@ t.test('token create ipv6 cidr', (t) => { t.teardown(reset) - token.exec(['create'], (err) => { - t.equal(err.message, 'CIDR whitelist can only contain IPv4 addresses, ::1/128 is IPv6', 'returns correct error') - t.equal(err.code, 'EINVALIDCIDR') - }) + await t.rejects( + token.exec(['create']), + { code: 'EINVALIDCIDR', message: /CIDR whitelist can only contain IPv4 addresses, ::1\/128 is IPv6/ }, + 'returns correct error' + ) }) -t.test('token create invalid cidr', (t) => { - t.plan(4) +t.test('token create invalid cidr', async t => { + t.plan(3) const password = 'thisisnotreallyapassword' @@ -899,8 +882,9 @@ t.test('token create invalid cidr', (t) => { t.teardown(reset) - token.exec(['create'], (err) => { - t.equal(err.message, 'CIDR whitelist contains invalid CIDR entry: apple/cider', 'returns correct error') - t.equal(err.code, 'EINVALIDCIDR') - }) + await t.rejects( + token.exec(['create']), + { code: 'EINVALIDCIDR', message: /CIDR whitelist contains invalid CIDR entry: apple\/cider/ }, + 'returns correct error' + ) }) diff --git a/deps/npm/test/lib/uninstall.js b/deps/npm/test/lib/commands/uninstall.js similarity index 71% rename from deps/npm/test/lib/uninstall.js rename to deps/npm/test/lib/commands/uninstall.js index 272adb86836028..ec7961f9c96c4e 100644 --- a/deps/npm/test/lib/uninstall.js +++ b/deps/npm/test/lib/commands/uninstall.js @@ -1,7 +1,7 @@ const t = require('tap') const fs = require('fs') const { resolve } = require('path') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') const npm = mockNpm({ globalDir: '', @@ -12,10 +12,10 @@ const npm = mockNpm({ localPrefix: '', }) const mocks = { - '../../lib/utils/reify-finish.js': () => Promise.resolve(), + '../../../lib/utils/reify-finish.js': () => Promise.resolve(), } -const Uninstall = t.mock('../../lib/uninstall.js', mocks) +const Uninstall = t.mock('../../../lib/commands/uninstall.js', mocks) const uninstall = new Uninstall(npm) t.afterEach(() => { @@ -26,7 +26,7 @@ t.afterEach(() => { npm.flatOptions.prefix = '' }) -t.test('remove single installed lib', t => { +t.test('remove single installed lib', async t => { const path = t.testdir({ 'package.json': JSON.stringify({ name: 'test-rm-single-lib', @@ -86,16 +86,12 @@ t.test('remove single installed lib', t => { npm.localPrefix = path - uninstall.exec(['b'], err => { - if (err) - throw err + await uninstall.exec(['b']) - t.throws(() => fs.statSync(b), 'should have removed package from npm') - t.end() - }) + t.throws(() => fs.statSync(b), 'should have removed package from npm') }) -t.test('remove multiple installed libs', t => { +t.test('remove multiple installed libs', async t => { const path = t.testdir({ node_modules: { a: { @@ -149,33 +145,25 @@ t.test('remove multiple installed libs', t => { npm.localPrefix = path - uninstall.exec(['b'], err => { - if (err) - throw err + await uninstall.exec(['b']) - t.throws(() => fs.statSync(a), 'should have removed a package from nm') - t.throws(() => fs.statSync(b), 'should have removed b package from nm') - t.end() - }) + t.throws(() => fs.statSync(a), 'should have removed a package from nm') + t.throws(() => fs.statSync(b), 'should have removed b package from nm') }) -t.test('no args local', t => { +t.test('no args local', async t => { const path = t.testdir() npm.flatOptions.prefix = path - uninstall.exec([], err => { - t.match( - err, - /Must provide a package name to remove/, - 'should throw package name required error' - ) - - t.end() - }) + await t.rejects( + uninstall.exec([]), + /Must provide a package name to remove/, + 'should throw package name required error' + ) }) -t.test('no args global', t => { +t.test('no args global', async t => { const path = t.testdir({ lib: { node_modules: { @@ -199,37 +187,28 @@ t.test('no args global', t => { const a = resolve(path, 'lib/node_modules/a') t.ok(() => fs.statSync(a)) - uninstall.exec([], err => { - if (err) - throw err - - t.throws(() => fs.statSync(a), 'should have removed global nm symlink') + await uninstall.exec([]) - t.end() - }) + t.throws(() => fs.statSync(a), 'should have removed global nm symlink') }) -t.test('no args global but no package.json', t => { +t.test('no args global but no package.json', async t => { const path = t.testdir({}) npm.prefix = path npm.localPrefix = path npm.flatOptions.global = true - uninstall.exec([], err => { - t.match( - err, - 'npm uninstall' - ) - - t.end() - }) + await t.rejects( + uninstall.exec([]), + /npm uninstall/ + ) }) -t.test('unknown error reading from localPrefix package.json', t => { +t.test('unknown error reading from localPrefix package.json', async t => { const path = t.testdir({}) - const Uninstall = t.mock('../../lib/uninstall.js', { + const Uninstall = t.mock('../../../lib/commands/uninstall.js', { ...mocks, 'read-package-json-fast': () => Promise.reject(new Error('ERR')), }) @@ -239,13 +218,9 @@ t.test('unknown error reading from localPrefix package.json', t => { npm.localPrefix = path npm.flatOptions.global = true - uninstall.exec([], err => { - t.match( - err, - /ERR/, - 'should throw unknown error' - ) - - t.end() - }) + await t.rejects( + uninstall.exec([]), + /ERR/, + 'should throw unknown error' + ) }) diff --git a/deps/npm/test/lib/unpublish.js b/deps/npm/test/lib/commands/unpublish.js similarity index 64% rename from deps/npm/test/lib/unpublish.js rename to deps/npm/test/lib/commands/unpublish.js index 9199b8aed94420..7e6b5755c76a84 100644 --- a/deps/npm/test/lib/unpublish.js +++ b/deps/npm/test/lib/commands/unpublish.js @@ -1,5 +1,5 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') let result = '' const noop = () => null @@ -28,8 +28,8 @@ const mocks = { libnpmaccess: { lsPackages: noop }, libnpmpublish: { unpublish: noop }, 'npm-registry-fetch': { json: noop }, - '../../lib/utils/otplease.js': async (opts, fn) => fn(opts), - '../../lib/utils/get-identity.js': async () => 'foo', + '../../../lib/utils/otplease.js': async (opts, fn) => fn(opts), + '../../../lib/utils/get-identity.js': async () => 'foo', } t.afterEach(() => { @@ -41,7 +41,7 @@ t.afterEach(() => { config.loglevel = 'silly' }) -t.test('no args --force', t => { +t.test('no args --force', async t => { config.force = true npm.log = { @@ -71,98 +71,82 @@ t.test('no args --force', t => { }, } - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, libnpmpublish, }) const unpublish = new Unpublish(npm) - unpublish.exec([], err => { - if (err) - throw err + await unpublish.exec([]) - t.equal( - result, - '- pkg@1.0.0', - 'should output removed pkg@version on success' - ) - t.end() - }) + t.equal( + result, + '- pkg@1.0.0', + 'should output removed pkg@version on success' + ) }) -t.test('no args --force missing package.json', t => { +t.test('no args --force missing package.json', async t => { config.force = true const testDir = t.testdir({}) npm.localPrefix = testDir - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, }) const unpublish = new Unpublish(npm) - unpublish.exec([], err => { - t.match( - err, - /Usage: npm unpublish/, - 'should throw usage instructions on missing package.json' - ) - t.end() - }) + await t.rejects( + unpublish.exec([]), + /Usage: npm unpublish/, + 'should throw usage instructions on missing package.json' + ) }) -t.test('no args --force unknown error reading package.json', t => { +t.test('no args --force unknown error reading package.json', async t => { config.force = true - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, 'read-package-json': (path, cb) => cb(new Error('ERR')), }) const unpublish = new Unpublish(npm) - unpublish.exec([], err => { - t.match( - err, - /ERR/, - 'should throw unknown error from reading package.json' - ) - t.end() - }) + await t.rejects( + unpublish.exec([]), + /ERR/, + 'should throw unknown error from reading package.json' + ) }) -t.test('no args', t => { - const Unpublish = t.mock('../../lib/unpublish.js', { +t.test('no args', async t => { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, }) const unpublish = new Unpublish(npm) - unpublish.exec([], err => { - t.match( - err, - /Refusing to delete entire project/, - 'should throw --force required error on no args' - ) - t.end() - }) + await t.rejects( + unpublish.exec([]), + /Refusing to delete entire project/, + 'should throw --force required error on no args' + ) }) -t.test('too many args', t => { - const Unpublish = t.mock('../../lib/unpublish.js', { +t.test('too many args', async t => { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, }) const unpublish = new Unpublish(npm) - unpublish.exec(['a', 'b'], err => { - t.match( - err, - /Usage: npm unpublish/, - 'should throw usage instructions if too many args' - ) - t.end() - }) + await t.rejects( + unpublish.exec(['a', 'b']), + /Usage: npm unpublish/, + 'should throw usage instructions if too many args' + ) }) -t.test('unpublish @version', t => { +t.test('unpublish @version', async t => { npm.log = { silly (title, key, value) { t.equal(title, 'unpublish', 'should silly log args') @@ -184,26 +168,22 @@ t.test('unpublish @version', t => { }, } - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, libnpmpublish, }) const unpublish = new Unpublish(npm) - unpublish.exec(['pkg@1.0.0'], err => { - if (err) - throw err + await unpublish.exec(['pkg@1.0.0']) - t.equal( - result, - '- pkg@1.0.0', - 'should output removed pkg@version on success' - ) - t.end() - }) + t.equal( + result, + '- pkg@1.0.0', + 'should output removed pkg@version on success' + ) }) -t.test('no version found in package.json', t => { +t.test('no version found in package.json', async t => { config.force = true const testDir = t.testdir({ @@ -213,67 +193,54 @@ t.test('no version found in package.json', t => { }) npm.localPrefix = testDir - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, }) const unpublish = new Unpublish(npm) - unpublish.exec([], err => { - if (err) - throw err - - t.equal( - result, - '- pkg', - 'should output removed pkg on success' - ) - t.end() - }) + await unpublish.exec([]) + t.equal( + result, + '- pkg', + 'should output removed pkg on success' + ) }) -t.test('unpublish --force no version set', t => { +t.test('unpublish --force no version set', async t => { config.force = true - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, }) const unpublish = new Unpublish(npm) - unpublish.exec(['pkg'], err => { - if (err) - throw err + await unpublish.exec(['pkg']) - t.equal( - result, - '- pkg', - 'should output pkg removed' - ) - t.end() - }) + t.equal( + result, + '- pkg', + 'should output pkg removed' + ) }) -t.test('silent', t => { +t.test('silent', async t => { config.loglevel = 'silent' - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, }) const unpublish = new Unpublish(npm) - unpublish.exec(['pkg@1.0.0'], err => { - if (err) - throw err + await unpublish.exec(['pkg@1.0.0']) - t.equal( - result, - '', - 'should have no output' - ) - t.end() - }) + t.equal( + result, + '', + 'should have no output' + ) }) -t.test('workspaces', t => { +t.test('workspaces', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'my-cool-pkg', @@ -301,84 +268,69 @@ t.test('workspaces', t => { }), }, }) - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, }) const unpublish = new Unpublish(npm) - t.test('no force', (t) => { + t.test('no force', async t => { npm.localPrefix = testDir - unpublish.execWorkspaces([], [], (err) => { - t.match(err, /--force/, 'should require force') - t.end() - }) + await t.rejects( + unpublish.execWorkspaces([], []), + /--force/, + 'should require force' + ) }) - t.test('all workspaces --force', (t) => { + t.test('all workspaces --force', async t => { npm.localPrefix = testDir config.force = true - unpublish.execWorkspaces([], [], (err) => { - t.notOk(err) - t.matchSnapshot(result, 'should output all workspaces') - t.end() - }) + await unpublish.execWorkspaces([], []) + t.matchSnapshot(result, 'should output all workspaces') }) - t.test('one workspace --force', (t) => { + t.test('one workspace --force', async t => { npm.localPrefix = testDir config.force = true - unpublish.execWorkspaces([], ['workspace-a'], (err) => { - t.notOk(err) - t.matchSnapshot(result, 'should output one workspaces') - t.end() - }) + await unpublish.execWorkspaces([], ['workspace-a']) + t.matchSnapshot(result, 'should output one workspaces') }) - t.end() }) -t.test('dryRun with spec', (t) => { +t.test('dryRun with spec', async t => { config['dry-run'] = true - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, libnpmpublish: { unpublish: () => { throw new Error('should not be called') } }, }) const unpublish = new Unpublish(npm) - unpublish.exec(['pkg@1.0.0'], err => { - if (err) - throw err - - t.equal( - result, - '- pkg@1.0.0', - 'should output removed pkg@version on success' - ) - t.end() - }) + await unpublish.exec(['pkg@1.0.0']) + + t.equal( + result, + '- pkg@1.0.0', + 'should output removed pkg@version on success' + ) }) -t.test('dryRun with local package', (t) => { +t.test('dryRun with local package', async t => { config['dry-run'] = true config.force = true - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, libnpmpublish: { unpublish: () => { throw new Error('should not be called') } }, }) const unpublish = new Unpublish(npm) - unpublish.exec([], err => { - if (err) - throw err - - t.equal( - result, - '- pkg@1.0.0', - 'should output removed pkg@1.0.0 on success' - ) - t.end() - }) + await unpublish.exec([]) + t.equal( + result, + '- pkg@1.0.0', + 'should output removed pkg@1.0.0 on success' + ) }) t.test('completion', async t => { @@ -391,7 +343,7 @@ t.test('completion', async t => { } t.test('completing with multiple versions from the registry', async t => { - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, libnpmaccess: { async lsPackages () { @@ -428,7 +380,7 @@ t.test('completion', async t => { }) t.test('no versions retrieved', async t => { - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, libnpmaccess: { async lsPackages () { @@ -460,7 +412,7 @@ t.test('completion', async t => { }) t.test('packages starting with same letters', async t => { - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, libnpmaccess: { async lsPackages () { @@ -487,7 +439,7 @@ t.test('completion', async t => { }) t.test('no packages retrieved', async t => { - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, libnpmaccess: { async lsPackages () { @@ -507,7 +459,7 @@ t.test('completion', async t => { }) t.test('no pkg name to complete', async t => { - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, libnpmaccess: { async lsPackages () { @@ -530,7 +482,7 @@ t.test('completion', async t => { }) t.test('no pkg names retrieved from user account', async t => { - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, libnpmaccess: { async lsPackages () { @@ -550,9 +502,9 @@ t.test('completion', async t => { }) t.test('logged out user', async t => { - const Unpublish = t.mock('../../lib/unpublish.js', { + const Unpublish = t.mock('../../../lib/commands/unpublish.js', { ...mocks, - '../../lib/utils/get-identity.js': () => Promise.reject(new Error('ERR')), + '../../../lib/utils/get-identity.js': () => Promise.reject(new Error('ERR')), }) const unpublish = new Unpublish(npm) @@ -565,7 +517,7 @@ t.test('completion', async t => { }) t.test('too many args', async t => { - const Unpublish = t.mock('../../lib/unpublish.js', mocks) + const Unpublish = t.mock('../../../lib/commands/unpublish.js', mocks) const unpublish = new Unpublish(npm) await testComp(t, { @@ -575,6 +527,4 @@ t.test('completion', async t => { expect: [], }) }) - - t.end() }) diff --git a/deps/npm/test/lib/unstar.js b/deps/npm/test/lib/commands/unstar.js similarity index 66% rename from deps/npm/test/lib/unstar.js rename to deps/npm/test/lib/commands/unstar.js index 8b853230a6c8b4..fb3c269b7bbdd1 100644 --- a/deps/npm/test/lib/unstar.js +++ b/deps/npm/test/lib/commands/unstar.js @@ -1,6 +1,6 @@ const t = require('tap') -t.test('unstar', t => { +t.test('unstar', async t => { t.plan(3) class Star { @@ -8,13 +8,12 @@ t.test('unstar', t => { this.npm = npm } - exec (args, cb) { + async exec (args) { t.same(args, ['pkg'], 'should forward packages') - cb() } } - const Unstar = t.mock('../../lib/unstar.js', { - '../../lib/star.js': Star, + const Unstar = t.mock('../../../lib/commands/unstar.js', { + '../../../lib/commands/star.js': Star, }) const unstar = new Unstar({ @@ -26,8 +25,5 @@ t.test('unstar', t => { }, }) - unstar.exec(['pkg'], err => { - if (err) - throw err - }) + await unstar.exec(['pkg']) }) diff --git a/deps/npm/test/lib/update.js b/deps/npm/test/lib/commands/update.js similarity index 76% rename from deps/npm/test/lib/update.js rename to deps/npm/test/lib/commands/update.js index 487b12e5fa2970..6ca6dbc87d9687 100644 --- a/deps/npm/test/lib/update.js +++ b/deps/npm/test/lib/commands/update.js @@ -1,6 +1,6 @@ const t = require('tap') const { resolve } = require('path') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') const config = { depth: 0, @@ -18,8 +18,8 @@ const mocks = { '@npmcli/arborist': class { reify () {} }, - '../../lib/utils/reify-finish.js': noop, - '../../lib/utils/usage.js': () => 'usage instructions', + '../../../lib/utils/reify-finish.js': noop, + '../../../lib/utils/usage.js': () => 'usage instructions', } t.afterEach(() => { @@ -28,7 +28,7 @@ t.afterEach(() => { npm.globalDir = '' }) -t.test('no args', t => { +t.test('no args', async t => { t.plan(3) npm.prefix = '/project/a' @@ -52,22 +52,19 @@ t.test('no args', t => { } } - const Update = t.mock('../../lib/update.js', { + const Update = t.mock('../../../lib/commands/update.js', { ...mocks, - '../../lib/utils/reify-finish.js': (npm, arb) => { + '../../../lib/utils/reify-finish.js': (npm, arb) => { t.match(arb, Arborist, 'should reify-finish with arborist instance') }, '@npmcli/arborist': Arborist, }) const update = new Update(npm) - update.exec([], err => { - if (err) - throw err - }) + await update.exec([]) }) -t.test('with args', t => { +t.test('with args', async t => { t.plan(3) npm.prefix = '/project/a' @@ -91,28 +88,25 @@ t.test('with args', t => { } } - const Update = t.mock('../../lib/update.js', { + const Update = t.mock('../../../lib/commands/update.js', { ...mocks, - '../../lib/utils/reify-finish.js': (npm, arb) => { + '../../../lib/utils/reify-finish.js': (npm, arb) => { t.match(arb, Arborist, 'should reify-finish with arborist instance') }, '@npmcli/arborist': Arborist, }) const update = new Update(npm) - update.exec(['ipt'], err => { - if (err) - throw err - }) + await update.exec(['ipt']) }) -t.test('update --depth=', t => { +t.test('update --depth=', async t => { t.plan(2) npm.prefix = '/project/a' config.depth = 1 - const Update = t.mock('../../lib/update.js', { + const Update = t.mock('../../../lib/commands/update.js', { ...mocks, npmlog: { warn: (title, msg) => { @@ -127,13 +121,10 @@ t.test('update --depth=', t => { }) const update = new Update(npm) - update.exec([], err => { - if (err) - throw err - }) + await update.exec([]) }) -t.test('update --global', t => { +t.test('update --global', async t => { t.plan(2) const normalizePath = p => p.replace(/\\+/g, '/') @@ -163,14 +154,11 @@ t.test('update --global', t => { reify () {} } - const Update = t.mock('../../lib/update.js', { + const Update = t.mock('../../../lib/commands/update.js', { ...mocks, '@npmcli/arborist': Arborist, }) const update = new Update(npm) - update.exec([], err => { - if (err) - throw err - }) + await update.exec([]) }) diff --git a/deps/npm/test/lib/version.js b/deps/npm/test/lib/commands/version.js similarity index 61% rename from deps/npm/test/lib/version.js rename to deps/npm/test/lib/commands/version.js index df6d0dd797d0a5..3b3f76f759be8b 100644 --- a/deps/npm/test/lib/version.js +++ b/deps/npm/test/lib/commands/version.js @@ -1,5 +1,5 @@ const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') let result = [] @@ -22,7 +22,7 @@ const mocks = { libnpmversion: noop, } -const Version = t.mock('../../lib/version.js', mocks) +const Version = t.mock('../../../lib/commands/version.js', mocks) const version = new Version(npm) const _processVersions = process.versions @@ -33,7 +33,7 @@ t.afterEach(() => { result = [] }) -t.test('no args', t => { +t.test('no args', async t => { const prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-version-no-args', @@ -43,34 +43,25 @@ t.test('no args', t => { npm.prefix = prefix Object.defineProperty(process, 'versions', { value: { node: '1.0.0' } }) - version.exec([], err => { - if (err) - throw err + await version.exec([]) - t.same( - 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.same( + 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.test('too many args', t => { - version.exec(['foo', 'bar'], err => { - t.match( - err, - 'npm version', - 'should throw usage instructions error' - ) - - t.end() - }) +t.test('too many args', async t => { + await t.rejects( + version.exec(['foo', 'bar']), + /npm version/, + 'should throw usage instructions error' + ) }) t.test('completion', async t => { @@ -94,47 +85,38 @@ t.test('completion', async t => { t.end() }) -t.test('failure reading package.json', t => { +t.test('failure reading package.json', async t => { const prefix = t.testdir({}) npm.prefix = prefix - version.exec([], err => { - if (err) - throw err - - t.same( - result, - [{ - npm: '1.0.0', - node: '1.0.0', - }], - 'should not have package name on returning object' - ) + await version.exec([]) - t.end() - }) + t.same( + result, + [{ + npm: '1.0.0', + node: '1.0.0', + }], + 'should not have package name on returning object' + ) }) -t.test('--json option', t => { +t.test('--json option', async t => { const prefix = t.testdir({}) config.json = true npm.prefix = prefix Object.defineProperty(process, 'versions', { value: {} }) - version.exec([], err => { - if (err) - throw err - t.same( - result, - ['{\n "npm": "1.0.0"\n}'], - 'should return json stringified result' - ) - t.end() - }) + await version.exec([]) + t.same( + result, + ['{\n "npm": "1.0.0"\n}'], + 'should return json stringified result' + ) }) -t.test('with one arg', t => { - const Version = t.mock('../../lib/version.js', { +t.test('with one arg', async t => { + const Version = t.mock('../../../lib/commands/version.js', { ...mocks, libnpmversion: (arg, opts) => { t.equal(arg, 'major', 'should forward expected value') @@ -150,21 +132,17 @@ t.test('with one arg', t => { }) const version = new Version(npm) - version.exec(['major'], err => { - if (err) - throw err - t.same(result, ['v4.0.0'], 'outputs the new version prefixed by the tagVersionPrefix') - t.end() - }) + await version.exec(['major']) + t.same(result, ['v4.0.0'], 'outputs the new version prefixed by the tagVersionPrefix') }) -t.test('workspaces', t => { +t.test('workspaces', async t => { t.teardown(() => { npm.localPrefix = '' npm.prefix = '' }) - t.test('no args, all workspaces', t => { + t.test('no args, all workspaces', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'workspaces-test', @@ -187,20 +165,16 @@ t.test('workspaces', t => { npm.localPrefix = testDir npm.prefix = testDir const version = new Version(npm) - version.execWorkspaces([], [], err => { - if (err) - throw err - t.same(result, [{ - 'workspaces-test': '1.0.0', - 'workspace-a': '1.0.0', - 'workspace-b': '1.0.0', - npm: '1.0.0', - }], 'outputs includes main package and workspace versions') - t.end() - }) + await version.execWorkspaces([], []) + t.same(result, [{ + 'workspaces-test': '1.0.0', + 'workspace-a': '1.0.0', + 'workspace-b': '1.0.0', + npm: '1.0.0', + }], 'outputs includes main package and workspace versions') }) - t.test('no args, single workspaces', t => { + t.test('no args, single workspaces', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'workspaces-test', @@ -223,19 +197,15 @@ t.test('workspaces', t => { npm.localPrefix = testDir npm.prefix = testDir const version = new Version(npm) - version.execWorkspaces([], ['workspace-a'], err => { - if (err) - throw err - t.same(result, [{ - 'workspaces-test': '1.0.0', - 'workspace-a': '1.0.0', - npm: '1.0.0', - }], 'outputs includes main package and requested workspace versions') - t.end() - }) + await version.execWorkspaces([], ['workspace-a']) + t.same(result, [{ + 'workspaces-test': '1.0.0', + 'workspace-a': '1.0.0', + npm: '1.0.0', + }], 'outputs includes main package and requested workspace versions') }) - t.test('no args, all workspaces, workspace with missing name or version', t => { + t.test('no args, all workspaces, workspace with missing name or version', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'workspaces-test', @@ -262,19 +232,15 @@ t.test('workspaces', t => { npm.localPrefix = testDir npm.prefix = testDir const version = new Version(npm) - version.execWorkspaces([], [], err => { - if (err) - throw err - t.same(result, [{ - 'workspaces-test': '1.0.0', - 'workspace-a': '1.0.0', - npm: '1.0.0', - }], 'outputs includes main package and valid workspace versions') - t.end() - }) + await version.execWorkspaces([], []) + t.same(result, [{ + 'workspaces-test': '1.0.0', + 'workspace-a': '1.0.0', + npm: '1.0.0', + }], 'outputs includes main package and valid workspace versions') }) - t.test('with one arg, all workspaces', t => { + t.test('with one arg, all workspaces', async t => { const libNpmVersionArgs = [] const testDir = t.testdir({ 'package.json': JSON.stringify({ @@ -295,7 +261,7 @@ t.test('workspaces', t => { }), }, }) - const Version = t.mock('../../lib/version.js', { + const Version = t.mock('../../../lib/commands/version.js', { ...mocks, libnpmversion: (arg, opts) => { libNpmVersionArgs.push([arg, opts]) @@ -306,25 +272,15 @@ t.test('workspaces', t => { npm.prefix = testDir const version = new Version(npm) - version.execWorkspaces(['major'], [], err => { - if (err) - throw err - t.same(result, ['workspace-a', 'v2.0.0', 'workspace-b', 'v2.0.0'], 'outputs the new version for only the workspaces prefixed by the tagVersionPrefix') - t.end() - }) + await version.execWorkspaces(['major'], []) + t.same(result, ['workspace-a', 'v2.0.0', 'workspace-b', 'v2.0.0'], 'outputs the new version for only the workspaces prefixed by the tagVersionPrefix') }) - t.test('too many args', t => { - version.execWorkspaces(['foo', 'bar'], [], err => { - t.match( - err, - 'npm version', - 'should throw usage instructions error' - ) - - t.end() - }) + t.test('too many args', async t => { + await t.rejects( + version.execWorkspaces(['foo', 'bar'], []), + /npm version/, + 'should throw usage instructions error' + ) }) - - t.end() }) diff --git a/deps/npm/test/lib/view.js b/deps/npm/test/lib/commands/view.js similarity index 59% rename from deps/npm/test/lib/view.js rename to deps/npm/test/lib/commands/view.js index 096ababb29ae83..116930aff4edee 100644 --- a/deps/npm/test/lib/view.js +++ b/deps/npm/test/lib/commands/view.js @@ -5,7 +5,7 @@ t.cleanSnapshot = str => str.replace(/published .*? ago/g, 'published {TIME} ago // run the same as tap does when running directly with node process.stdout.columns = undefined -const { fake: mockNpm } = require('../fixtures/mock-npm') +const { fake: mockNpm } = require('../../fixtures/mock-npm') let logs const cleanLogs = () => { @@ -57,7 +57,17 @@ const packument = (nv, opts) => { unpackedSize: 1, }, }, - '1.0.1': {}, + '1.0.1': { + name: 'blue', + version: '1.0.1', + dist: { + shasum: '124', + tarball: 'http://hm.blue.com/1.0.1.tgz', + integrity: '---', + fileCount: 1, + unpackedSize: 1, + }, + }, }, }, cyan: { @@ -252,8 +262,8 @@ const packument = (nv, opts) => { t.beforeEach(cleanLogs) -t.test('should log package info', t => { - const View = t.mock('../../lib/view.js', { +t.test('should log package info', async t => { + const View = t.mock('../../../lib/commands/view.js', { pacote: { packument, }, @@ -263,7 +273,7 @@ t.test('should log package info', t => { }) const view = new View(npm) - const ViewJson = t.mock('../../lib/view.js', { + const ViewJson = t.mock('../../../lib/commands/view.js', { pacote: { packument, }, @@ -276,7 +286,7 @@ t.test('should log package info', t => { }) const viewJson = new ViewJson(jsonNpm) - const ViewUnicode = t.mock('../../lib/view.js', { + const ViewUnicode = t.mock('../../../lib/commands/view.js', { pacote: { packument, }, @@ -286,87 +296,63 @@ t.test('should log package info', t => { }) const viewUnicode = new ViewUnicode(unicodeNpm) - t.test('package from git', t => { - view.exec(['https://github.com/npm/green'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('package from git', async t => { + await view.exec(['https://github.com/npm/green']) + t.matchSnapshot(logs) }) - t.test('package with license, bugs, repository and other fields', t => { - view.exec(['green@1.0.0'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('package with license, bugs, repository and other fields', async t => { + await view.exec(['green@1.0.0']) + t.matchSnapshot(logs) }) - t.test('package with more than 25 deps', t => { - view.exec(['black@1.0.0'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('package with more than 25 deps', async t => { + await view.exec(['black@1.0.0']) + t.matchSnapshot(logs) }) - t.test('package with maintainers info as object', t => { - view.exec(['pink@1.0.0'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('package with maintainers info as object', async t => { + await view.exec(['pink@1.0.0']) + t.matchSnapshot(logs) }) - t.test('package with homepage', t => { - view.exec(['orange@1.0.0'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('package with homepage', async t => { + await view.exec(['orange@1.0.0']) + t.matchSnapshot(logs) }) - t.test('package with no versions', t => { - view.exec(['brown'], () => { - t.equal(logs, '', 'no info to display') - t.end() - }) + t.test('package with no versions', async t => { + await view.exec(['brown']) + t.equal(logs, '', 'no info to display') }) - t.test('package with no repo or homepage', t => { - view.exec(['blue@1.0.0'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('package with no repo or homepage', async t => { + await view.exec(['blue@1.0.0']) + t.matchSnapshot(logs) }) - t.test('package with semver range', t => { - view.exec(['blue@^1.0.0'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('package with semver range', async t => { + await view.exec(['blue@^1.0.0']) + t.matchSnapshot(logs) }) - t.test('package with no modified time', t => { - viewUnicode.exec(['cyan@1.0.0'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('package with no modified time', async t => { + await viewUnicode.exec(['cyan@1.0.0']) + t.matchSnapshot(logs) }) - t.test('package with --json and semver range', t => { - viewJson.exec(['cyan@^1.0.0'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('package with --json and semver range', async t => { + await viewJson.exec(['cyan@^1.0.0']) + t.matchSnapshot(logs) }) - t.test('package with --json and no versions', t => { - viewJson.exec(['brown'], () => { - t.equal(logs, '', 'no info to display') - t.end() - }) + t.test('package with --json and no versions', async t => { + await viewJson.exec(['brown']) + t.equal(logs, '', 'no info to display') }) - - t.end() }) -t.test('should log info of package in current working dir', t => { +t.test('should log info of package in current working dir', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({ name: 'blue', @@ -374,7 +360,7 @@ t.test('should log info of package in current working dir', t => { }, null, 2), }) - const View = t.mock('../../lib/view.js', { + const View = t.mock('../../../lib/commands/view.js', { pacote: { packument, }, @@ -387,25 +373,19 @@ t.test('should log info of package in current working dir', t => { }) const view = new View(npm) - t.test('specific version', t => { - view.exec(['.@1.0.0'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('specific version', async t => { + await view.exec(['.@1.0.0']) + t.matchSnapshot(logs) }) - t.test('non-specific version', t => { - view.exec(['.'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('non-specific version', async t => { + await view.exec(['.']) + t.matchSnapshot(logs) }) - - t.end() }) -t.test('should log info by field name', t => { - const ViewJson = t.mock('../../lib/view.js', { +t.test('should log info by field name', async t => { + const ViewJson = t.mock('../../../lib/commands/view.js', { pacote: { packument, }, @@ -419,7 +399,7 @@ t.test('should log info by field name', t => { const viewJson = new ViewJson(jsonNpm) - const View = t.mock('../../lib/view.js', { + const View = t.mock('../../../lib/commands/view.js', { pacote: { packument, }, @@ -427,74 +407,54 @@ t.test('should log info by field name', t => { const npm = mockNpm() const view = new View(npm) - t.test('readme', t => { - view.exec(['yellow@1.0.0', 'readme'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('readme', async t => { + await view.exec(['yellow@1.0.0', 'readme']) + t.matchSnapshot(logs) }) - t.test('several fields', t => { - viewJson.exec(['yellow@1.0.0', 'name', 'version', 'foo[bar]'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('several fields', async t => { + await viewJson.exec(['yellow@1.0.0', 'name', 'version', 'foo[bar]']) + t.matchSnapshot(logs) }) - t.test('several fields with several versions', t => { - view.exec(['yellow@1.x.x', 'author'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('several fields with several versions', async t => { + await view.exec(['yellow@1.x.x', 'author']) + t.matchSnapshot(logs) }) - t.test('nested field with brackets', t => { - viewJson.exec(['orange@1.0.0', 'dist[shasum]'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('nested field with brackets', async t => { + await viewJson.exec(['orange@1.0.0', 'dist[shasum]']) + t.matchSnapshot(logs) }) - t.test('maintainers with email', t => { - viewJson.exec(['yellow@1.0.0', 'maintainers', 'name'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('maintainers with email', async t => { + await viewJson.exec(['yellow@1.0.0', 'maintainers', 'name']) + t.matchSnapshot(logs) }) - t.test('maintainers with url', t => { - viewJson.exec(['pink@1.0.0', 'maintainers'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('maintainers with url', async t => { + await viewJson.exec(['pink@1.0.0', 'maintainers']) + t.matchSnapshot(logs) }) - t.test('unknown nested field ', t => { - view.exec(['yellow@1.0.0', 'dist.foobar'], () => { - t.equal(logs, '', 'no info to display') - t.end() - }) + t.test('unknown nested field ', async t => { + await view.exec(['yellow@1.0.0', 'dist.foobar']) + t.equal(logs, '', 'no info to display') }) - t.test('array field - 1 element', t => { - view.exec(['purple@1.0.0', 'maintainers.name'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('array field - 1 element', async t => { + await view.exec(['purple@1.0.0', 'maintainers.name']) + t.matchSnapshot(logs) }) - t.test('array field - 2 elements', t => { - view.exec(['yellow@1.x.x', 'maintainers.name'], () => { - t.matchSnapshot(logs) - t.end() - }) + t.test('array field - 2 elements', async t => { + await view.exec(['yellow@1.x.x', 'maintainers.name']) + t.matchSnapshot(logs) }) - - t.end() }) -t.test('throw error if global mode', (t) => { - const View = t.mock('../../lib/view.js') +t.test('throw error if global mode', async t => { + const View = t.mock('../../../lib/commands/view.js') const npm = mockNpm({ config: { global: true, @@ -502,60 +462,60 @@ t.test('throw error if global mode', (t) => { }, }) const view = new View(npm) - view.exec([], (err) => { - t.equal(err.message, 'Cannot use view command in global mode.') - t.end() - }) + await t.rejects( + view.exec([]), + /Cannot use view command in global mode./ + ) }) -t.test('throw ENOENT error if package.json misisng', (t) => { +t.test('throw ENOENT error if package.json missing', async t => { const testDir = t.testdir({}) - const View = t.mock('../../lib/view.js') + const View = t.mock('../../../lib/commands/view.js') const npm = mockNpm({ prefix: testDir, }) const view = new View(npm) - view.exec([], (err) => { - t.match(err, { code: 'ENOENT' }) - t.end() - }) + await t.rejects( + view.exec([]), + { code: 'ENOENT' } + ) }) -t.test('throw EJSONPARSE error if package.json not json', (t) => { +t.test('throw EJSONPARSE error if package.json not json', async t => { const testDir = t.testdir({ 'package.json': 'not json, nope, not even a little bit!', }) - const View = t.mock('../../lib/view.js') + const View = t.mock('../../../lib/commands/view.js') const npm = mockNpm({ prefix: testDir, }) const view = new View(npm) - view.exec([], (err) => { - t.match(err, { code: 'EJSONPARSE' }) - t.end() - }) + await t.rejects( + view.exec([]), + { code: 'EJSONPARSE' } + ) }) -t.test('throw error if package.json has no name', (t) => { +t.test('throw error if package.json has no name', async t => { const testDir = t.testdir({ 'package.json': '{}', }) - const View = t.mock('../../lib/view.js') + const View = t.mock('../../../lib/commands/view.js') const npm = mockNpm({ prefix: testDir, }) const view = new View(npm) - view.exec([], (err) => { - t.equal(err.message, 'Invalid package.json, no "name" field') - t.end() - }) + await t.rejects( + view.exec([]), + /Invalid package.json, no "name" field/ + ) }) -t.test('throws when unpublished', (t) => { - const View = t.mock('../../lib/view.js', { +t.test('throws when unpublished', async t => { + const View = t.mock('../../../lib/commands/view.js', { pacote: { packument, }, @@ -566,13 +526,13 @@ t.test('throws when unpublished', (t) => { }, }) const view = new View(npm) - view.exec(['red'], (err) => { - t.equal(err.code, 'E404') - t.end() - }) + await t.rejects( + view.exec(['red']), + { code: 'E404'} + ) }) -t.test('workspaces', t => { +t.test('workspaces', async t => { t.beforeEach(() => { warnMsg = undefined config.json = false @@ -596,7 +556,7 @@ t.test('workspaces', t => { }), }, }) - const View = t.mock('../../lib/view.js', { + const View = t.mock('../../../lib/commands/view.js', { pacote: { packument, }, @@ -617,88 +577,59 @@ t.test('workspaces', t => { }) const view = new View(npm) - t.test('all workspaces', t => { - view.execWorkspaces([], [], (err) => { - t.error(err) - t.matchSnapshot(logs) - t.end() - }) + t.test('all workspaces', async t => { + await view.execWorkspaces([], []) + t.matchSnapshot(logs) }) - t.test('one specific workspace', t => { - view.execWorkspaces([], ['green'], (err) => { - t.error(err) - t.matchSnapshot(logs) - t.end() - }) + t.test('one specific workspace', async t => { + await view.execWorkspaces([], ['green']) + t.matchSnapshot(logs) }) - t.test('all workspaces --json', t => { + t.test('all workspaces --json', async t => { config.json = true - view.execWorkspaces([], [], (err) => { - t.error(err) - t.matchSnapshot(logs) - t.end() - }) + await view.execWorkspaces([], []) + t.matchSnapshot(logs) }) - t.test('all workspaces single field', t => { - view.execWorkspaces(['.', 'name'], [], (err) => { - t.error(err) - t.matchSnapshot(logs) - t.end() - }) + t.test('all workspaces single field', async t => { + await view.execWorkspaces(['.', 'name'], []) + t.matchSnapshot(logs) }) - t.test('all workspaces nonexistent field', t => { - view.execWorkspaces(['.', 'foo'], [], (err) => { - t.error(err) - t.matchSnapshot(logs) - t.end() - }) + t.test('all workspaces nonexistent field', async t => { + await view.execWorkspaces(['.', 'foo'], []) + t.matchSnapshot(logs) }) - t.test('all workspaces nonexistent field --json', t => { + t.test('all workspaces nonexistent field --json', async t => { config.json = true - view.execWorkspaces(['.', 'foo'], [], (err) => { - t.error(err) - t.matchSnapshot(logs) - t.end() - }) + await view.execWorkspaces(['.', 'foo'], []) + t.matchSnapshot(logs) }) - t.test('all workspaces single field --json', t => { + t.test('all workspaces single field --json', async t => { config.json = true - view.execWorkspaces(['.', 'name'], [], (err) => { - t.error(err) - t.matchSnapshot(logs) - t.end() - }) + await view.execWorkspaces(['.', 'name'], []) + t.matchSnapshot(logs) }) - t.test('single workspace --json', t => { + t.test('single workspace --json', async t => { config.json = true - view.execWorkspaces([], ['green'], (err) => { - t.error(err) - t.matchSnapshot(logs) - t.end() - }) + await view.execWorkspaces([], ['green']) + t.matchSnapshot(logs) }) - t.test('remote package name', t => { - view.execWorkspaces(['pink'], [], (err) => { - t.error(err) - t.matchSnapshot(warnMsg) - t.matchSnapshot(logs) - t.end() - }) + t.test('remote package name', async t => { + await view.execWorkspaces(['pink'], []) + t.matchSnapshot(warnMsg) + t.matchSnapshot(logs) }) - - t.end() }) t.test('completion', async t => { - const View = t.mock('../../lib/view.js', { + const View = t.mock('../../../lib/commands/view.js', { pacote: { packument, }, @@ -713,11 +644,10 @@ t.test('completion', async t => { conf: { argv: { remain: ['npm', 'view', 'green@1.0.0'] } }, }) t.ok(res, 'returns back fields') - t.end() }) t.test('no registry completion', async t => { - const View = t.mock('../../lib/view.js') + const View = t.mock('../../../lib/commands/view.js') const npm = mockNpm({ config: { tag: '1.0.1', diff --git a/deps/npm/test/lib/whoami.js b/deps/npm/test/lib/commands/whoami.js similarity index 71% rename from deps/npm/test/lib/whoami.js rename to deps/npm/test/lib/commands/whoami.js index c54ee2a5a2be78..dc6144ec1dd284 100644 --- a/deps/npm/test/lib/whoami.js +++ b/deps/npm/test/lib/commands/whoami.js @@ -1,17 +1,18 @@ const t = require('tap') -const { real: mockNpm } = require('../fixtures/mock-npm') +const { real: mockNpm } = require('../../fixtures/mock-npm') const username = 'foo' -const { joinedOutput, command, npm } = mockNpm(t, { +const { joinedOutput, Npm } = mockNpm(t, { '../../lib/utils/get-identity.js': () => Promise.resolve(username), }) +const npm = new Npm() t.before(async () => { await npm.load() }) t.test('npm whoami', async (t) => { - await command('whoami') + await npm.exec('whoami', []) t.equal(joinedOutput(), username, 'should print username') }) @@ -20,6 +21,6 @@ t.test('npm whoami --json', async (t) => { npm.config.set('json', false) }) npm.config.set('json', true) - await command('whoami') + await npm.exec('whoami', []) t.equal(JSON.parse(joinedOutput()), username, 'should print username') }) diff --git a/deps/npm/test/lib/deprecate.js b/deps/npm/test/lib/deprecate.js deleted file mode 100644 index a69ef6c7796fc2..00000000000000 --- a/deps/npm/test/lib/deprecate.js +++ /dev/null @@ -1,147 +0,0 @@ -const t = require('tap') - -let getIdentityImpl = () => 'someperson' -let npmFetchBody = null - -const npmFetch = async (uri, opts) => { - npmFetchBody = opts.body -} - -npmFetch.json = async (uri, opts) => { - return { - versions: { - '1.0.0': {}, - '1.0.1': {}, - '1.0.1-pre': {}, - }, - } -} - -const Deprecate = t.mock('../../lib/deprecate.js', { - '../../lib/utils/get-identity.js': async () => getIdentityImpl(), - '../../lib/utils/otplease.js': async (opts, fn) => fn(opts), - libnpmaccess: { - lsPackages: async () => ({ foo: 'write', bar: 'write', baz: 'write', buzz: 'read' }), - }, - 'npm-registry-fetch': npmFetch, -}) - -const deprecate = new Deprecate({ - flatOptions: { registry: 'https://registry.npmjs.org' }, -}) - -t.test('completion', async t => { - const defaultIdentityImpl = getIdentityImpl - t.teardown(() => { - getIdentityImpl = defaultIdentityImpl - }) - - const testComp = async (argv, expect) => { - const res = - await deprecate.completion({ conf: { argv: { remain: argv } } }) - t.strictSame(res, expect, `completion: ${argv}`) - } - - await Promise.all([ - testComp([], ['foo', 'bar', 'baz']), - testComp(['b'], ['bar', 'baz']), - testComp(['fo'], ['foo']), - testComp(['g'], []), - testComp(['foo', 'something'], []), - ]) - - getIdentityImpl = () => { - throw new Error('deprecate test failure') - } - - t.rejects(testComp([], []), { message: 'deprecate test failure' }) -}) - -t.test('no args', t => { - deprecate.exec([], (err) => { - t.match(err, 'Usage:', 'logs usage') - t.end() - }) -}) - -t.test('only one arg', t => { - deprecate.exec(['foo'], (err) => { - t.match(err, 'Usage:', 'logs usage') - t.end() - }) -}) - -t.test('invalid semver range', t => { - deprecate.exec(['foo@notaversion', 'this will fail'], (err) => { - t.match(err, /invalid version range/, 'logs semver error') - t.end() - }) -}) - -t.test('undeprecate', t => { - deprecate.exec(['foo', ''], (err) => { - if (err) - throw err - t.match(npmFetchBody, { - versions: { - '1.0.0': { deprecated: '' }, - '1.0.1': { deprecated: '' }, - '1.0.1-pre': { deprecated: '' }, - }, - }, 'undeprecates everything') - t.end() - }) -}) - -t.test('deprecates given range', t => { - t.teardown(() => { - npmFetchBody = null - }) - - deprecate.exec(['foo@1.0.0', 'this version is deprecated'], (err) => { - if (err) - throw err - - t.match(npmFetchBody, { - versions: { - '1.0.0': { - deprecated: 'this version is deprecated', - }, - '1.0.1': { - // the undefined here is necessary to ensure that we absolutely - // did not assign this property - deprecated: undefined, - }, - }, - }) - - t.end() - }) -}) - -t.test('deprecates all versions when no range is specified', t => { - t.teardown(() => { - npmFetchBody = null - }) - - deprecate.exec(['foo', 'this version is deprecated'], (err) => { - if (err) - throw err - - t.match(npmFetchBody, { - versions: { - '1.0.0': { - deprecated: 'this version is deprecated', - }, - '1.0.1': { - deprecated: 'this version is deprecated', - }, - '1.0.1-pre': { - deprecated: 'this version is deprecated', - }, - }, - }) - - t.end() - }) -}) diff --git a/deps/npm/test/lib/dist-tag.js b/deps/npm/test/lib/dist-tag.js deleted file mode 100644 index 1fb5cb3b6ee625..00000000000000 --- a/deps/npm/test/lib/dist-tag.js +++ /dev/null @@ -1,445 +0,0 @@ -const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') - -let result = '' -let log = '' - -t.afterEach(() => { - result = '' - log = '' -}) - -const routeMap = { - '/-/package/@scoped%2fpkg/dist-tags': { - latest: '1.0.0', - a: '0.0.1', - b: '0.5.0', - }, - '/-/package/@scoped%2fanother/dist-tags': { - latest: '2.0.0', - a: '0.0.2', - b: '0.6.0', - }, - '/-/package/@scoped%2fanother/dist-tags/c': { - latest: '7.7.7', - a: '0.0.2', - b: '0.6.0', - c: '7.7.7', - }, - '/-/package/workspace-a/dist-tags': { - latest: '1.0.0', - 'latest-a': '1.0.0', - }, - '/-/package/workspace-b/dist-tags': { - latest: '2.0.0', - 'latest-b': '2.0.0', - }, - '/-/package/workspace-c/dist-tags': { - latest: '3.0.0', - 'latest-c': '3.0.0', - }, -} - -let npmRegistryFetchMock = (url, opts) => { - if (url === '/-/package/foo/dist-tags') - throw new Error('no package found') - - return routeMap[url] -} - -npmRegistryFetchMock.json = async (url, opts) => routeMap[url] - -const logger = (...msgs) => { - for (const msg of [...msgs]) - log += msg + ' ' - - log += '\n' -} - -const DistTag = t.mock('../../lib/dist-tag.js', { - npmlog: { - error: logger, - info: logger, - verbose: logger, - warn: logger, - }, - get 'npm-registry-fetch' () { - return npmRegistryFetchMock - }, -}) - -const config = {} -const npm = mockNpm({ - config, - output: msg => { - result = result ? [result, msg].join('\n') : msg - }, -}) -const distTag = new DistTag(npm) - -t.test('ls in current package', (t) => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: '@scoped/pkg', - }), - }) - distTag.exec(['ls'], (err) => { - t.error(err, 'npm dist-tags ls') - t.matchSnapshot( - result, - 'should list available tags for current package' - ) - t.end() - }) -}) - -t.test('ls global', (t) => { - t.teardown(() => { - config.global = false - }) - config.global = true - distTag.exec(['ls'], (err) => { - t.matchSnapshot( - err, - 'should throw basic usage' - ) - t.end() - }) -}) - -t.test('no args in current package', (t) => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - name: '@scoped/pkg', - }), - }) - distTag.exec([], (err) => { - t.error(err, 'npm dist-tags ls') - t.matchSnapshot( - result, - 'should default to listing available tags for current package' - ) - t.end() - }) -}) - -t.test('borked cmd usage', (t) => { - npm.prefix = t.testdir({}) - distTag.exec(['borked', '@scoped/pkg'], (err) => { - t.matchSnapshot(err, 'should show usage error') - t.end() - }) -}) - -t.test('ls on named package', (t) => { - npm.prefix = t.testdir({}) - distTag.exec(['ls', '@scoped/another'], (err) => { - t.error(err, 'npm dist-tags ls') - t.matchSnapshot( - result, - 'should list tags for the specified package' - ) - t.end() - }) -}) - -t.test('ls on missing package', (t) => { - npm.prefix = t.testdir({}) - distTag.exec(['ls', 'foo'], (err) => { - t.matchSnapshot( - log, - 'should log no dist-tag found msg' - ) - t.matchSnapshot( - err, - 'should throw error message' - ) - t.end() - }) -}) - -t.test('ls on missing name in current package', (t) => { - npm.prefix = t.testdir({ - 'package.json': JSON.stringify({ - version: '1.0.0', - }), - }) - distTag.exec(['ls'], (err) => { - t.matchSnapshot( - err, - 'should throw usage error message' - ) - t.end() - }) -}) - -t.test('only named package arg', (t) => { - npm.prefix = t.testdir({}) - distTag.exec(['@scoped/another'], (err) => { - t.error(err, 'npm dist-tags ls') - t.matchSnapshot( - result, - 'should default to listing tags for the specified package' - ) - t.end() - }) -}) - -t.test('workspaces', (t) => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'root', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], - }), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), - }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.0.0', - }), - }, - 'workspace-c': { - 'package.json': JSON.stringify({ - name: 'workspace-c', - version: '1.0.0', - }), - }, - }) - - t.test('no args', t => { - distTag.execWorkspaces([], [], (err) => { - t.error(err) - t.matchSnapshot(result, 'printed the expected output') - t.end() - }) - }) - - t.test('no args, one workspace', t => { - distTag.execWorkspaces([], ['workspace-a'], (err) => { - t.error(err) - t.matchSnapshot(result, 'printed the expected output') - t.end() - }) - }) - - t.test('one arg -- .', t => { - distTag.execWorkspaces(['.'], [], (err) => { - t.error(err) - t.matchSnapshot(result, 'printed the expected output') - t.end() - }) - }) - - t.test('one arg -- .@1, ignores version spec', t => { - distTag.execWorkspaces(['.@'], [], (err) => { - t.error(err) - t.matchSnapshot(result, 'printed the expected output') - t.end() - }) - }) - - t.test('one arg -- list', t => { - distTag.execWorkspaces(['list'], [], (err) => { - t.error(err) - t.matchSnapshot(result, 'printed the expected output') - t.end() - }) - }) - - t.test('two args -- list, .', t => { - distTag.execWorkspaces(['list', '.'], [], (err) => { - t.error(err) - t.matchSnapshot(result, 'printed the expected output') - t.end() - }) - }) - - t.test('two args -- list, .@1, ignores version spec', t => { - distTag.execWorkspaces(['list', '.@'], [], (err) => { - t.error(err) - t.matchSnapshot(result, 'printed the expected output') - t.end() - }) - }) - - t.test('two args -- list, @scoped/pkg, logs a warning and ignores workspaces', t => { - distTag.execWorkspaces(['list', '@scoped/pkg'], [], (err) => { - t.error(err) - t.match(log, 'Ignoring workspaces for specified package', 'logs a warning') - t.matchSnapshot(result, 'printed the expected output') - t.end() - }) - }) - - t.test('no args, one failing workspace sets exitCode to 1', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'root', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b', 'workspace-c', 'workspace-d'], - }), - 'workspace-a': { - 'package.json': JSON.stringify({ - name: 'workspace-a', - version: '1.0.0', - }), - }, - 'workspace-b': { - 'package.json': JSON.stringify({ - name: 'workspace-b', - version: '1.0.0', - }), - }, - 'workspace-c': { - 'package.json': JSON.stringify({ - name: 'workspace-c', - version: '1.0.0', - }), - }, - 'workspace-d': { - 'package.json': JSON.stringify({ - name: 'workspace-d', - version: '1.0.0', - }), - }, - }) - - distTag.execWorkspaces([], [], (err) => { - t.error(err) - t.equal(process.exitCode, 1, 'set the error status') - process.exitCode = 0 - t.match(log, 'dist-tag ls Couldn\'t get dist-tag data for workspace-d@latest', 'logs the error') - t.matchSnapshot(result, 'printed the expected output') - t.end() - }) - }) - - t.end() -}) - -t.test('add new tag', (t) => { - const _nrf = npmRegistryFetchMock - t.teardown(() => { - npmRegistryFetchMock = _nrf - }) - - npmRegistryFetchMock = async (url, opts) => { - t.equal(opts.method, 'PUT', 'should trigger request to add new tag') - t.equal(opts.body, '7.7.7', 'should point to expected version') - } - npm.prefix = t.testdir({}) - distTag.exec(['add', '@scoped/another@7.7.7', 'c'], (err) => { - t.error(err, 'npm dist-tags add') - t.matchSnapshot( - result, - 'should return success msg' - ) - t.end() - }) -}) - -t.test('add using valid semver range as name', (t) => { - npm.prefix = t.testdir({}) - distTag.exec(['add', '@scoped/another@7.7.7', '1.0.0'], (err) => { - t.match( - err, - /Error: Tag name must not be a valid SemVer range: 1.0.0/, - 'should exit with semver range error' - ) - t.matchSnapshot( - log, - 'should return success msg' - ) - t.end() - }) -}) - -t.test('add missing args', (t) => { - npm.prefix = t.testdir({}) - config.tag = '' - t.teardown(() => { - delete config.tag - }) - distTag.exec(['add', '@scoped/another@7.7.7'], (err) => { - t.matchSnapshot(err, 'should exit usage error message') - t.end() - }) -}) - -t.test('add missing pkg name', (t) => { - npm.prefix = t.testdir({}) - distTag.exec(['add', null], (err) => { - t.matchSnapshot(err, 'should exit usage error message') - t.end() - }) -}) - -t.test('set existing version', (t) => { - npm.prefix = t.testdir({}) - distTag.exec(['set', '@scoped/another@0.6.0', 'b'], (err) => { - t.error(err, 'npm dist-tags set') - t.matchSnapshot( - log, - 'should log warn msg' - ) - t.end() - }) -}) - -t.test('remove existing tag', (t) => { - const _nrf = npmRegistryFetchMock - t.teardown(() => { - npmRegistryFetchMock = _nrf - }) - - npmRegistryFetchMock = async (url, opts) => { - t.equal(opts.method, 'DELETE', 'should trigger request to remove tag') - } - npm.prefix = t.testdir({}) - distTag.exec(['rm', '@scoped/another', 'c'], (err) => { - t.error(err, 'npm dist-tags rm') - t.matchSnapshot(log, 'should log remove info') - t.matchSnapshot(result, 'should return success msg') - t.end() - }) -}) - -t.test('remove non-existing tag', (t) => { - npm.prefix = t.testdir({}) - distTag.exec(['rm', '@scoped/another', 'nonexistent'], (err) => { - t.match( - err, - /Error: nonexistent is not a dist-tag on @scoped\/another/, - 'should exit with error' - ) - t.matchSnapshot(log, 'should log error msg') - t.end() - }) -}) - -t.test('remove missing pkg name', (t) => { - npm.prefix = t.testdir({}) - distTag.exec(['rm', null], (err) => { - t.matchSnapshot(err, 'should exit usage error message') - t.end() - }) -}) - -t.test('completion', t => { - const { completion } = distTag - t.plan(2) - - const match = completion({ conf: { argv: { remain: ['npm', 'dist-tag'] } } }) - t.resolveMatch(match, ['add', 'rm', 'ls'], - 'should list npm dist-tag commands for completion') - - const noMatch = completion({ conf: { argv: { remain: ['npm', 'dist-tag', 'foobar'] } } }) - t.resolveMatch(noMatch, []) - t.end() -}) diff --git a/deps/npm/test/lib/doctor.js b/deps/npm/test/lib/doctor.js deleted file mode 100644 index 0ceb670c150546..00000000000000 --- a/deps/npm/test/lib/doctor.js +++ /dev/null @@ -1,962 +0,0 @@ -const t = require('tap') - -const { join } = require('path') -const fs = require('fs') -const ansiTrim = require('../../lib/utils/ansi-trim.js') -const isWindows = require('../../lib/utils/is-windows.js') - -// getuid and getgid do not exist in windows, so we shim them -// to return 0, as that is the value that lstat will assign the -// gid and uid properties for fs.Stats objects -if (isWindows) { - process.getuid = () => 0 - process.getgid = () => 0 -} - -const output = [] - -let pingError -const ping = async () => { - if (pingError) - throw pingError -} - -let whichError = null -const which = async () => { - if (whichError) - throw whichError - return '/path/to/git' -} - -const nodeVersions = [ - { version: 'v14.0.0', lts: false }, - { version: 'v13.0.0', lts: false }, - // it's necessary to allow tests in node 10.x to not mark 12.x as lts - { version: 'v12.0.0', lts: false }, - { version: 'v10.13.0', lts: 'Dubnium' }, -] - -const fetch = async () => { - return { - json: async () => { - return nodeVersions - }, - } -} - -const logs = { - info: [], -} - -const clearLogs = (obj = logs) => { - output.length = 0 - for (const key in obj) { - if (Array.isArray(obj[key])) - obj[key].length = 0 - else - delete obj[key] - } -} - -const npm = { - flatOptions: { - registry: 'https://registry.npmjs.org/', - }, - log: { - info: (msg) => { - logs.info.push(msg) - }, - newItem: (name) => { - logs[name] = {} - - return { - info: (_, msg) => { - if (!logs[name].info) - logs[name].info = [] - logs[name].info.push(msg) - }, - warn: (_, msg) => { - if (!logs[name].warn) - logs[name].warn = [] - logs[name].warn.push(msg) - }, - error: (_, msg) => { - if (!logs[name].error) - logs[name].error = [] - logs[name].error.push(msg) - }, - silly: (_, msg) => { - if (!logs[name].silly) - logs[name].silly = [] - logs[name].silly.push(msg) - }, - completeWork: () => {}, - finish: () => { - logs[name].finished = true - }, - } - }, - level: 'error', - levels: { - info: 1, - error: 0, - }, - }, - version: '7.1.0', - output: (data) => { - output.push(data) - }, -} - -let latestNpm = npm.version -const pacote = { - manifest: async () => { - return { version: latestNpm } - }, -} - -let verifyResponse = { verifiedCount: 1, verifiedContent: 1 } -const cacache = { - verify: async () => { - return verifyResponse - }, -} - -const Doctor = t.mock('../../lib/doctor.js', { - '../../lib/utils/is-windows.js': false, - '../../lib/utils/ping.js': ping, - cacache, - pacote, - 'make-fetch-happen': fetch, - which, -}) -const doctor = new Doctor(npm) - -const origVersion = process.version -t.test('node versions', t => { - t.plan(nodeVersions.length) - - nodeVersions.forEach(({ version }) => { - t.test(`${version}:`, vt => { - Object.defineProperty(process, 'version', { value: version }) - vt.teardown(() => { - Object.defineProperty(process, 'version', { value: origVersion }) - }) - - vt.test(`${version}: npm doctor checks ok`, st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - clearLogs() - }) - - doctor.exec([], (err) => { - if (err) { - st.fail(output) - return st.end() - } - - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - st.end() - }) - }) - - vt.test('npm doctor supports silent', st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - npm.log.level = 'info' - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - npm.log.level = 'error' - clearLogs() - }) - - doctor.exec([], (err) => { - if (err) { - st.fail(err) - return st.end() - } - - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.strictSame(output, [], 'did not print output') - st.end() - }) - }) - - vt.test('npm doctor supports color', st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - npm.color = true - pingError = { message: 'generic error' } - const _consoleError = console.error - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - delete npm.color - pingError = null - console.error = _consoleError - clearLogs() - }) - - doctor.exec([], (err) => { - st.match(err, /Some problems found/, 'detected the ping error') - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.match(output, /npm ping.*not ok/, 'ping output is ok') - st.match(output, /npm -v.*ok/, 'npm -v output is ok') - st.match(output, /node -v.*ok/, 'node -v output is ok') - st.match(output, /npm config get registry.*ok.*using default/, 'npm config get registry output is ok') - st.match(output, /which git.*ok/, 'which git output is ok') - st.match(output, /cached files.*ok/, 'cached files are ok') - st.match(output, /local node_modules.*ok/, 'local node_modules are ok') - st.match(output, /global node_modules.*ok/, 'global node_modules are ok') - st.match(output, /local bin folder.*ok/, 'local bin is ok') - st.match(output, /global bin folder.*ok/, 'global bin is ok') - st.match(output, /cache contents.*ok/, 'cache contents is ok') - st.not(output[0], ansiTrim(output[0]), 'output should contain color codes') - st.end() - }) - }) - - vt.test('npm doctor skips some tests in windows', st => { - const WinDoctor = t.mock('../../lib/doctor.js', { - '../../lib/utils/is-windows.js': true, - '../../lib/utils/ping.js': ping, - cacache, - pacote, - 'make-fetch-happen': fetch, - which, - }) - const winDoctor = new WinDoctor(npm) - - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - clearLogs() - }) - - winDoctor.exec([], (err) => { - if (err) { - st.fail(output) - return st.end() - } - - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: undefined, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - st.end() - }) - }) - - vt.test('npm doctor ping error E{3}', st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - pingError = { code: 'E111', message: 'this error is 111' } - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - pingError = null - console.error = consoleError - clearLogs() - }) - - doctor.exec([], (err) => { - st.match(err, /Some problems found/, 'detected the ping error') - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.match(output, /npm ping\s*not ok\s*111 this error is 111/, 'ping output contains trimmed error') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - st.end() - }) - }) - - vt.test('npm doctor generic ping error', st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - pingError = { message: 'generic error' } - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - pingError = null - console.error = consoleError - clearLogs() - }) - - doctor.exec([], (err) => { - st.match(err, /Some problems found/, 'detected the ping error') - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.match(output, /npm ping\s*not ok\s*generic error/, 'ping output contains trimmed error') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - st.end() - }) - }) - - vt.test('npm doctor outdated npm version', st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - latestNpm = '7.1.1' - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - latestNpm = npm.version - console.error = consoleError - clearLogs() - }) - - doctor.exec([], (err) => { - st.match(err, /Some problems found/, 'detected the out of date npm') - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*not ok/, 'npm -v output is not ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - st.end() - }) - }) - - vt.test('npm doctor file permission checks', st => { - const dir = st.testdir({ - cache: { - one: 'one', - link: st.fixture('symlink', './baddir'), - unreadable: 'unreadable', - baddir: {}, - }, - local: { - two: 'two', - notmine: 'notmine', - }, - global: { - three: 'three', - broken: 'broken', - }, - localBin: { - four: 'four', - five: 'five', - }, - globalBin: { - six: 'six', - seven: 'seven', - }, - }) - - const _fsLstat = fs.lstat - fs.lstat = (p, cb) => { - let err = null - let stat = null - - try { - stat = fs.lstatSync(p) - } catch (err) { - return cb(err) - } - - switch (p) { - case join(dir, 'local', 'notmine'): - stat.uid += 1 - stat.gid += 1 - break - case join(dir, 'global', 'broken'): - err = new Error('broken') - break - } - - return cb(err, stat) - } - - const _fsReaddir = fs.readdir - fs.readdir = (p, cb) => { - let err = null - let result = null - - try { - result = fs.readdirSync(p) - } catch (err) { - return cb(err) - } - - if (p === join(dir, 'cache', 'baddir')) - err = new Error('broken') - - return cb(err, result) - } - - const _fsAccess = fs.access - fs.access = (p, mask, cb) => { - const err = new Error('failed') - switch (p) { - case join(dir, 'cache', 'unreadable'): - case join(dir, 'localBin', 'four'): - case join(dir, 'globalBin', 'six'): - return cb(err) - default: - return cb(null) - } - } - - const Doctor = t.mock('../../lib/doctor.js', { - '../../lib/utils/is-windows.js': false, - '../../lib/utils/ping.js': ping, - cacache, - pacote, - 'make-fetch-happen': fetch, - which, - fs, - }) - const doctor = new Doctor(npm) - // it's necessary to allow tests in node 10.x to not mark 12.x as lted - - npm.cache = npm.flatOptions.cache = join(dir, 'cache') - npm.localDir = join(dir, 'local') - npm.globalDir = join(dir, 'global') - npm.localBin = join(dir, 'localBin') - npm.globalBin = join(dir, 'globalBin') - const _consoleError = console.error - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - console.error = _consoleError - fs.lstat = _fsLstat - fs.readdir = _fsReaddir - fs.access = _fsAccess - clearLogs() - }) - - doctor.exec([], (err) => { - st.match(err, /Some problems found/, 'identified problems') - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [join(dir, 'cache')]: { finished: true }, - [join(dir, 'local')]: { finished: true }, - [join(dir, 'global')]: { finished: true }, - [join(dir, 'localBin')]: { finished: true }, - [join(dir, 'globalBin')]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*not ok/, 'cached files are not ok') - st.match(output, /local node_modules\s*not ok/, 'local node_modules are not ok') - st.match(output, /global node_modules\s*not ok/, 'global node_modules are not ok') - st.match(output, /local bin folder\s*not ok/, 'local bin is not ok') - st.match(output, /global bin folder\s*not ok/, 'global bin is not ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - st.end() - }) - }) - - vt.test('npm doctor missing git', st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - whichError = new Error('boom') - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - whichError = null - console.error = consoleError - clearLogs() - }) - - doctor.exec([], (err) => { - st.match(err, /Some problems found/, 'detected the missing git') - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') - st.match(output, /which git\s*not ok/, 'which git output is not ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - st.end() - }) - }) - - vt.test('npm doctor cache verification showed bad content', st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - const _verifyResponse = verifyResponse - verifyResponse = { - ...verifyResponse, - badContentCount: 1, - } - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - verifyResponse = _verifyResponse - console.error = consoleError - clearLogs() - }) - - doctor.exec([], (err) => { - // cache verification problems get fixed and so do not throw an error - if (err) { - st.fail(output) - return st.end() - } - - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is not ok') - st.end() - }) - }) - - vt.test('npm doctor cache verification showed reclaimed content', st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - const _verifyResponse = verifyResponse - verifyResponse = { - ...verifyResponse, - reclaimedCount: 1, - reclaimedSize: 100, - } - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - verifyResponse = _verifyResponse - console.error = consoleError - clearLogs() - }) - - doctor.exec([], (err) => { - // cache verification problems get fixed and so do not throw an error - if (err) { - st.fail(output) - return st.end() - } - - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is not ok') - st.end() - }) - }) - - vt.test('npm doctor cache verification showed missing content', st => { - const dir = t.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - const _verifyResponse = verifyResponse - verifyResponse = { - ...verifyResponse, - missingContent: 1, - } - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - verifyResponse = _verifyResponse - console.error = consoleError - clearLogs() - }) - - doctor.exec([], (err) => { - // cache verification problems get fixed and so do not throw an error - if (err) { - st.fail(output) - return st.end() - } - - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is not ok') - st.end() - }) - }) - - vt.test('npm doctor not using default registry', st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - const _currentRegistry = npm.flatOptions.registry - npm.flatOptions.registry = 'https://google.com' - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - npm.flatOptions.registry = _currentRegistry - console.error = consoleError - clearLogs() - }) - - doctor.exec([], (err) => { - // cache verification problems get fixed and so do not throw an error - st.match(err, /Some problems found/, 'detected the non-default registry') - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match(output, /npm config get registry\s*not ok/, 'npm config get registry output is not ok') - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - st.end() - }) - }) - - vt.end() - }) - }) -}) - -t.test('outdated node version', vt => { - vt.plan(1) - const version = 'v10.0.0' - - Object.defineProperty(process, 'version', { value: version }) - vt.teardown(() => { - Object.defineProperty(process, 'version', { value: origVersion }) - }) - - vt.test('npm doctor outdated nodejs version', st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - nodeVersions.push({ version: process.version.replace(/\d+(-.*)?$/, '999'), lts: false }) - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - nodeVersions.pop() - console.error = consoleError - clearLogs() - }) - - doctor.exec([], (err) => { - st.match(err, /Some problems found/, 'detected the out of date nodejs') - st.match(logs, { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, 'trackers all finished') - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*not ok/, 'node -v output is not ok') - st.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok') - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - st.end() - }) - }) -}) diff --git a/deps/npm/test/lib/edit.js b/deps/npm/test/lib/edit.js deleted file mode 100644 index 09908165d77222..00000000000000 --- a/deps/npm/test/lib/edit.js +++ /dev/null @@ -1,144 +0,0 @@ -const t = require('tap') -const { resolve } = require('path') -const { EventEmitter } = require('events') - -let editorBin = null -let editorArgs = null -let editorOpts = null -let EDITOR_CODE = 0 -const childProcess = { - spawn: (bin, args, opts) => { - // save for assertions - editorBin = bin - editorArgs = args - editorOpts = opts - - const editorEvents = new EventEmitter() - process.nextTick(() => { - editorEvents.emit('exit', EDITOR_CODE) - }) - return editorEvents - }, -} - -let rebuildArgs = null -let rebuildFail = null -let EDITOR = 'vim' -const npm = { - config: { - get: () => EDITOR, - }, - dir: resolve(__dirname, '../../node_modules'), - commands: { - rebuild: (args, cb) => { - rebuildArgs = args - return cb(rebuildFail) - }, - }, -} - -const gracefulFs = require('graceful-fs') -const Edit = t.mock('../../lib/edit.js', { - child_process: childProcess, - 'graceful-fs': gracefulFs, -}) -const edit = new Edit(npm) - -t.test('npm edit', t => { - t.teardown(() => { - rebuildArgs = null - editorBin = null - editorArgs = null - editorOpts = null - }) - - return edit.exec(['semver'], (err) => { - if (err) - throw err - - const path = resolve(__dirname, '../../node_modules/semver') - t.strictSame(editorBin, EDITOR, 'used the correct editor') - t.strictSame(editorArgs, [path], 'edited the correct directory') - t.strictSame(editorOpts, { stdio: 'inherit' }, 'passed the correct opts') - t.strictSame(rebuildArgs, [path], 'passed the correct path to rebuild') - t.end() - }) -}) - -t.test('rebuild fails', t => { - t.teardown(() => { - rebuildFail = null - rebuildArgs = null - editorBin = null - editorArgs = null - editorOpts = null - }) - - rebuildFail = new Error('test error') - return edit.exec(['semver'], (err) => { - const path = resolve(__dirname, '../../node_modules/semver') - t.strictSame(editorBin, EDITOR, 'used the correct editor') - t.strictSame(editorArgs, [path], 'edited the correct directory') - t.strictSame(editorOpts, { stdio: 'inherit' }, 'passed the correct opts') - t.strictSame(rebuildArgs, [path], 'passed the correct path to rebuild') - t.match(err, { message: 'test error' }) - t.end() - }) -}) - -t.test('npm edit editor has flags', t => { - EDITOR = 'code -w' - t.teardown(() => { - rebuildArgs = null - editorBin = null - editorArgs = null - editorOpts = null - EDITOR = 'vim' - }) - - return edit.exec(['semver'], (err) => { - if (err) - throw err - - const path = resolve(__dirname, '../../node_modules/semver') - t.strictSame(editorBin, 'code', 'used the correct editor') - t.strictSame(editorArgs, ['-w', path], 'edited the correct directory, keeping flags') - t.strictSame(editorOpts, { stdio: 'inherit' }, 'passed the correct opts') - t.strictSame(rebuildArgs, [path], 'passed the correct path to rebuild') - t.end() - }) -}) - -t.test('npm edit no args', t => { - return edit.exec([], (err) => { - t.match(err, /npm edit/, 'throws usage error') - t.end() - }) -}) - -t.test('npm edit lstat error propagates', t => { - const _lstat = gracefulFs.lstat - gracefulFs.lstat = (dir, cb) => { - return cb(new Error('lstat failed')) - } - t.teardown(() => { - gracefulFs.lstat = _lstat - }) - - return edit.exec(['semver'], (err) => { - t.match(err, /lstat failed/, 'user received correct error') - t.end() - }) -}) - -t.test('npm edit editor exit code error propagates', t => { - EDITOR_CODE = 137 - t.teardown(() => { - EDITOR_CODE = 0 - }) - - return edit.exec(['semver'], (err) => { - t.match(err, /exited with code: 137/, 'user received correct error') - t.end() - }) -}) diff --git a/deps/npm/test/lib/hook.js b/deps/npm/test/lib/hook.js deleted file mode 100644 index 2419f160417482..00000000000000 --- a/deps/npm/test/lib/hook.js +++ /dev/null @@ -1,588 +0,0 @@ -const t = require('tap') - -const output = [] -const npm = { - flatOptions: { - json: false, - parseable: false, - silent: false, - loglevel: 'info', - unicode: false, - }, - output: (msg) => { - output.push(msg) - }, -} - -const pkgTypes = { - semver: 'package', - '@npmcli': 'scope', - npm: 'owner', -} - -const now = Date.now() -let hookResponse = null -let hookArgs = null -const libnpmhook = { - add: async (pkg, uri, secret, opts) => { - hookArgs = { pkg, uri, secret, opts } - return { id: 1, name: pkg.replace(/^@/, ''), type: pkgTypes[pkg], endpoint: uri } - }, - ls: async (opts) => { - hookArgs = opts - let id = 0 - if (hookResponse) - return hookResponse - - return Object.keys(pkgTypes).map((name) => ({ - id: ++id, - name: name.replace(/^@/, ''), - type: pkgTypes[name], - endpoint: 'https://google.com', - last_delivery: id % 2 === 0 ? now : undefined, - })) - }, - rm: async (id, opts) => { - hookArgs = { id, opts } - const pkg = Object.keys(pkgTypes)[0] - return { id: 1, name: pkg.replace(/^@/, ''), type: pkgTypes[pkg], endpoint: 'https://google.com' } - }, - update: async (id, uri, secret, opts) => { - hookArgs = { id, uri, secret, opts } - const pkg = Object.keys(pkgTypes)[0] - return { id, name: pkg.replace(/^@/, ''), type: pkgTypes[pkg], endpoint: uri } - }, -} - -const Hook = t.mock('../../lib/hook.js', { - '../../lib/utils/otplease.js': async (opts, fn) => fn(opts), - libnpmhook, -}) -const hook = new Hook(npm) - -t.test('npm hook no args', t => { - return hook.exec([], (err) => { - t.match(err, /npm hook add/, 'throws usage with no arguments') - t.end() - }) -}) - -t.test('npm hook add', t => { - t.teardown(() => { - hookArgs = null - output.length = 0 - }) - - return hook.exec(['add', 'semver', 'https://google.com', 'some-secret'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - pkg: 'semver', - uri: 'https://google.com', - secret: 'some-secret', - opts: npm.flatOptions, - }, 'provided the correct arguments to libnpmhook') - t.strictSame(output, ['+ semver -> https://google.com'], 'prints the correct output') - t.end() - }) -}) - -t.test('npm hook add - unicode output', t => { - npm.flatOptions.unicode = true - t.teardown(() => { - npm.flatOptions.unicode = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['add', 'semver', 'https://google.com', 'some-secret'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - pkg: 'semver', - uri: 'https://google.com', - secret: 'some-secret', - opts: npm.flatOptions, - }, 'provided the correct arguments to libnpmhook') - t.strictSame(output, ['+ semver ➜ https://google.com'], 'prints the correct output') - t.end() - }) -}) - -t.test('npm hook add - json output', t => { - npm.flatOptions.json = true - t.teardown(() => { - npm.flatOptions.json = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['add', '@npmcli', 'https://google.com', 'some-secret'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - pkg: '@npmcli', - uri: 'https://google.com', - secret: 'some-secret', - opts: npm.flatOptions, - }, 'provided the correct arguments to libnpmhook') - t.strictSame(JSON.parse(output[0]), { - id: 1, - name: 'npmcli', - endpoint: 'https://google.com', - type: 'scope', - }, 'prints the correct json output') - t.end() - }) -}) - -t.test('npm hook add - parseable output', t => { - npm.flatOptions.parseable = true - t.teardown(() => { - npm.flatOptions.parseable = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['add', '@npmcli', 'https://google.com', 'some-secret'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - pkg: '@npmcli', - uri: 'https://google.com', - secret: 'some-secret', - opts: npm.flatOptions, - }, 'provided the correct arguments to libnpmhook') - t.strictSame(output[0].split(/\t/), [ - 'id', 'name', 'type', 'endpoint', - ], 'prints the correct parseable output headers') - t.strictSame(output[1].split(/\t/), [ - '1', 'npmcli', 'scope', 'https://google.com', - ], 'prints the correct parseable values') - t.end() - }) -}) - -t.test('npm hook add - silent output', t => { - npm.flatOptions.silent = true - t.teardown(() => { - npm.flatOptions.silent = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['add', '@npmcli', 'https://google.com', 'some-secret'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - pkg: '@npmcli', - uri: 'https://google.com', - secret: 'some-secret', - opts: npm.flatOptions, - }, 'provided the correct arguments to libnpmhook') - t.strictSame(output, [], 'printed no output') - t.end() - }) -}) - -t.test('npm hook ls', t => { - t.teardown(() => { - hookArgs = null - output.length = 0 - }) - - return hook.exec(['ls'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - ...npm.flatOptions, - package: undefined, - }, 'received the correct arguments') - t.equal(output[0], 'You have 3 hooks configured.', 'prints the correct header') - const out = require('../../lib/utils/ansi-trim')(output[1]) - t.match(out, /semver.*https:\/\/google.com.*\n.*\n.*never triggered/, 'prints package hook') - t.match(out, /@npmcli.*https:\/\/google.com.*\n.*\n.*triggered just now/, 'prints scope hook') - t.match(out, /~npm.*https:\/\/google.com.*\n.*\n.*never triggered/, 'prints owner hook') - t.end() - }) -}) - -t.test('npm hook ls, no results', t => { - hookResponse = [] - t.teardown(() => { - hookResponse = null - hookArgs = null - output.length = 0 - }) - - return hook.exec(['ls'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - ...npm.flatOptions, - package: undefined, - }, 'received the correct arguments') - t.equal(output[0], 'You don\'t have any hooks configured yet.', 'prints the correct result') - t.end() - }) -}) - -t.test('npm hook ls, single result', t => { - hookResponse = [{ - id: 1, - name: 'semver', - type: 'package', - endpoint: 'https://google.com', - }] - - t.teardown(() => { - hookResponse = null - hookArgs = null - output.length = 0 - }) - - return hook.exec(['ls'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - ...npm.flatOptions, - package: undefined, - }, 'received the correct arguments') - t.equal(output[0], 'You have one hook configured.', 'prints the correct header') - const out = require('../../lib/utils/ansi-trim')(output[1]) - t.match(out, /semver.*https:\/\/google.com.*\n.*\n.*never triggered/, 'prints package hook') - t.end() - }) -}) - -t.test('npm hook ls - json output', t => { - npm.flatOptions.json = true - t.teardown(() => { - npm.flatOptions.json = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['ls'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - ...npm.flatOptions, - package: undefined, - }, 'received the correct arguments') - const out = JSON.parse(output[0]) - t.match(out, [{ - id: 1, - name: 'semver', - type: 'package', - endpoint: 'https://google.com', - }, { - id: 2, - name: 'npmcli', - type: 'scope', - endpoint: 'https://google.com', - }, { - id: 3, - name: 'npm', - type: 'owner', - endpoint: 'https://google.com', - }], 'prints the correct output') - t.end() - }) -}) - -t.test('npm hook ls - parseable output', t => { - npm.flatOptions.parseable = true - t.teardown(() => { - npm.flatOptions.parseable = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['ls'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - ...npm.flatOptions, - package: undefined, - }, 'received the correct arguments') - t.strictSame(output.map(line => line.split(/\t/)), [ - ['id', 'name', 'type', 'endpoint', 'last_delivery'], - ['1', 'semver', 'package', 'https://google.com', ''], - ['2', 'npmcli', 'scope', 'https://google.com', `${now}`], - ['3', 'npm', 'owner', 'https://google.com', ''], - ], 'prints the correct result') - t.end() - }) -}) - -t.test('npm hook ls - silent output', t => { - npm.flatOptions.silent = true - t.teardown(() => { - npm.flatOptions.silent = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['ls'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - ...npm.flatOptions, - package: undefined, - }, 'received the correct arguments') - t.strictSame(output, [], 'printed no output') - t.end() - }) -}) - -t.test('npm hook rm', t => { - t.teardown(() => { - hookArgs = null - output.length = 0 - }) - - return hook.exec(['rm', '1'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - id: '1', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.strictSame(output, [ - '- semver X https://google.com', - ], 'printed the correct output') - t.end() - }) -}) - -t.test('npm hook rm - unicode output', t => { - npm.flatOptions.unicode = true - t.teardown(() => { - npm.flatOptions.unicode = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['rm', '1'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - id: '1', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.strictSame(output, [ - '- semver ✘ https://google.com', - ], 'printed the correct output') - t.end() - }) -}) - -t.test('npm hook rm - silent output', t => { - npm.flatOptions.silent = true - t.teardown(() => { - npm.flatOptions.silent = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['rm', '1'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - id: '1', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.strictSame(output, [], 'printed no output') - t.end() - }) -}) - -t.test('npm hook rm - json output', t => { - npm.flatOptions.json = true - t.teardown(() => { - npm.flatOptions.json = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['rm', '1'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - id: '1', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.strictSame(JSON.parse(output[0]), { - id: 1, - name: 'semver', - type: 'package', - endpoint: 'https://google.com', - }, 'printed correct output') - t.end() - }) -}) - -t.test('npm hook rm - parseable output', t => { - npm.flatOptions.parseable = true - t.teardown(() => { - npm.flatOptions.parseable = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['rm', '1'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - id: '1', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.strictSame(output.map(line => line.split(/\t/)), [ - ['id', 'name', 'type', 'endpoint'], - ['1', 'semver', 'package', 'https://google.com'], - ], 'printed correct output') - t.end() - }) -}) - -t.test('npm hook update', t => { - t.teardown(() => { - hookArgs = null - output.length = 0 - }) - - return hook.exec(['update', '1', 'https://google.com', 'some-secret'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - id: '1', - uri: 'https://google.com', - secret: 'some-secret', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.strictSame(output, [ - '+ semver -> https://google.com', - ], 'printed the correct output') - t.end() - }) -}) - -t.test('npm hook update - unicode', t => { - npm.flatOptions.unicode = true - t.teardown(() => { - npm.flatOptions.unicode = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['update', '1', 'https://google.com', 'some-secret'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - id: '1', - uri: 'https://google.com', - secret: 'some-secret', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.strictSame(output, [ - '+ semver ➜ https://google.com', - ], 'printed the correct output') - t.end() - }) -}) - -t.test('npm hook update - json output', t => { - npm.flatOptions.json = true - t.teardown(() => { - npm.flatOptions.json = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['update', '1', 'https://google.com', 'some-secret'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - id: '1', - uri: 'https://google.com', - secret: 'some-secret', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.strictSame(JSON.parse(output[0]), { - id: '1', - name: 'semver', - type: 'package', - endpoint: 'https://google.com', - }, 'printed the correct output') - t.end() - }) -}) - -t.test('npm hook update - parseable output', t => { - npm.flatOptions.parseable = true - t.teardown(() => { - npm.flatOptions.parseable = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['update', '1', 'https://google.com', 'some-secret'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - id: '1', - uri: 'https://google.com', - secret: 'some-secret', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.strictSame(output.map(line => line.split(/\t/)), [ - ['id', 'name', 'type', 'endpoint'], - ['1', 'semver', 'package', 'https://google.com'], - ], 'printed the correct output') - t.end() - }) -}) - -t.test('npm hook update - silent output', t => { - npm.flatOptions.silent = true - t.teardown(() => { - npm.flatOptions.silent = false - hookArgs = null - output.length = 0 - }) - - return hook.exec(['update', '1', 'https://google.com', 'some-secret'], (err) => { - if (err) - throw err - - t.strictSame(hookArgs, { - id: '1', - uri: 'https://google.com', - secret: 'some-secret', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.strictSame(output, [], 'printed no output') - t.end() - }) -}) diff --git a/deps/npm/test/lib/install-ci-test.js b/deps/npm/test/lib/install-ci-test.js deleted file mode 100644 index 2695e0f13decb3..00000000000000 --- a/deps/npm/test/lib/install-ci-test.js +++ /dev/null @@ -1,56 +0,0 @@ -const t = require('tap') - -const InstallCITest = require('../../lib/install-ci-test.js') - -let ciArgs = null -let ciCalled = false -let testArgs = null -let testCalled = false -let ciError = null - -const installCITest = new InstallCITest({ - commands: { - ci: (args, cb) => { - ciArgs = args - ciCalled = true - cb(ciError) - }, - test: (args, cb) => { - testArgs = args - testCalled = true - cb() - }, - }, -}) - -t.test('the install-ci-test command', t => { - t.afterEach(() => { - ciArgs = null - ciCalled = false - testArgs = null - testCalled = false - ciError = null - }) - - t.test('ci and test', t => { - installCITest.exec(['extra'], () => { - t.equal(ciCalled, true) - t.equal(testCalled, true) - t.match(ciArgs, ['extra']) - t.match(testArgs, []) - t.end() - }) - }) - - t.test('ci fails', t => { - ciError = new Error('test fail') - installCITest.exec(['extra'], (err) => { - t.equal(ciCalled, true) - t.equal(testCalled, false) - t.match(ciArgs, ['extra']) - t.match(err, { message: 'test fail' }) - t.end() - }) - }) - t.end() -}) diff --git a/deps/npm/test/lib/install-test.js b/deps/npm/test/lib/install-test.js deleted file mode 100644 index adec91b6199230..00000000000000 --- a/deps/npm/test/lib/install-test.js +++ /dev/null @@ -1,56 +0,0 @@ -const t = require('tap') - -const InstallTest = require('../../lib/install-test.js') - -let installArgs = null -let installCalled = false -let testArgs = null -let testCalled = false -let installError = null - -const installTest = new InstallTest({ - commands: { - install: (args, cb) => { - installArgs = args - installCalled = true - cb(installError) - }, - test: (args, cb) => { - testArgs = args - testCalled = true - cb() - }, - }, -}) - -t.test('the install-test command', t => { - t.afterEach(() => { - installArgs = null - installCalled = false - testArgs = null - testCalled = false - installError = null - }) - - t.test('install and test', t => { - installTest.exec(['extra'], () => { - t.equal(installCalled, true) - t.equal(testCalled, true) - t.match(installArgs, ['extra']) - t.match(testArgs, []) - t.end() - }) - }) - - t.test('install fails', t => { - installError = new Error('test fail') - installTest.exec(['extra'], (err) => { - t.equal(installCalled, true) - t.equal(testCalled, false) - t.match(installArgs, ['extra']) - t.match(err, { message: 'test fail' }) - t.end() - }) - }) - t.end() -}) diff --git a/deps/npm/test/lib/lifecycle-cmd.js b/deps/npm/test/lib/lifecycle-cmd.js new file mode 100644 index 00000000000000..eb03f19270be01 --- /dev/null +++ b/deps/npm/test/lib/lifecycle-cmd.js @@ -0,0 +1,28 @@ +const t = require('tap') +const LifecycleCmd = require('../../lib/lifecycle-cmd.js') +let runArgs = null +const npm = { + exec: async (cmd, args) => { + if (cmd === 'run-script') { + runArgs = args + return 'called the right thing' + } + }, +} +t.test('create a lifecycle command', async t => { + t.plan(5) + class TestStage extends LifecycleCmd { + static get name () { + return 'test-stage' + } + } + const cmd = new TestStage(npm) + t.match(cmd.usage, /test-stage/) + let result + result = await cmd.exec(['some', 'args']) + t.same(runArgs, ['test-stage', 'some', 'args']) + t.strictSame(result, 'called the right thing') + result = await cmd.execWorkspaces(['some', 'args'], []) + t.same(runArgs, ['test-stage', 'some', 'args']) + t.strictSame(result, 'called the right thing') +}) diff --git a/deps/npm/test/lib/load-all-commands.js b/deps/npm/test/lib/load-all-commands.js index e5f10099cf365c..e9d61f9c1f69e6 100644 --- a/deps/npm/test/lib/load-all-commands.js +++ b/deps/npm/test/lib/load-all-commands.js @@ -3,36 +3,37 @@ // name, a description, and if it has completion it is a function. That it // renders also ensures that any params we've defined in our commands work. const t = require('tap') +const util = require('util') const { real: mockNpm } = require('../fixtures/mock-npm.js') const { cmdList } = require('../../lib/utils/cmd-list.js') -const { npm, outputs } = mockNpm(t) +const { Npm, outputs } = mockNpm(t) +const npm = new Npm() -t.test('load each command', t => { - t.plan(cmdList.length) - npm.load((er) => { - if (er) - throw er - npm.config.set('usage', true) - for (const cmd of cmdList.sort((a, b) => a.localeCompare(b, 'en'))) { - t.test(cmd, t => { - const impl = npm.commands[cmd] - if (impl.completion) - t.type(impl.completion, 'function', 'completion, if present, is a function') - t.type(impl, 'function', 'implementation is a function') - t.ok(impl.description, 'implementation has a description') - t.ok(impl.name, 'implementation has a name') - t.match(impl.usage, cmd, 'usage contains the command') - impl([], (err) => { - t.notOk(err) - t.match(outputs[0][0], impl.usage, 'usage is what is output') - // This ties usage to a snapshot so we have to re-run snap if usage - // changes, which rebuilds the man pages - t.matchSnapshot(outputs[0][0]) - t.end() - }) - }) - outputs.length = 0 - } +t.test('load each command', async t => { + t.afterEach(() => { + outputs.length = 0 }) + t.plan(cmdList.length) + await npm.load() + npm.config.set('usage', true) // This makes npm.exec output the usage + for (const cmd of cmdList.sort((a, b) => a.localeCompare(b, 'en'))) { + t.test(cmd, async t => { + const impl = await npm.cmd(cmd) + if (impl.completion) + t.type(impl.completion, 'function', 'completion, if present, is a function') + t.type(impl.exec, 'function', 'implementation has an exec function') + t.type(impl.execWorkspaces, 'function', 'implementation has an execWorkspaces function') + t.equal(util.inspect(impl.exec), '[AsyncFunction: exec]', 'exec function is async') + t.equal(util.inspect(impl.execWorkspaces), '[AsyncFunction: execWorkspaces]', 'execWorkspaces function is async') + t.ok(impl.description, 'implementation has a description') + t.ok(impl.name, 'implementation has a name') + t.match(impl.usage, cmd, 'usage contains the command') + await npm.exec(cmd, []) + t.match(outputs[0][0], impl.usage, 'usage is what is output') + // This ties usage to a snapshot so we have to re-run snap if usage + // changes, which rebuilds the man pages + t.matchSnapshot(outputs[0][0]) + }) + } }) diff --git a/deps/npm/test/lib/load-all.js b/deps/npm/test/lib/load-all.js index c38c244934ec39..b6b2b6adc44f52 100644 --- a/deps/npm/test/lib/load-all.js +++ b/deps/npm/test/lib/load-all.js @@ -8,7 +8,8 @@ const full = process.env.npm_lifecycle_event === 'check-coverage' if (!full) t.pass('nothing to do here, not checking for full coverage') else { - const { npm } = mockNpm(t) + const { Npm } = mockNpm(t) + const npm = new Npm() t.teardown(() => { const exitHandler = require('../../lib/utils/exit-handler.js') @@ -16,7 +17,7 @@ else { exitHandler() }) - t.test('load npm first', async t => { + t.before(async t => { await npm.load() }) diff --git a/deps/npm/test/lib/npm.js b/deps/npm/test/lib/npm.js index 1451cd879a9be3..dc9640c0629b13 100644 --- a/deps/npm/test/lib/npm.js +++ b/deps/npm/test/lib/npm.js @@ -55,8 +55,9 @@ t.afterEach(() => { const CACHE = t.testdir() process.env.npm_config_cache = CACHE -t.test('not yet loaded', t => { - const { npm, logs } = mockNpm(t) +t.test('not yet loaded', async t => { + const { Npm, logs } = mockNpm(t) + const npm = new Npm() t.match(npm, { started: Number, command: null, @@ -70,56 +71,38 @@ t.test('not yet loaded', t => { }) t.throws(() => npm.config.set('foo', 'bar')) t.throws(() => npm.config.get('foo')) - const list = npm.commands.list - t.throws(() => npm.commands.list()) - t.equal(npm.commands.ls, list) - t.equal(npm.commands.list, list) - t.equal(npm.commands.asdfasdf, undefined) - t.equal(npm.deref('list'), 'ls') t.same(logs, []) t.end() }) -t.test('npm.load', t => { - t.test('callback must be a function', t => { - const { npm, logs } = mockNpm(t) - const er = new TypeError('callback must be a function if provided') - t.throws(() => npm.load({}), er) - t.same(logs, []) - t.end() - }) - - t.test('callback style', t => { - const { npm } = mockNpm(t) - npm.load((err) => { - if (err) - throw err - t.ok(npm.loaded) - t.end() - }) - }) - +t.test('npm.load', async t => { t.test('load error', async t => { - const { npm } = mockNpm(t) + const { Npm } = mockNpm(t) + const npm = new Npm() const loadError = new Error('load error') npm.config.load = async () => { throw loadError } - await npm.load().catch(er => { - t.equal(er, loadError) - t.equal(npm.loadErr, loadError) - }) + await t.rejects( + () => npm.load(), + /load error/ + ) + + t.equal(npm.loadErr, loadError) npm.config.load = async () => { - throw new Error('new load error') + throw new Error('different error') } - await npm.load().catch(er => { - t.equal(er, loadError, 'loading again returns the original error') - t.equal(npm.loadErr, loadError) - }) + await t.rejects( + () => npm.load(), + /load error/, + 'loading again returns the original error' + ) + t.equal(npm.loadErr, loadError) }) t.test('basic loading', async t => { - const { npm, logs } = mockNpm(t) + const { Npm, logs } = mockNpm(t) + const npm = new Npm() const dir = t.testdir({ node_modules: {}, }) @@ -187,7 +170,8 @@ t.test('npm.load', t => { t.test('forceful loading', async t => { process.argv = [...process.argv, '--force', '--color', 'always'] - const { npm, logs } = mockNpm(t) + const { Npm, logs } = mockNpm(t) + const npm = new Npm() await npm.load() t.match(logs.filter(l => l[0] !== 'timing'), [ [ @@ -223,7 +207,8 @@ t.test('npm.load', t => { process.env.PATH = PATH }) - const { npm, logs, outputs } = mockNpm(t) + const { Npm, logs, outputs } = mockNpm(t) + const npm = new Npm() await npm.load() t.equal(npm.config.get('scope'), '@foo', 'added the @ sign to scope') t.match(logs.filter(l => l[0] !== 'timing' || !/^config:/.test(l[1])), [ @@ -246,50 +231,41 @@ t.test('npm.load', t => { t.equal(process.execPath, resolve(dir, 'bin', node)) outputs.length = 0 - await npm.commands.ll([], (er) => { - if (er) - throw er + await npm.exec('ll', []) - t.equal(npm.command, 'll', 'command set to first npm command') - t.equal(npm.flatOptions.npmCommand, 'll', 'npmCommand flatOption set') + t.equal(npm.command, 'll', 'command set to first npm command') + t.equal(npm.flatOptions.npmCommand, 'll', 'npmCommand flatOption set') - t.same(outputs, [[npm.commands.ll.usage]], 'print usage') - npm.config.set('usage', false) - t.equal(npm.commands.ll, npm.commands.ll, 'same command, different name') - }) + const ll = await npm.cmd('ll') + t.same(outputs, [[ll.usage]], 'print usage') + npm.config.set('usage', false) outputs.length = 0 logs.length = 0 - await npm.commands.get(['scope', '\u2010not-a-dash'], (er) => { - if (er) - throw er - - t.strictSame([npm.command, npm.flatOptions.npmCommand], ['ll', 'll'], - 'does not change npm.command when another command is called') - - t.match(logs, [ - [ - 'error', - 'arg', - 'Argument starts with non-ascii dash, this is probably invalid:', - '\u2010not-a-dash', - ], - [ - 'timing', - 'command:config', - /Completed in [0-9.]+ms/, - ], - [ - 'timing', - 'command:get', - /Completed in [0-9.]+ms/, - ], - ]) - t.same(outputs, [['scope=@foo\n\u2010not-a-dash=undefined']]) - }) + await npm.exec('get', ['scope', '\u2010not-a-dash']) + + t.strictSame([npm.command, npm.flatOptions.npmCommand], ['ll', 'll'], + 'does not change npm.command when another command is called') - // need this here or node 10 will improperly end the promise ahead of time - await new Promise((res) => setTimeout(res)) + t.match(logs, [ + [ + 'error', + 'arg', + 'Argument starts with non-ascii dash, this is probably invalid:', + '\u2010not-a-dash', + ], + [ + 'timing', + 'command:config', + /Completed in [0-9.]+ms/, + ], + [ + 'timing', + 'command:get', + /Completed in [0-9.]+ms/, + ], + ]) + t.same(outputs, [['scope=@foo\n\u2010not-a-dash=undefined']]) }) t.test('--no-workspaces with --workspace', async t => { @@ -317,17 +293,13 @@ t.test('npm.load', t => { '--workspaces', 'false', '--workspace', 'a', ] - const { npm } = mockNpm(t) - await npm.load() + const { Npm } = mockNpm(t) + const npm = new Npm() npm.localPrefix = dir - await new Promise((res, rej) => { - npm.commands.run([], er => { - if (!er) - return rej(new Error('Expected an error')) - t.match(er.message, 'Can not use --no-workspaces and --workspace at the same time') - res() - }) - }) + await t.rejects( + npm.exec('run', []), + /Can not use --no-workspaces and --workspace at the same time/ + ) }) t.test('workspace-aware configs and commands', async t => { @@ -367,36 +339,30 @@ t.test('npm.load', t => { 'true', ] - const { npm, outputs } = mockNpm(t) + const { Npm, outputs } = mockNpm(t) + const npm = new Npm() await npm.load() npm.localPrefix = dir - await new Promise((res, rej) => { - // verify that calling the command with a short name still sets - // the npm.command property to the full canonical name of the cmd. - npm.command = null - npm.commands.run([], er => { - if (er) - rej(er) - - t.equal(npm.command, 'run-script', 'npm.command set to canonical name') - - t.match( - outputs, - [ - ['Lifecycle scripts included in a@1.0.0:'], - [' test\n echo test a'], - [''], - ['Lifecycle scripts included in b@1.0.0:'], - [' test\n echo test b'], - [''], - ], - 'should exec workspaces version of commands' - ) - - res() - }) - }) + // verify that calling the command with a short name still sets + // the npm.command property to the full canonical name of the cmd. + npm.command = null + await npm.exec('run', []) + + t.equal(npm.command, 'run-script', 'npm.command set to canonical name') + + t.match( + outputs, + [ + ['Lifecycle scripts included in a@1.0.0:'], + [' test\n echo test a'], + [''], + ['Lifecycle scripts included in b@1.0.0:'], + [' test\n echo test b'], + [''], + ], + 'should exec workspaces version of commands' + ) }) t.test('workspaces in global mode', async t => { @@ -434,23 +400,21 @@ t.test('npm.load', t => { '--global', 'true', ] - const { npm } = mockNpm(t) + const { Npm } = mockNpm(t) + const npm = new Npm() await npm.load() npm.localPrefix = dir - await new Promise((res, rej) => { - // verify that calling the command with a short name still sets - // the npm.command property to the full canonical name of the cmd. - npm.command = null - npm.commands.run([], er => { - t.match(er, /Workspaces not supported for global packages/) - res() - }) - }) + // verify that calling the command with a short name still sets + // the npm.command property to the full canonical name of the cmd. + npm.command = null + await t.rejects( + npm.exec('run', []), + /Workspaces not supported for global packages/ + ) }) - t.end() }) -t.test('set process.title', t => { +t.test('set process.title', async t => { t.test('basic title setting', async t => { process.argv = [ process.execPath, @@ -459,7 +423,8 @@ t.test('set process.title', t => { '--scope=foo', 'ls', ] - const { npm } = mockNpm(t) + const { Npm } = mockNpm(t) + const npm = new Npm() await npm.load() t.equal(npm.title, 'npm ls') t.equal(process.title, 'npm ls') @@ -475,7 +440,8 @@ t.test('set process.title', t => { 'revoke', 'deadbeefcafebad', ] - const { npm } = mockNpm(t) + const { Npm } = mockNpm(t) + const npm = new Npm() await npm.load() t.equal(npm.title, 'npm token revoke ***') t.equal(process.title, 'npm token revoke ***') @@ -490,17 +456,17 @@ t.test('set process.title', t => { 'token', 'revoke', ] - const { npm } = mockNpm(t) + const { Npm } = mockNpm(t) + const npm = new Npm() await npm.load() t.equal(npm.title, 'npm token revoke') t.equal(process.title, 'npm token revoke') }) - - t.end() }) t.test('timings', t => { - const { npm, logs } = mockNpm(t) + const { Npm, logs } = mockNpm(t) + const npm = new Npm() process.emit('time', 'foo') process.emit('time', 'bar') t.match(npm.timers.get('foo'), Number, 'foo timer is a number') @@ -525,8 +491,10 @@ t.test('timings', t => { }) t.test('output clears progress and console.logs the message', t => { - const npm = require('../../lib/npm.js') - const logs = [] + const mock = mockNpm(t) + const { Npm, logs } = mock + const npm = new Npm() + npm.output = mock.npmOutput const { log } = console const { log: { clearProgress, showProgress } } = npm let showingProgress = true @@ -546,3 +514,13 @@ t.test('output clears progress and console.logs the message', t => { t.strictSame(logs, [['hello']]) t.end() }) + +t.test('unknown command', async t => { + const mock = mockNpm(t) + const { Npm } = mock + const npm = new Npm() + await t.rejects( + npm.cmd('thisisnotacommand'), + { code: 'EUNKNOWNCOMMAND' } + ) +}) diff --git a/deps/npm/test/lib/org.js b/deps/npm/test/lib/org.js deleted file mode 100644 index 156232ac22a5db..00000000000000 --- a/deps/npm/test/lib/org.js +++ /dev/null @@ -1,578 +0,0 @@ -const t = require('tap') -const ansiTrim = require('../../lib/utils/ansi-trim.js') - -const output = [] -const npm = { - flatOptions: { - json: false, - parseable: false, - silent: false, - loglevel: 'info', - }, - output: (msg) => { - output.push(msg) - }, -} - -let orgSize = 1 -let orgSetArgs = null -let orgRmArgs = null -let orgLsArgs = null -let orgList = {} -const libnpmorg = { - set: async (org, user, role, opts) => { - orgSetArgs = { org, user, role, opts } - return { - org: { - name: org, - size: orgSize, - }, - user, - role, - } - }, - rm: async (org, user, opts) => { - orgRmArgs = { org, user, opts } - }, - ls: async (org, opts) => { - orgLsArgs = { org, opts } - return orgList - }, -} - -const Org = t.mock('../../lib/org.js', { - '../../lib/utils/otplease.js': async (opts, fn) => fn(opts), - libnpmorg, -}) -const org = new Org(npm) - -t.test('completion', async t => { - const completion = (argv) => - org.completion({ conf: { argv: { remain: argv } } }) - - const assertions = [ - [['npm', 'org'], ['set', 'rm', 'ls']], - [['npm', 'org', 'ls'], []], - [['npm', 'org', 'add'], []], - [['npm', 'org', 'rm'], []], - [['npm', 'org', 'set'], []], - ] - - for (const [argv, expected] of assertions) - t.resolveMatch(completion(argv), expected, `completion for: ${argv.join(', ')}`) - - t.rejects(completion(['npm', 'org', 'flurb']), /flurb not recognized/, 'errors for unknown subcommand') -}) - -t.test('npm org - invalid subcommand', t => { - org.exec(['foo'], (err) => { - t.match(err, /npm org set/, 'prints usage information') - t.end() - }) -}) - -t.test('npm org add', t => { - t.teardown(() => { - orgSetArgs = null - output.length = 0 - }) - - org.exec(['add', 'orgname', 'username'], (err) => { - if (err) - throw err - - t.strictSame(orgSetArgs, { - org: 'orgname', - user: 'username', - role: 'developer', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.equal(output[0], 'Added username as developer to orgname. You now have 1 member in this org.', 'printed the correct output') - t.end() - }) -}) - -t.test('npm org add - no org', t => { - t.teardown(() => { - orgSetArgs = null - output.length = 0 - }) - - org.exec(['add', '', 'username'], (err) => { - t.match(err, /`orgname` is required/, 'returns the correct error') - t.end() - }) -}) - -t.test('npm org add - no user', t => { - t.teardown(() => { - orgSetArgs = null - output.length = 0 - }) - - org.exec(['add', 'orgname', ''], (err) => { - t.match(err, /`username` is required/, 'returns the correct error') - t.end() - }) -}) - -t.test('npm org add - invalid role', t => { - t.teardown(() => { - orgSetArgs = null - output.length = 0 - }) - - org.exec(['add', 'orgname', 'username', 'person'], (err) => { - t.match(err, /`role` must be one of/, 'returns the correct error') - t.end() - }) -}) - -t.test('npm org add - more users', t => { - orgSize = 5 - t.teardown(() => { - orgSize = 1 - orgSetArgs = null - output.length = 0 - }) - - org.exec(['add', 'orgname', 'username'], (err) => { - if (err) - throw err - - t.strictSame(orgSetArgs, { - org: 'orgname', - user: 'username', - role: 'developer', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.equal(output[0], 'Added username as developer to orgname. You now have 5 members in this org.', 'printed the correct output') - t.end() - }) -}) - -t.test('npm org add - json output', t => { - npm.flatOptions.json = true - t.teardown(() => { - npm.flatOptions.json = false - orgSetArgs = null - output.length = 0 - }) - - org.exec(['add', 'orgname', 'username'], (err) => { - if (err) - throw err - - t.strictSame(orgSetArgs, { - org: 'orgname', - user: 'username', - role: 'developer', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.strictSame(JSON.parse(output[0]), { - org: { - name: 'orgname', - size: 1, - }, - user: 'username', - role: 'developer', - }, 'printed the correct output') - t.end() - }) -}) - -t.test('npm org add - parseable output', t => { - npm.flatOptions.parseable = true - t.teardown(() => { - npm.flatOptions.parseable = false - orgSetArgs = null - output.length = 0 - }) - - org.exec(['add', 'orgname', 'username'], (err) => { - if (err) - throw err - - t.strictSame(orgSetArgs, { - org: 'orgname', - user: 'username', - role: 'developer', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.strictSame(output.map(line => line.split(/\t/)), [ - ['org', 'orgsize', 'user', 'role'], - ['orgname', '1', 'username', 'developer'], - ], 'printed the correct output') - t.end() - }) -}) - -t.test('npm org add - silent output', t => { - npm.flatOptions.silent = true - t.teardown(() => { - npm.flatOptions.silent = false - orgSetArgs = null - output.length = 0 - }) - - org.exec(['add', 'orgname', 'username'], (err) => { - if (err) - throw err - - t.strictSame(orgSetArgs, { - org: 'orgname', - user: 'username', - role: 'developer', - opts: npm.flatOptions, - }, 'received the correct arguments') - t.strictSame(output, [], 'prints no output') - t.end() - }) -}) - -t.test('npm org rm', t => { - t.teardown(() => { - orgRmArgs = null - orgLsArgs = null - output.length = 0 - }) - - org.exec(['rm', 'orgname', 'username'], (err) => { - if (err) - throw err - - t.strictSame(orgRmArgs, { - org: 'orgname', - user: 'username', - opts: npm.flatOptions, - }, 'libnpmorg.rm received the correct args') - t.strictSame(orgLsArgs, { - org: 'orgname', - opts: npm.flatOptions, - }, 'libnpmorg.ls received the correct args') - t.equal(output[0], 'Successfully removed username from orgname. You now have 0 members in this org.', 'printed the correct output') - t.end() - }) -}) - -t.test('npm org rm - no org', t => { - t.teardown(() => { - orgRmArgs = null - orgLsArgs = null - output.length = 0 - }) - - org.exec(['rm', '', 'username'], (err) => { - t.match(err, /`orgname` is required/, 'threw the correct error') - t.end() - }) -}) - -t.test('npm org rm - no user', t => { - t.teardown(() => { - orgRmArgs = null - orgLsArgs = null - output.length = 0 - }) - - org.exec(['rm', 'orgname'], (err) => { - t.match(err, /`username` is required/, 'threw the correct error') - t.end() - }) -}) - -t.test('npm org rm - one user left', t => { - orgList = { - one: 'developer', - } - - t.teardown(() => { - orgList = {} - orgRmArgs = null - orgLsArgs = null - output.length = 0 - }) - - org.exec(['rm', 'orgname', 'username'], (err) => { - if (err) - throw err - - t.strictSame(orgRmArgs, { - org: 'orgname', - user: 'username', - opts: npm.flatOptions, - }, 'libnpmorg.rm received the correct args') - t.strictSame(orgLsArgs, { - org: 'orgname', - opts: npm.flatOptions, - }, 'libnpmorg.ls received the correct args') - t.equal(output[0], 'Successfully removed username from orgname. You now have 1 member in this org.', 'printed the correct output') - t.end() - }) -}) - -t.test('npm org rm - json output', t => { - npm.flatOptions.json = true - t.teardown(() => { - npm.flatOptions.json = false - orgRmArgs = null - orgLsArgs = null - output.length = 0 - }) - - org.exec(['rm', 'orgname', 'username'], (err) => { - if (err) - throw err - - t.strictSame(orgRmArgs, { - org: 'orgname', - user: 'username', - opts: npm.flatOptions, - }, 'libnpmorg.rm received the correct args') - t.strictSame(orgLsArgs, { - org: 'orgname', - opts: npm.flatOptions, - }, 'libnpmorg.ls received the correct args') - t.strictSame(JSON.parse(output[0]), { - user: 'username', - org: 'orgname', - userCount: 0, - deleted: true, - }, 'printed the correct output') - t.end() - }) -}) - -t.test('npm org rm - parseable output', t => { - npm.flatOptions.parseable = true - t.teardown(() => { - npm.flatOptions.parseable = false - orgRmArgs = null - orgLsArgs = null - output.length = 0 - }) - - org.exec(['rm', 'orgname', 'username'], (err) => { - if (err) - throw err - - t.strictSame(orgRmArgs, { - org: 'orgname', - user: 'username', - opts: npm.flatOptions, - }, 'libnpmorg.rm received the correct args') - t.strictSame(orgLsArgs, { - org: 'orgname', - opts: npm.flatOptions, - }, 'libnpmorg.ls received the correct args') - t.strictSame(output.map(line => line.split(/\t/)), [ - ['user', 'org', 'userCount', 'deleted'], - ['username', 'orgname', '0', 'true'], - ], 'printed the correct output') - t.end() - }) -}) - -t.test('npm org rm - silent output', t => { - npm.flatOptions.silent = true - t.teardown(() => { - npm.flatOptions.silent = false - orgRmArgs = null - orgLsArgs = null - output.length = 0 - }) - - org.exec(['rm', 'orgname', 'username'], (err) => { - if (err) - throw err - - t.strictSame(orgRmArgs, { - org: 'orgname', - user: 'username', - opts: npm.flatOptions, - }, 'libnpmorg.rm received the correct args') - t.strictSame(orgLsArgs, { - org: 'orgname', - opts: npm.flatOptions, - }, 'libnpmorg.ls received the correct args') - t.strictSame(output, [], 'printed no output') - t.end() - }) -}) - -t.test('npm org ls', t => { - orgList = { - one: 'developer', - two: 'admin', - three: 'owner', - } - t.teardown(() => { - orgList = {} - orgLsArgs = null - output.length = 0 - }) - - org.exec(['ls', 'orgname'], (err) => { - if (err) - throw err - - t.strictSame(orgLsArgs, { - org: 'orgname', - opts: npm.flatOptions, - }, 'receieved the correct args') - const out = ansiTrim(output[0]) - t.match(out, /one.*developer/, 'contains the developer member') - t.match(out, /two.*admin/, 'contains the admin member') - t.match(out, /three.*owner/, 'contains the owner member') - t.end() - }) -}) - -t.test('npm org ls - user filter', t => { - orgList = { - username: 'admin', - missing: 'admin', - } - t.teardown(() => { - orgList = {} - orgLsArgs = null - output.length = 0 - }) - - org.exec(['ls', 'orgname', 'username'], (err) => { - if (err) - throw err - - t.strictSame(orgLsArgs, { - org: 'orgname', - opts: npm.flatOptions, - }, 'receieved the correct args') - const out = ansiTrim(output[0]) - t.match(out, /username.*admin/, 'contains the filtered member') - t.notMatch(out, /missing.*admin/, 'does not contain other members') - t.end() - }) -}) - -t.test('npm org ls - user filter, missing user', t => { - orgList = { - missing: 'admin', - } - t.teardown(() => { - orgList = {} - orgLsArgs = null - output.length = 0 - }) - - org.exec(['ls', 'orgname', 'username'], (err) => { - if (err) - throw err - - t.strictSame(orgLsArgs, { - org: 'orgname', - opts: npm.flatOptions, - }, 'receieved the correct args') - const out = ansiTrim(output[0]) - t.notMatch(out, /username/, 'does not contain the requested member') - t.notMatch(out, /missing.*admin/, 'does not contain other members') - t.end() - }) -}) - -t.test('npm org ls - no org', t => { - t.teardown(() => { - orgLsArgs = null - output.length = 0 - }) - - org.exec(['ls'], (err) => { - t.match(err, /`orgname` is required/, 'throws the correct error') - t.end() - }) -}) - -t.test('npm org ls - json output', t => { - npm.flatOptions.json = true - orgList = { - one: 'developer', - two: 'admin', - three: 'owner', - } - t.teardown(() => { - npm.flatOptions.json = false - orgList = {} - orgLsArgs = null - output.length = 0 - }) - - org.exec(['ls', 'orgname'], (err) => { - if (err) - throw err - - t.strictSame(orgLsArgs, { - org: 'orgname', - opts: npm.flatOptions, - }, 'receieved the correct args') - t.strictSame(JSON.parse(output[0]), orgList, 'prints the correct output') - t.end() - }) -}) - -t.test('npm org ls - parseable output', t => { - npm.flatOptions.parseable = true - orgList = { - one: 'developer', - two: 'admin', - three: 'owner', - } - t.teardown(() => { - npm.flatOptions.parseable = false - orgList = {} - orgLsArgs = null - output.length = 0 - }) - - org.exec(['ls', 'orgname'], (err) => { - if (err) - throw err - - t.strictSame(orgLsArgs, { - org: 'orgname', - opts: npm.flatOptions, - }, 'receieved the correct args') - t.strictSame(output.map(line => line.split(/\t/)), [ - ['user', 'role'], - ['one', 'developer'], - ['two', 'admin'], - ['three', 'owner'], - ], 'printed the correct output') - t.end() - }) -}) - -t.test('npm org ls - silent output', t => { - npm.flatOptions.silent = true - orgList = { - one: 'developer', - two: 'admin', - three: 'owner', - } - t.teardown(() => { - npm.flatOptions.silent = false - orgList = {} - orgLsArgs = null - output.length = 0 - }) - - org.exec(['ls', 'orgname'], (err) => { - if (err) - throw err - - t.strictSame(orgLsArgs, { - org: 'orgname', - opts: npm.flatOptions, - }, 'receieved the correct args') - t.strictSame(output, [], 'printed no output') - t.end() - }) -}) diff --git a/deps/npm/test/lib/pkg.js b/deps/npm/test/lib/pkg.js deleted file mode 100644 index 688df6859054af..00000000000000 --- a/deps/npm/test/lib/pkg.js +++ /dev/null @@ -1,737 +0,0 @@ -const { resolve } = require('path') -const { readFileSync } = require('fs') -const t = require('tap') -const { fake: mockNpm } = require('../fixtures/mock-npm') - -const redactCwd = (path) => { - const normalizePath = p => p - .replace(/\\+/g, '/') - .replace(/\r\n/g, '\n') - return normalizePath(path) - .replace(new RegExp(normalizePath(process.cwd()), 'g'), '{CWD}') -} - -t.cleanSnapshot = (str) => redactCwd(str) - -let OUTPUT = '' -const config = { - global: false, - force: false, - 'pkg-cast': 'string', -} -const npm = mockNpm({ - localPrefix: t.testdirName, - config, - output: (str) => { - OUTPUT += str - }, -}) - -const Pkg = require('../../lib/pkg.js') -const pkg = new Pkg(npm) - -const readPackageJson = (path) => { - path = path || npm.localPrefix - return JSON.parse(readFileSync(resolve(path, 'package.json'), 'utf8')) -} - -t.afterEach(() => { - config.global = false - config.json = false - npm.localPrefix = t.testdirName - OUTPUT = '' -}) - -t.test('no args', t => { - pkg.exec([], err => { - t.match( - err, - { code: 'EUSAGE' }, - 'should throw usage error' - ) - t.end() - }) -}) - -t.test('no global mode', t => { - config.global = true - pkg.exec(['get', 'foo'], err => { - t.match( - err, - { code: 'EPKGGLOBAL' }, - 'should throw no global mode error' - ) - t.end() - }) -}) - -t.test('get no args', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - }), - }) - - pkg.exec(['get'], err => { - if (err) - throw err - - t.strictSame( - JSON.parse(OUTPUT), - { - name: 'foo', - version: '1.1.1', - }, - 'should print package.json content' - ) - t.end() - }) -}) - -t.test('get single arg', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - }), - }) - - pkg.exec(['get', 'version'], err => { - if (err) - throw err - - t.strictSame( - JSON.parse(OUTPUT), - '1.1.1', - 'should print retrieved package.json field' - ) - t.end() - }) -}) - -t.test('get nested arg', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - scripts: { - test: 'node test.js', - }, - }), - }) - - pkg.exec(['get', 'scripts.test'], err => { - if (err) - throw err - - t.strictSame( - JSON.parse(OUTPUT), - 'node test.js', - 'should print retrieved nested field' - ) - t.end() - }) -}) - -t.test('get array field', t => { - const files = [ - 'index.js', - 'cli.js', - ] - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - files, - }), - }) - - pkg.exec(['get', 'files'], err => { - if (err) - throw err - - t.strictSame( - JSON.parse(OUTPUT), - files, - 'should print retrieved array field' - ) - t.end() - }) -}) - -t.test('get array item', t => { - const files = [ - 'index.js', - 'cli.js', - ] - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - files, - }), - }) - - pkg.exec(['get', 'files[0]'], err => { - if (err) - throw err - - t.strictSame( - JSON.parse(OUTPUT), - 'index.js', - 'should print retrieved array field' - ) - t.end() - }) -}) - -t.test('get array nested items notation', t => { - const contributors = [ - { - name: 'Ruy', - url: 'http://example.com/ruy', - }, - { - name: 'Gar', - url: 'http://example.com/gar', - }, - ] - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - contributors, - }), - }) - - pkg.exec(['get', 'contributors.name'], err => { - if (err) - throw err - - t.strictSame( - JSON.parse(OUTPUT), - { - 'contributors[0].name': 'Ruy', - 'contributors[1].name': 'Gar', - }, - 'should print json result containing matching results' - ) - t.end() - }) -}) - -t.test('set no args', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ name: 'foo' }), - }) - pkg.exec(['set'], err => { - t.match( - err, - { code: 'EPKGSET' }, - 'should throw an error if no args' - ) - - t.end() - }) -}) - -t.test('set missing value', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ name: 'foo' }), - }) - pkg.exec(['set', 'key='], err => { - t.match( - err, - { code: 'EPKGSET' }, - 'should throw an error if missing value' - ) - - t.end() - }) -}) - -t.test('set missing key', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ name: 'foo' }), - }) - pkg.exec(['set', '=value'], err => { - t.match( - err, - { code: 'EPKGSET' }, - 'should throw an error if missing key' - ) - - t.end() - }) -}) - -t.test('set single field', t => { - const json = { - name: 'foo', - version: '1.1.1', - } - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify(json), - }) - - pkg.exec(['set', 'description=Awesome stuff'], err => { - if (err) - throw err - - t.strictSame( - readPackageJson(), - { - ...json, - description: 'Awesome stuff', - }, - 'should add single field to package.json' - ) - t.end() - }) -}) - -t.test('push to array syntax', t => { - const json = { - name: 'foo', - version: '1.1.1', - keywords: [ - 'foo', - ], - } - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify(json), - }) - - pkg.exec(['set', 'keywords[]=bar', 'keywords[]=baz'], err => { - if (err) - throw err - - t.strictSame( - readPackageJson(), - { - ...json, - keywords: [ - 'foo', - 'bar', - 'baz', - ], - }, - 'should append to arrays using empty bracket syntax' - ) - t.end() - }) -}) - -t.test('set multiple fields', t => { - const json = { - name: 'foo', - version: '1.1.1', - } - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify(json), - }) - - pkg.exec(['set', 'bin.foo=foo.js', 'scripts.test=node test.js'], err => { - if (err) - throw err - - t.strictSame( - readPackageJson(), - { - ...json, - bin: { - foo: 'foo.js', - }, - scripts: { - test: 'node test.js', - }, - }, - 'should add single field to package.json' - ) - t.end() - }) -}) - -t.test('set = separate value', t => { - const json = { - name: 'foo', - version: '1.1.1', - } - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify(json), - }) - - pkg.exec(['set', 'tap[test-env][0]=LC_ALL=sk'], err => { - if (err) - throw err - - t.strictSame( - readPackageJson(), - { - ...json, - tap: { - 'test-env': [ - 'LC_ALL=sk', - ], - }, - }, - 'should add single field to package.json' - ) - t.end() - }) -}) - -t.test('set --json', async t => { - config.json = true - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.1.1', - }), - }) - - await new Promise((res, rej) => { - pkg.exec(['set', 'private=true'], err => { - if (err) - rej(err) - - t.strictSame( - readPackageJson(), - { - name: 'foo', - version: '1.1.1', - private: true, - }, - 'should add boolean field to package.json' - ) - res() - }) - }) - - await new Promise((res, rej) => { - pkg.exec(['set', 'tap.timeout=60'], err => { - if (err) - rej(err) - - t.strictSame( - readPackageJson(), - { - name: 'foo', - version: '1.1.1', - private: true, - tap: { - timeout: 60, - }, - }, - 'should add number field to package.json' - ) - res() - }) - }) - - await new Promise((res, rej) => { - pkg.exec(['set', 'foo={ "bar": { "baz": "BAZ" } }'], err => { - if (err) - rej(err) - - t.strictSame( - readPackageJson(), - { - name: 'foo', - version: '1.1.1', - private: true, - tap: { - timeout: 60, - }, - foo: { - bar: { - baz: 'BAZ', - }, - }, - }, - 'should add object field to package.json' - ) - res() - }) - }) - - await new Promise((res, rej) => { - pkg.exec(['set', 'workspaces=["packages/*"]'], err => { - if (err) - rej(err) - - t.strictSame( - readPackageJson(), - { - name: 'foo', - version: '1.1.1', - private: true, - workspaces: [ - 'packages/*', - ], - tap: { - timeout: 60, - }, - foo: { - bar: { - baz: 'BAZ', - }, - }, - }, - 'should add object field to package.json' - ) - res() - }) - }) - - await new Promise((res, rej) => { - pkg.exec(['set', 'description="awesome"'], err => { - if (err) - rej(err) - - t.strictSame( - readPackageJson(), - { - name: 'foo', - version: '1.1.1', - description: 'awesome', - private: true, - workspaces: [ - 'packages/*', - ], - tap: { - timeout: 60, - }, - foo: { - bar: { - baz: 'BAZ', - }, - }, - }, - 'should add object field to package.json' - ) - res() - }) - }) -}) - -t.test('delete no args', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ name: 'foo' }), - }) - pkg.exec(['delete'], err => { - t.match( - err, - { code: 'EPKGDELETE' }, - 'should throw an error if deleting no args' - ) - - t.end() - }) -}) - -t.test('delete invalid key', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ name: 'foo' }), - }) - pkg.exec(['delete', ''], err => { - t.match( - err, - { code: 'EPKGDELETE' }, - 'should throw an error if deleting invalid args' - ) - - t.end() - }) -}) - -t.test('delete single field', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - }), - }) - pkg.exec(['delete', 'version'], err => { - if (err) - throw err - - t.strictSame( - readPackageJson(), - { - name: 'foo', - }, - 'should delete single field from package.json' - ) - - t.end() - }) -}) - -t.test('delete multiple field', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - description: 'awesome', - }), - }) - pkg.exec(['delete', 'version', 'description'], err => { - if (err) - throw err - - t.strictSame( - readPackageJson(), - { - name: 'foo', - }, - 'should delete multiple fields from package.json' - ) - - t.end() - }) -}) - -t.test('delete nested field', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - info: { - foo: { - bar: [ - { - baz: 'deleteme', - }, - ], - }, - }, - }), - }) - pkg.exec(['delete', 'info.foo.bar[0].baz'], err => { - if (err) - throw err - - t.strictSame( - readPackageJson(), - { - name: 'foo', - version: '1.0.0', - info: { - foo: { - bar: [ - {}, - ], - }, - }, - }, - 'should delete nested fields from package.json' - ) - - t.end() - }) -}) - -t.test('workspaces', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'root', - version: '1.0.0', - workspaces: [ - 'packages/*', - ], - }), - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.2.3', - }), - }, - }, - }) - - await new Promise((res, rej) => { - pkg.execWorkspaces(['get', 'name', 'version'], [], err => { - if (err) - rej(err) - - t.strictSame( - JSON.parse(OUTPUT), - { - a: { - name: 'a', - version: '1.0.0', - }, - b: { - name: 'b', - version: '1.2.3', - }, - }, - 'should return expected result for configured workspaces' - ) - res() - }) - }) - - await new Promise((res, rej) => { - pkg.execWorkspaces(['set', 'funding=http://example.com'], [], err => { - if (err) - rej(err) - - t.strictSame( - readPackageJson(resolve(npm.localPrefix, 'packages/a')), - { - name: 'a', - version: '1.0.0', - funding: 'http://example.com', - }, - 'should add field to workspace a' - ) - - t.strictSame( - readPackageJson(resolve(npm.localPrefix, 'packages/b')), - { - name: 'b', - version: '1.2.3', - funding: 'http://example.com', - }, - 'should add field to workspace b' - ) - res() - }) - }) - - await new Promise((res, rej) => { - pkg.execWorkspaces(['delete', 'version'], [], err => { - if (err) - rej(err) - - t.strictSame( - readPackageJson(resolve(npm.localPrefix, 'packages/a')), - { - name: 'a', - funding: 'http://example.com', - }, - 'should delete version field from workspace a' - ) - - t.strictSame( - readPackageJson(resolve(npm.localPrefix, 'packages/b')), - { - name: 'b', - funding: 'http://example.com', - }, - 'should delete version field from workspace b' - ) - res() - }) - }) -}) diff --git a/deps/npm/test/lib/prefix.js b/deps/npm/test/lib/prefix.js deleted file mode 100644 index 18a37f3ccd1e0e..00000000000000 --- a/deps/npm/test/lib/prefix.js +++ /dev/null @@ -1,13 +0,0 @@ -const t = require('tap') -const { real: mockNpm } = require('../fixtures/mock-npm') - -t.test('prefix', async (t) => { - const { joinedOutput, command, npm } = mockNpm(t) - await npm.load() - await command('prefix') - t.equal( - joinedOutput(), - npm.prefix, - 'outputs npm.prefix' - ) -}) diff --git a/deps/npm/test/lib/root.js b/deps/npm/test/lib/root.js deleted file mode 100644 index 7b91654c6c98fe..00000000000000 --- a/deps/npm/test/lib/root.js +++ /dev/null @@ -1,13 +0,0 @@ -const t = require('tap') -const { real: mockNpm } = require('../fixtures/mock-npm') - -t.test('prefix', async (t) => { - const { joinedOutput, command, npm } = mockNpm(t) - await npm.load() - await command('root') - t.equal( - joinedOutput(), - npm.dir, - 'outputs npm.dir' - ) -}) diff --git a/deps/npm/test/lib/run-script.js b/deps/npm/test/lib/run-script.js deleted file mode 100644 index a3f04ea6790fa4..00000000000000 --- a/deps/npm/test/lib/run-script.js +++ /dev/null @@ -1,1022 +0,0 @@ -const t = require('tap') -const { resolve } = require('path') -const { fake: mockNpm } = require('../fixtures/mock-npm') - -const normalizePath = p => p - .replace(/\\+/g, '/') - .replace(/\r\n/g, '\n') - -const cleanOutput = (str) => normalizePath(str) - .replace(normalizePath(process.cwd()), '{CWD}') - -const RUN_SCRIPTS = [] -const flatOptions = { - scriptShell: undefined, -} -const config = { - json: false, - parseable: false, - 'if-present': false, -} - -const npm = mockNpm({ - localPrefix: __dirname, - flatOptions, - config, - commands: { - help: { - description: 'test help description', - }, - test: { - description: 'test test description', - }, - }, - output: (...msg) => output.push(msg), -}) - -const output = [] - -const npmlog = { - disableProgress: () => null, - level: 'warn', - error: () => null, -} - -t.afterEach(() => { - npm.color = false - npmlog.level = 'warn' - npmlog.error = () => null - output.length = 0 - RUN_SCRIPTS.length = 0 - config['if-present'] = false - config.json = false - config.parseable = false -}) - -const getRS = windows => { - const RunScript = t.mock('../../lib/run-script.js', { - '@npmcli/run-script': Object.assign(async opts => { - RUN_SCRIPTS.push(opts) - }, { - isServerPackage: require('@npmcli/run-script').isServerPackage, - }), - npmlog, - '../../lib/utils/is-windows-shell.js': windows, - }) - return new RunScript(npm) -} - -const runScript = getRS(false) -const runScriptWin = getRS(true) - -const { writeFileSync } = require('fs') -t.test('completion', t => { - const dir = t.testdir() - npm.localPrefix = dir - t.test('already have a script name', async t => { - const res = await runScript.completion({conf: {argv: {remain: ['npm', 'run', 'x']}}}) - t.equal(res, undefined) - t.end() - }) - t.test('no package.json', async t => { - const res = await runScript.completion({conf: {argv: {remain: ['npm', 'run']}}}) - t.strictSame(res, []) - t.end() - }) - t.test('has package.json, no scripts', async t => { - writeFileSync(`${dir}/package.json`, JSON.stringify({})) - const res = await runScript.completion({conf: {argv: {remain: ['npm', 'run']}}}) - t.strictSame(res, []) - t.end() - }) - t.test('has package.json, with scripts', async t => { - writeFileSync(`${dir}/package.json`, JSON.stringify({ - scripts: { hello: 'echo hello', world: 'echo world' }, - })) - const res = await runScript.completion({conf: {argv: {remain: ['npm', 'run']}}}) - t.strictSame(res, ['hello', 'world']) - t.end() - }) - t.end() -}) - -t.test('fail if no package.json', t => { - t.plan(2) - npm.localPrefix = t.testdir() - runScript.exec([], er => t.match(er, { code: 'ENOENT' })) - runScript.exec(['test'], er => t.match(er, { code: 'ENOENT' })) -}) - -t.test('default env, start, and restart scripts', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ name: 'x', version: '1.2.3' }), - 'server.js': 'console.log("hello, world")', - }) - - t.test('start', t => { - runScript.exec(['start'], er => { - if (er) - throw er - - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { name: 'x', version: '1.2.3', _id: 'x@1.2.3', scripts: {}}, - event: 'start', - }, - ]) - t.end() - }) - }) - - t.test('env', t => { - runScript.exec(['env'], er => { - if (er) - throw er - - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { - name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - env: 'env', - }, - }, - event: 'env', - }, - ]) - t.end() - }) - }) - - t.test('windows env', t => { - runScriptWin.exec(['env'], er => { - if (er) - throw er - - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - env: 'SET', - } }, - event: 'env', - }, - ]) - t.end() - }) - }) - - t.test('restart', t => { - runScript.exec(['restart'], er => { - if (er) - throw er - - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - restart: 'npm stop --if-present && npm start', - } }, - event: 'restart', - }, - ]) - t.end() - }) - }) - t.end() -}) - -t.test('non-default env script', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { - env: 'hello', - }, - }), - }) - - t.test('env', t => { - runScript.exec(['env'], er => { - if (er) - throw er - - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { - name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - env: 'hello', - }, - }, - event: 'env', - }, - ]) - t.end() - }) - }) - - t.test('env windows', t => { - runScriptWin.exec(['env'], er => { - if (er) - throw er - - t.match(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - env: 'hello', - }, - }, - event: 'env', - }, - ]) - t.end() - }) - }) - t.end() -}) - -t.test('try to run missing script', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - scripts: { hello: 'world' }, - bin: { goodnight: 'moon' }, - }), - }) - t.test('no suggestions', t => { - runScript.exec(['notevenclose'], er => { - t.match(er, { - message: 'Missing script: "notevenclose"', - }) - t.end() - }) - }) - t.test('script suggestions', t => { - runScript.exec(['helo'], er => { - t.match(er, { - message: 'Missing script: "helo"', - }) - t.match(er, { - message: 'npm run hello', - }) - t.end() - }) - }) - t.test('bin suggestions', t => { - runScript.exec(['goodneght'], er => { - t.match(er, { - message: 'Missing script: "goodneght"', - }) - t.match(er, { - message: 'npm exec goodnight', - }) - t.end() - }) - }) - t.test('with --if-present', t => { - config['if-present'] = true - runScript.exec(['goodbye'], er => { - if (er) - throw er - - t.strictSame(RUN_SCRIPTS, [], 'did not try to run anything') - t.end() - }) - }) - t.end() -}) - -t.test('run pre/post hooks', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { - preenv: 'echo before the env', - postenv: 'echo after the env', - }, - }), - }) - - runScript.exec(['env'], er => { - if (er) - throw er - - t.match(RUN_SCRIPTS, [ - { event: 'preenv' }, - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - env: 'env', - } }, - event: 'env', - }, - { event: 'postenv' }, - ]) - t.end() - }) -}) - -t.test('skip pre/post hooks when using ignoreScripts', t => { - config['ignore-scripts'] = true - - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { - preenv: 'echo before the env', - postenv: 'echo after the env', - }, - }), - }) - - runScript.exec(['env'], er => { - if (er) - throw er - - t.same(RUN_SCRIPTS, [ - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - preenv: 'echo before the env', - postenv: 'echo after the env', - env: 'env', - } }, - banner: true, - event: 'env', - }, - ]) - t.end() - delete config['ignore-scripts'] - }) -}) - -t.test('run silent', t => { - npmlog.level = 'silent' - t.teardown(() => { - npmlog.level = 'warn' - }) - - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { - preenv: 'echo before the env', - postenv: 'echo after the env', - }, - }), - }) - - runScript.exec(['env'], er => { - if (er) - throw er - - t.match(RUN_SCRIPTS, [ - { - event: 'preenv', - stdio: 'inherit', - }, - { - path: npm.localPrefix, - args: [], - scriptShell: undefined, - stdio: 'inherit', - stdioString: true, - pkg: { name: 'x', - version: '1.2.3', - _id: 'x@1.2.3', - scripts: { - env: 'env', - } }, - event: 'env', - banner: false, - }, - { - event: 'postenv', - stdio: 'inherit', - }, - ]) - t.end() - }) -}) - -t.test('list scripts', t => { - const scripts = { - test: 'exit 2', - start: 'node server.js', - stop: 'node kill-server.js', - preenv: 'echo before the env', - postenv: 'echo after the env', - } - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts, - }), - }) - - t.test('no args', t => { - runScript.exec([], er => { - if (er) - throw er - t.strictSame(output, [ - ['Lifecycle scripts included in x@1.2.3:'], - [' test\n exit 2'], - [' start\n node server.js'], - [' stop\n node kill-server.js'], - ['\navailable via `npm run-script`:'], - [' preenv\n echo before the env'], - [' postenv\n echo after the env'], - [''], - ], 'basic report') - t.end() - }) - }) - - t.test('silent', t => { - npmlog.level = 'silent' - runScript.exec([], er => { - if (er) - throw er - t.strictSame(output, []) - t.end() - }) - }) - t.test('warn json', t => { - npmlog.level = 'warn' - config.json = true - runScript.exec([], er => { - if (er) - throw er - t.strictSame(output, [[JSON.stringify(scripts, 0, 2)]], 'json report') - t.end() - }) - }) - - t.test('parseable', t => { - config.parseable = true - runScript.exec([], er => { - if (er) - throw er - t.strictSame(output, [ - ['test:exit 2'], - ['start:node server.js'], - ['stop:node kill-server.js'], - ['preenv:echo before the env'], - ['postenv:echo after the env'], - ]) - t.end() - }) - }) - t.end() -}) - -t.test('list scripts when no scripts', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - }), - }) - - runScript.exec([], er => { - if (er) - throw er - t.strictSame(output, [], 'nothing to report') - t.end() - }) -}) - -t.test('list scripts, only commands', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { preversion: 'echo doing the version dance' }, - }), - }) - - runScript.exec([], er => { - if (er) - throw er - t.strictSame(output, [ - ['Lifecycle scripts included in x@1.2.3:'], - [' preversion\n echo doing the version dance'], - [''], - ]) - t.end() - }) -}) - -t.test('list scripts, only non-commands', t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - scripts: { glorp: 'echo doing the glerp glop' }, - }), - }) - - runScript.exec([], er => { - if (er) - throw er - t.strictSame(output, [ - ['Scripts available in x@1.2.3 via `npm run-script`:'], - [' glorp\n echo doing the glerp glop'], - [''], - ]) - t.end() - }) -}) - -t.test('workspaces', t => { - npm.localPrefix = t.testdir({ - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - scripts: { glorp: 'echo a doing the glerp glop' }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '2.0.0', - scripts: { glorp: 'echo b doing the glerp glop' }, - }), - }, - c: { - 'package.json': JSON.stringify({ - name: 'c', - version: '1.0.0', - scripts: { - test: 'exit 0', - posttest: 'echo posttest', - lorem: 'echo c lorem', - }, - }), - }, - d: { - 'package.json': JSON.stringify({ - name: 'd', - version: '1.0.0', - scripts: { - test: 'exit 0', - posttest: 'echo posttest', - }, - }), - }, - e: { - 'package.json': JSON.stringify({ - name: 'e', - scripts: { test: 'exit 0', start: 'echo start something' }, - }), - }, - noscripts: { - 'package.json': JSON.stringify({ - name: 'noscripts', - version: '1.0.0', - }), - }, - }, - 'package.json': JSON.stringify({ - name: 'x', - version: '1.2.3', - workspaces: ['packages/*'], - }), - }) - - t.test('list all scripts', t => { - runScript.execWorkspaces([], [], er => { - if (er) - throw er - t.strictSame(output, [ - ['Scripts available in a@1.0.0 via `npm run-script`:'], - [' glorp\n echo a doing the glerp glop'], - [''], - ['Scripts available in b@2.0.0 via `npm run-script`:'], - [' glorp\n echo b doing the glerp glop'], - [''], - ['Lifecycle scripts included in c@1.0.0:'], - [' test\n exit 0'], - [' posttest\n echo posttest'], - ['\navailable via `npm run-script`:'], - [' lorem\n echo c lorem'], - [''], - ['Lifecycle scripts included in d@1.0.0:'], - [' test\n exit 0'], - [' posttest\n echo posttest'], - [''], - ['Lifecycle scripts included in e:'], - [' test\n exit 0'], - [' start\n echo start something'], - [''], - ]) - t.end() - }) - }) - - t.test('list regular scripts, filtered by name', t => { - runScript.execWorkspaces([], ['a', 'b'], er => { - if (er) - throw er - t.strictSame(output, [ - ['Scripts available in a@1.0.0 via `npm run-script`:'], - [' glorp\n echo a doing the glerp glop'], - [''], - ['Scripts available in b@2.0.0 via `npm run-script`:'], - [' glorp\n echo b doing the glerp glop'], - [''], - ]) - t.end() - }) - }) - - t.test('list regular scripts, filtered by path', t => { - runScript.execWorkspaces([], ['./packages/a'], er => { - if (er) - throw er - t.strictSame(output, [ - ['Scripts available in a@1.0.0 via `npm run-script`:'], - [' glorp\n echo a doing the glerp glop'], - [''], - ]) - t.end() - }) - }) - - t.test('list regular scripts, filtered by parent folder', t => { - runScript.execWorkspaces([], ['./packages'], er => { - if (er) - throw er - t.strictSame(output, [ - ['Scripts available in a@1.0.0 via `npm run-script`:'], - [' glorp\n echo a doing the glerp glop'], - [''], - ['Scripts available in b@2.0.0 via `npm run-script`:'], - [' glorp\n echo b doing the glerp glop'], - [''], - ['Lifecycle scripts included in c@1.0.0:'], - [' test\n exit 0'], - [' posttest\n echo posttest'], - ['\navailable via `npm run-script`:'], - [' lorem\n echo c lorem'], - [''], - ['Lifecycle scripts included in d@1.0.0:'], - [' test\n exit 0'], - [' posttest\n echo posttest'], - [''], - ['Lifecycle scripts included in e:'], - [' test\n exit 0'], - [' start\n echo start something'], - [''], - ]) - t.end() - }) - }) - - t.test('list all scripts with colors', t => { - npm.color = true - runScript.execWorkspaces([], [], er => { - if (er) - throw er - t.strictSame(output, [ - [ - '\u001b[1mScripts\u001b[22m available in \x1B[32ma@1.0.0\x1B[39m via `\x1B[34mnpm run-script\x1B[39m`:', - ], - [' glorp\n \x1B[2mecho a doing the glerp glop\x1B[22m'], - [''], - [ - '\u001b[1mScripts\u001b[22m available in \x1B[32mb@2.0.0\x1B[39m via `\x1B[34mnpm run-script\x1B[39m`:', - ], - [' glorp\n \x1B[2mecho b doing the glerp glop\x1B[22m'], - [''], - [ - '\x1B[0m\x1B[1mLifecycle scripts\x1B[22m\x1B[0m included in \x1B[32mc@1.0.0\x1B[39m:', - ], - [' test\n \x1B[2mexit 0\x1B[22m'], - [' posttest\n \x1B[2mecho posttest\x1B[22m'], - ['\navailable via `\x1B[34mnpm run-script\x1B[39m`:'], - [' lorem\n \x1B[2mecho c lorem\x1B[22m'], - [''], - [ - '\x1B[0m\x1B[1mLifecycle scripts\x1B[22m\x1B[0m included in \x1B[32md@1.0.0\x1B[39m:', - ], - [' test\n \x1B[2mexit 0\x1B[22m'], - [' posttest\n \x1B[2mecho posttest\x1B[22m'], - [''], - [ - '\x1B[0m\x1B[1mLifecycle scripts\x1B[22m\x1B[0m included in \x1B[32me\x1B[39m:', - ], - [' test\n \x1B[2mexit 0\x1B[22m'], - [' start\n \x1B[2mecho start something\x1B[22m'], - [''], - ]) - t.end() - }) - }) - - t.test('list all scripts --json', t => { - config.json = true - runScript.execWorkspaces([], [], er => { - if (er) - throw er - t.strictSame(output, [ - [ - '{\n' + - ' "a": {\n' + - ' "glorp": "echo a doing the glerp glop"\n' + - ' },\n' + - ' "b": {\n' + - ' "glorp": "echo b doing the glerp glop"\n' + - ' },\n' + - ' "c": {\n' + - ' "test": "exit 0",\n' + - ' "posttest": "echo posttest",\n' + - ' "lorem": "echo c lorem"\n' + - ' },\n' + - ' "d": {\n' + - ' "test": "exit 0",\n' + - ' "posttest": "echo posttest"\n' + - ' },\n' + - ' "e": {\n' + - ' "test": "exit 0",\n' + - ' "start": "echo start something"\n' + - ' },\n' + - ' "noscripts": {}\n' + - '}', - ], - ]) - t.end() - }) - }) - - t.test('list all scripts --parseable', t => { - config.parseable = true - runScript.execWorkspaces([], [], er => { - if (er) - throw er - t.strictSame(output, [ - ['a:glorp:echo a doing the glerp glop'], - ['b:glorp:echo b doing the glerp glop'], - ['c:test:exit 0'], - ['c:posttest:echo posttest'], - ['c:lorem:echo c lorem'], - ['d:test:exit 0'], - ['d:posttest:echo posttest'], - ['e:test:exit 0'], - ['e:start:echo start something'], - ]) - t.end() - }) - }) - - t.test('list no scripts --loglevel=silent', t => { - npmlog.level = 'silent' - runScript.execWorkspaces([], [], er => { - if (er) - throw er - t.strictSame(output, []) - t.end() - }) - }) - - t.test('run scripts across all workspaces', t => { - runScript.execWorkspaces(['test'], [], er => { - if (er) - throw er - - t.match(RUN_SCRIPTS, [ - { - path: resolve(npm.localPrefix, 'packages/c'), - pkg: { name: 'c', version: '1.0.0' }, - event: 'test', - }, - { - path: resolve(npm.localPrefix, 'packages/c'), - pkg: { name: 'c', version: '1.0.0' }, - event: 'posttest', - }, - { - path: resolve(npm.localPrefix, 'packages/d'), - pkg: { name: 'd', version: '1.0.0' }, - event: 'test', - }, - { - path: resolve(npm.localPrefix, 'packages/d'), - pkg: { name: 'd', version: '1.0.0' }, - event: 'posttest', - }, - { - path: resolve(npm.localPrefix, 'packages/e'), - pkg: { name: 'e' }, - event: 'test', - }, - ]) - t.end() - }) - }) - - t.test('missing scripts in all workspaces', t => { - const LOG = [] - npmlog.error = (err) => { - LOG.push(String(err)) - } - runScript.execWorkspaces(['missing-script'], [], er => { - t.match( - er, - /Missing script: missing-script/, - 'should throw missing script error' - ) - - process.exitCode = 0 // clean exit code - - t.match(RUN_SCRIPTS, []) - t.strictSame(LOG.map(cleanOutput), [ - 'Lifecycle script `missing-script` failed with error:', - 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', - ' in workspace: a@1.0.0', - ' at location: {CWD}/test/lib/tap-testdir-run-script-workspaces/packages/a', - 'Lifecycle script `missing-script` failed with error:', - 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', - ' in workspace: b@2.0.0', - ' at location: {CWD}/test/lib/tap-testdir-run-script-workspaces/packages/b', - 'Lifecycle script `missing-script` failed with error:', - 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', - ' in workspace: c@1.0.0', - ' at location: {CWD}/test/lib/tap-testdir-run-script-workspaces/packages/c', - 'Lifecycle script `missing-script` failed with error:', - 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', - ' in workspace: d@1.0.0', - ' at location: {CWD}/test/lib/tap-testdir-run-script-workspaces/packages/d', - 'Lifecycle script `missing-script` failed with error:', - 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', - ' in workspace: e', - ' at location: {CWD}/test/lib/tap-testdir-run-script-workspaces/packages/e', - 'Lifecycle script `missing-script` failed with error:', - 'Error: Missing script: "missing-script"\n\nTo see a list of scripts, run:\n npm run', - ' in workspace: noscripts@1.0.0', - ' at location: {CWD}/test/lib/tap-testdir-run-script-workspaces/packages/noscripts', - ], 'should log error msgs for each workspace script') - - t.end() - }) - }) - - t.test('missing scripts in some workspaces', t => { - const LOG = [] - npmlog.error = (err) => { - LOG.push(String(err)) - } - runScript.execWorkspaces(['test'], ['a', 'b', 'c', 'd'], er => { - if (er) - throw er - - t.match(RUN_SCRIPTS, []) - t.strictSame(LOG.map(cleanOutput), [ - 'Lifecycle script `test` failed with error:', - 'Error: Missing script: "test"\n\nTo see a list of scripts, run:\n npm run', - ' in workspace: a@1.0.0', - ' at location: {CWD}/test/lib/tap-testdir-run-script-workspaces/packages/a', - 'Lifecycle script `test` failed with error:', - 'Error: Missing script: "test"\n\nTo see a list of scripts, run:\n npm run', - ' in workspace: b@2.0.0', - ' at location: {CWD}/test/lib/tap-testdir-run-script-workspaces/packages/b', - ], 'should log error msgs for each workspace script') - t.end() - }) - }) - - t.test('no workspaces when filtering by user args', t => { - runScript.execWorkspaces([], ['foo', 'bar'], er => { - t.equal( - er.message, - 'No workspaces found:\n --workspace=foo --workspace=bar', - 'should throw error msg' - ) - t.end() - }) - }) - - t.test('no workspaces', t => { - const _prevPrefix = npm.localPrefix - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'foo', - version: '1.0.0', - }), - }) - - runScript.execWorkspaces([], [], er => { - t.match(er, /No workspaces found!/, 'should throw error msg') - npm.localPrefix = _prevPrefix - t.end() - }) - }) - - t.test('single failed workspace run', t => { - const RunScript = t.mock('../../lib/run-script.js', { - '@npmcli/run-script': () => { - throw new Error('err') - }, - npmlog, - '../../lib/utils/is-windows-shell.js': false, - }) - const runScript = new RunScript(npm) - - runScript.execWorkspaces(['test'], ['c'], er => { - t.ok('should complete running all targets') - process.exitCode = 0 // clean up exit code - t.end() - }) - }) - - t.test('failed workspace run with succeeded runs', t => { - const RunScript = t.mock('../../lib/run-script.js', { - '@npmcli/run-script': async opts => { - if (opts.pkg.name === 'a') - throw new Error('ERR') - - RUN_SCRIPTS.push(opts) - }, - npmlog, - '../../lib/utils/is-windows-shell.js': false, - }) - const runScript = new RunScript(npm) - - runScript.execWorkspaces(['glorp'], ['a', 'b'], er => { - t.match(RUN_SCRIPTS, [ - { - path: resolve(npm.localPrefix, 'packages/b'), - pkg: { name: 'b', version: '2.0.0' }, - event: 'glorp', - }, - ]) - - process.exitCode = 0 // clean up exit code - t.end() - }) - }) - - t.end() -}) diff --git a/deps/npm/test/lib/set-script.js b/deps/npm/test/lib/set-script.js deleted file mode 100644 index 37ba9a1cc71a20..00000000000000 --- a/deps/npm/test/lib/set-script.js +++ /dev/null @@ -1,179 +0,0 @@ -const t = require('tap') -const fs = require('fs') -const parseJSON = require('json-parse-even-better-errors') -const { fake: mockNpm } = require('../fixtures/mock-npm') -const { resolve } = require('path') - -const flatOptions = {} -const npm = mockNpm(flatOptions) - -const ERROR_OUTPUT = [] -const WARN_OUTPUT = [] -const SetScript = t.mock('../../lib/set-script.js', { - npmlog: { - error: (...args) => { - ERROR_OUTPUT.push(args) - }, - warn: (...args) => { - WARN_OUTPUT.push(args) - }, - }, -}) -const setScript = new SetScript(npm) - -t.test('completion', t => { - t.test('already have a script name', async t => { - npm.localPrefix = t.testdir({}) - const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run', 'x']}}}) - t.equal(res, undefined) - t.end() - }) - - t.test('no package.json', async t => { - npm.localPrefix = t.testdir({}) - const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run']}}}) - t.strictSame(res, []) - t.end() - }) - - t.test('has package.json, no scripts', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({}), - }) - const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run']}}}) - t.strictSame(res, []) - t.end() - }) - - t.test('has package.json, with scripts', async t => { - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - scripts: { hello: 'echo hello', world: 'echo world' }, - }), - }) - const res = await setScript.completion({conf: {argv: {remain: ['npm', 'run']}}}) - t.strictSame(res, ['hello', 'world']) - t.end() - }) - - t.end() -}) - -t.test('fails on invalid arguments', (t) => { - t.plan(3) - setScript.exec(['arg1'], (fail) => t.match(fail, /Expected 2 arguments: got 1/)) - setScript.exec(['arg1', 'arg2', 'arg3'], (fail) => t.match(fail, /Expected 2 arguments: got 3/)) - setScript.exec(['arg1', 'arg2', 'arg3', 'arg4'], (fail) => t.match(fail, /Expected 2 arguments: got 4/)) -}) - -t.test('fails if run in postinstall script', (t) => { - const lifecycleEvent = process.env.npm_lifecycle_event - t.teardown(() => { - process.env.npm_lifecycle_event = lifecycleEvent - }) - - process.env.npm_lifecycle_event = 'postinstall' - t.plan(1) - setScript.exec(['arg1', 'arg2'], (fail) => t.equal(fail.toString(), 'Error: Scripts can’t set from the postinstall script')) -}) - -t.test('fails when package.json not found', (t) => { - t.plan(1) - setScript.exec(['arg1', 'arg2'], (fail) => t.match(fail, /package.json not found/)) -}) - -t.test('fails on invalid JSON', (t) => { - npm.localPrefix = t.testdir({ - 'package.json': 'iamnotjson', - }) - - t.plan(1) - setScript.exec(['arg1', 'arg2'], (fail) => t.match(fail, /Invalid package.json: JSONParseError/)) -}) - -t.test('creates scripts object', (t) => { - npm.localPrefix = t.testdir({ - 'package.json': '{}', - }) - - t.plan(2) - setScript.exec(['arg1', 'arg2'], (error) => { - t.equal(error, undefined) - const contents = fs.readFileSync(resolve(npm.localPrefix, 'package.json')) - t.ok(parseJSON(contents), {scripts: {arg1: 'arg2'}}) - }) -}) - -t.test('warns when overwriting', (t) => { - WARN_OUTPUT.length = 0 - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - scripts: { - arg1: 'blah', - }, - }), - }) - - t.plan(2) - setScript.exec(['arg1', 'arg2'], (error) => { - t.equal(error, undefined, 'no error') - t.hasStrict(WARN_OUTPUT[0], ['set-script', 'Script "arg1" was overwritten'], 'warning was logged') - }) -}) - -t.test('workspaces', (t) => { - ERROR_OUTPUT.length = 0 - WARN_OUTPUT.length = 0 - npm.localPrefix = t.testdir({ - 'package.json': JSON.stringify({ - name: 'workspaces-test', - version: '1.0.0', - workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], - }), - 'workspace-a': { - 'package.json': '{}', - }, - 'workspace-b': { - 'package.json': '"notajsonobject"', - }, - 'workspace-c': { - 'package.json': JSON.stringify({ - scripts: { - arg1: 'test', - }, - }, null, ' '.repeat(6)).replace(/\n/g, '\r\n'), - }, - }) - - setScript.execWorkspaces(['arg1', 'arg2'], [], (error) => { - t.equal(error, undefined, 'did not callback with an error') - t.equal(process.exitCode, 1, 'did set the exitCode to 1') - // force the exitCode back to 0 to make tap happy - process.exitCode = 0 - - // workspace-a had the script added - const contentsA = fs.readFileSync(resolve(npm.localPrefix, 'workspace-a', 'package.json')) - const dataA = parseJSON(contentsA) - t.hasStrict(dataA, { scripts: { arg1: 'arg2' } }, 'defined the script') - - // workspace-b logged an error - t.strictSame(ERROR_OUTPUT, [ - ['set-script', `Can't update invalid package.json data`], - [' in workspace: workspace-b'], - [` at location: ${resolve(npm.localPrefix, 'workspace-b')}`], - ], 'logged workspace-b error') - - // workspace-c overwrite a script and logged a warning - const contentsC = fs.readFileSync(resolve(npm.localPrefix, 'workspace-c', 'package.json')) - const dataC = parseJSON(contentsC) - t.hasStrict(dataC, { scripts: { arg1: 'arg2' } }, 'defined the script') - t.equal(dataC[Symbol.for('indent')], ' '.repeat(6), 'kept the correct indent') - t.equal(dataC[Symbol.for('newline')], '\r\n', 'kept the correct newline') - t.match(WARN_OUTPUT, [ - ['set-script', 'Script "arg1" was overwritten'], - [' in workspace: workspace-c'], - [` at location: ${resolve(npm.localPrefix, 'workspace-c')}`], - ], 'logged workspace-c warning') - t.end() - }) -}) diff --git a/deps/npm/test/lib/shrinkwrap.js b/deps/npm/test/lib/shrinkwrap.js deleted file mode 100644 index ab3b8d0ffe447e..00000000000000 --- a/deps/npm/test/lib/shrinkwrap.js +++ /dev/null @@ -1,349 +0,0 @@ -const t = require('tap') -const fs = require('fs') -const { fake: mockNpm } = require('../fixtures/mock-npm') - -const config = { - global: false, -} -const flatOptions = { - depth: 0, -} -const npm = mockNpm({ - config, - flatOptions, - lockfileVersion: 2, - globalDir: '', - prefix: '', -}) -const tree = { - meta: { - hiddenLockfile: null, - loadedFromDisk: false, - filename: '', - originalLockfileVersion: 2, - save () {}, - }, -} -const mocks = { - npmlog: { notice () {} }, - '@npmcli/arborist': class { - loadVirtual () { - return tree - } - - loadActual () { - return tree - } - }, - '../../lib/utils/usage.js': () => 'usage instructions', - '../../lib/utils/config/definitions.js': {}, -} - -t.afterEach(() => { - npm.prefix = '' - config.global = false - npm.globalDir = '' -}) - -t.test('no args', t => { - t.plan(4) - - npm.prefix = '/project/a' - - class Arborist { - constructor (args) { - t.same( - args, - { ...flatOptions, path: npm.prefix }, - 'should call arborist constructor with expected args' - ) - } - - async loadVirtual () { - t.ok('should load virtual tree') - return { - ...tree, - meta: { - ...tree.meta, - save () { - t.ok('should save the lockfile') - }, - }, - } - } - } - - const npmlog = { - notice (title, msg) { - t.equal( - msg, - 'created a lockfile as npm-shrinkwrap.json', - 'should log notice msg that file was successfully created' - ) - }, - } - - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', { - ...mocks, - npmlog, - '@npmcli/arborist': Arborist, - }) - const shrinkwrap = new Shrinkwrap(npm) - - shrinkwrap.exec([], err => { - if (err) - throw err - }) -}) - -t.test('no virtual tree', t => { - t.plan(4) - - npm.prefix = '/project/a' - - class Arborist { - constructor (args) { - t.same( - args, - { ...flatOptions, path: npm.prefix }, - 'should call arborist constructor with expected args' - ) - } - - async loadVirtual () { - throw new Error('ERR') - } - - async loadActual () { - t.ok('should load actual tree') - return { - ...tree, - meta: { - ...tree.meta, - save () { - t.ok('should save the lockfile') - }, - }, - } - } - } - - const npmlog = { - notice (title, msg) { - t.equal( - msg, - 'created a lockfile as npm-shrinkwrap.json', - 'should log notice msg that file was successfully created' - ) - }, - } - - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', { - ...mocks, - npmlog, - '@npmcli/arborist': Arborist, - }) - const shrinkwrap = new Shrinkwrap(npm) - - shrinkwrap.exec([], err => { - if (err) - throw err - }) -}) - -t.test('existing package-json file', t => { - t.plan(5) - - npm.prefix = '/project/a' - - class Arborist { - constructor (args) { - t.same( - args, - { ...flatOptions, path: npm.prefix }, - 'should call arborist constructor with expected args' - ) - } - - async loadVirtual () { - t.ok('should load virtual tree') - return { - ...tree, - meta: { - hiddenLockfile: false, - loadedFromDisk: true, - filename: 'package-lock.json', - save () { - t.ok('should save the lockfile') - }, - }, - } - } - } - - const npmlog = { - notice (title, msg) { - t.equal( - msg, - 'package-lock.json has been renamed to npm-shrinkwrap.json', - 'should log notice msg that file was renamed' - ) - }, - } - - const fs = { - promises: { - unlink (filename) { - t.equal(filename, 'package-lock.json', 'should remove old lockfile') - }, - }, - } - - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', { - ...mocks, - fs, - npmlog, - '@npmcli/arborist': Arborist, - }) - const shrinkwrap = new Shrinkwrap(npm) - - shrinkwrap.exec([], err => { - if (err) - throw err - }) -}) - -t.test('update shrinkwrap file version', t => { - t.plan(4) - - npm.prefix = '/project/a' - - class Arborist { - constructor (args) { - t.same( - args, - { ...flatOptions, path: npm.prefix }, - 'should call arborist constructor with expected args' - ) - } - - async loadVirtual () { - t.ok('should load virtual tree') - return { - ...tree, - meta: { - hiddenLockfile: false, - loadedFromDisk: true, - filename: 'npm-shrinkwrap.json', - originalLockfileVersion: 1, - save () { - t.ok('should save the lockfile') - }, - }, - } - } - } - - const npmlog = { - notice (title, msg) { - t.equal( - msg, - 'npm-shrinkwrap.json updated to version 2', - 'should log notice msg that file was updated' - ) - }, - } - - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', { - ...mocks, - npmlog, - '@npmcli/arborist': Arborist, - }) - const shrinkwrap = new Shrinkwrap(npm) - - shrinkwrap.exec([], err => { - if (err) - throw err - }) -}) - -t.test('update to date shrinkwrap file', t => { - t.plan(4) - - npm.prefix = '/project/a' - - class Arborist { - constructor (args) { - t.same( - args, - { ...flatOptions, path: npm.prefix }, - 'should call arborist constructor with expected args' - ) - } - - async loadVirtual () { - t.ok('should load virtual tree') - return { - ...tree, - meta: { - hiddenLockfile: false, - loadedFromDisk: true, - filename: 'npm-shrinkwrap.json', - originalLockfileVersion: 2, - save () { - t.ok('should save the lockfile') - }, - }, - } - } - } - - const npmlog = { - notice (title, msg) { - t.equal( - msg, - 'npm-shrinkwrap.json up to date', - 'should log notice msg shrinkwrap up to date' - ) - }, - } - - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', { - ...mocks, - npmlog, - '@npmcli/arborist': Arborist, - }) - const shrinkwrap = new Shrinkwrap(npm) - - shrinkwrap.exec([], err => { - if (err) - throw err - }) -}) - -t.test('shrinkwrap --global', t => { - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', mocks) - - config.global = true - const shrinkwrap = new Shrinkwrap(npm) - - shrinkwrap.exec([], err => { - t.match( - err, - /does not work for global packages/, - 'should throw no global support msg' - ) - t.equal(err.code, 'ESHRINKWRAPGLOBAL', 'should throw expected error code') - t.end() - }) -}) - -t.test('works without fs.promises', async t => { - t.doesNotThrow(() => { - const Shrinkwrap = t.mock('../../lib/shrinkwrap.js', { - ...mocks, - fs: { ...fs, promises: null }, - }) - new Shrinkwrap(npm) - }) -}) diff --git a/deps/npm/test/lib/team.js b/deps/npm/test/lib/team.js deleted file mode 100644 index 68ac28fff36ff8..00000000000000 --- a/deps/npm/test/lib/team.js +++ /dev/null @@ -1,557 +0,0 @@ -const t = require('tap') - -let result = '' -const libnpmteam = { - async add () {}, - async create () {}, - async destroy () {}, - async lsTeams () {}, - async lsUsers () {}, - async rm () {}, -} -const npm = { - flatOptions: {}, - output: (...msg) => { - result += msg.join('\n') - }, -} -const mocks = { - libnpmteam, - 'cli-columns': a => a.join(' '), - '../../lib/utils/otplease.js': async (opts, fn) => fn(opts), - '../../lib/utils/usage.js': () => 'usage instructions', -} - -t.afterEach(() => { - result = '' - npm.flatOptions = {} -}) - -const Team = t.mock('../../lib/team.js', mocks) -const team = new Team(npm) - -t.test('no args', t => { - team.exec([], err => { - t.match( - err, - 'usage instructions', - 'should throw usage instructions' - ) - t.end() - }) -}) - -t.test('team add ', t => { - t.test('default output', t => { - team.exec(['add', '@npmcli:developers', 'foo'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should output success result for add user') - t.end() - }) - }) - - t.test('--parseable', t => { - npm.flatOptions.parseable = true - - team.exec(['add', '@npmcli:developers', 'foo'], err => { - if (err) - throw err - - t.matchSnapshot( - result, - 'should output success result for parseable add user' - ) - t.end() - }) - }) - - t.test('--json', t => { - npm.flatOptions.json = true - - team.exec(['add', '@npmcli:developers', 'foo'], err => { - if (err) - throw err - - t.same( - JSON.parse(result), - { - added: true, - team: 'npmcli:developers', - user: 'foo', - }, - 'should output success result for add user json' - ) - t.end() - }) - }) - - t.test('--silent', t => { - npm.flatOptions.silent = true - - team.exec(['add', '@npmcli:developers', 'foo'], err => { - if (err) - throw err - - t.same(result, '', 'should not output success if silent') - t.end() - }) - }) - - t.end() -}) - -t.test('team create ', t => { - t.test('default output', t => { - team.exec(['create', '@npmcli:newteam'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should output success result for create team') - t.end() - }) - }) - - t.test('--parseable', t => { - npm.flatOptions.parseable = true - - team.exec(['create', '@npmcli:newteam'], err => { - if (err) - throw err - - t.matchSnapshot( - result, - 'should output parseable success result for create team' - ) - t.end() - }) - }) - - t.test('--json', t => { - npm.flatOptions.json = true - - team.exec(['create', '@npmcli:newteam'], err => { - if (err) - throw err - - t.same( - JSON.parse(result), - { - created: true, - team: 'npmcli:newteam', - }, - 'should output success result for create team' - ) - t.end() - }) - }) - - t.test('--silent', t => { - npm.flatOptions.silent = true - - team.exec(['create', '@npmcli:newteam'], err => { - if (err) - throw err - - t.same(result, '', 'should not output create success if silent') - t.end() - }) - }) - - t.end() -}) - -t.test('team destroy ', t => { - t.test('default output', t => { - team.exec(['destroy', '@npmcli:newteam'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should output success result for destroy team') - t.end() - }) - }) - - t.test('--parseable', t => { - npm.flatOptions.parseable = true - - team.exec(['destroy', '@npmcli:newteam'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should output parseable result for destroy team') - t.end() - }) - }) - - t.test('--json', t => { - npm.flatOptions.json = true - - team.exec(['destroy', '@npmcli:newteam'], err => { - if (err) - throw err - - t.same( - JSON.parse(result), - { - deleted: true, - team: 'npmcli:newteam', - }, - 'should output parseable result for destroy team' - ) - t.end() - }) - }) - - t.test('--silent', t => { - npm.flatOptions.silent = true - - team.exec(['destroy', '@npmcli:newteam'], err => { - if (err) - throw err - - t.same(result, '', 'should not output destroy if silent') - t.end() - }) - }) - - t.end() -}) - -t.test('team ls ', t => { - const libnpmteam = { - async lsTeams () { - return [ - 'npmcli:developers', - 'npmcli:designers', - 'npmcli:product', - ] - }, - } - - const Team = t.mock('../../lib/team.js', { - ...mocks, - libnpmteam, - }) - const team = new Team(npm) - - t.test('default output', t => { - team.exec(['ls', '@npmcli'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should list teams for a given scope') - t.end() - }) - }) - - t.test('--parseable', t => { - npm.flatOptions.parseable = true - - team.exec(['ls', '@npmcli'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should list teams for a parseable scope') - t.end() - }) - }) - - t.test('--json', t => { - npm.flatOptions.json = true - - team.exec(['ls', '@npmcli'], err => { - if (err) - throw err - - t.same( - JSON.parse(result), - [ - 'npmcli:designers', - 'npmcli:developers', - 'npmcli:product', - ], - 'should json list teams for a scope json' - ) - t.end() - }) - }) - - t.test('--silent', t => { - npm.flatOptions.silent = true - - team.exec(['ls', '@npmcli'], err => { - if (err) - throw err - - t.same(result, '', 'should not list teams if silent') - t.end() - }) - }) - - t.test('no teams', t => { - const libnpmteam = { - async lsTeams () { - return [] - }, - } - - const Team = t.mock('../../lib/team.js', { - ...mocks, - libnpmteam, - }) - const team = new Team(npm) - - team.exec(['ls', '@npmcli'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should list no teams for a given scope') - t.end() - }) - }) - - t.test('single team', t => { - const libnpmteam = { - async lsTeams () { - return ['npmcli:developers'] - }, - } - - const Team = t.mock('../../lib/team.js', { - ...mocks, - libnpmteam, - }) - const team = new Team(npm) - - team.exec(['ls', '@npmcli'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should list single team for a given scope') - t.end() - }) - }) - - t.end() -}) - -t.test('team ls ', t => { - const libnpmteam = { - async lsUsers () { - return ['nlf', 'ruyadorno', 'darcyclarke', 'isaacs'] - }, - } - const Team = t.mock('../../lib/team.js', { - ...mocks, - libnpmteam, - }) - const team = new Team(npm) - - t.test('default output', t => { - team.exec(['ls', '@npmcli:developers'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should list users for a given scope:team') - t.end() - }) - }) - - t.test('--parseable', t => { - npm.flatOptions.parseable = true - - team.exec(['ls', '@npmcli:developers'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should list users for a parseable scope:team') - t.end() - }) - }) - - t.test('--json', t => { - npm.flatOptions.json = true - - team.exec(['ls', '@npmcli:developers'], err => { - if (err) - throw err - - t.same( - JSON.parse(result), - [ - 'darcyclarke', - 'isaacs', - 'nlf', - 'ruyadorno', - ], - 'should list users for a scope:team json' - ) - t.end() - }) - }) - - t.test('--silent', t => { - npm.flatOptions.silent = true - - team.exec(['ls', '@npmcli:developers'], err => { - if (err) - throw err - - t.same(result, '', 'should not output users if silent') - t.end() - }) - }) - - t.test('no users', t => { - const libnpmteam = { - async lsUsers () { - return [] - }, - } - - const Team = t.mock('../../lib/team.js', { - ...mocks, - libnpmteam, - }) - const team = new Team(npm) - - team.exec(['ls', '@npmcli:developers'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should list no users for a given scope') - t.end() - }) - }) - - t.test('single user', t => { - const libnpmteam = { - async lsUsers () { - return ['foo'] - }, - } - - const Team = t.mock('../../lib/team.js', { - ...mocks, - libnpmteam, - }) - const team = new Team(npm) - - team.exec(['ls', '@npmcli:developers'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should list single user for a given scope') - t.end() - }) - }) - - t.end() -}) - -t.test('team rm ', t => { - t.test('default output', t => { - team.exec(['rm', '@npmcli:newteam', 'foo'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should output success result for remove user') - t.end() - }) - }) - - t.test('--parseable', t => { - npm.flatOptions.parseable = true - - team.exec(['rm', '@npmcli:newteam', 'foo'], err => { - if (err) - throw err - - t.matchSnapshot(result, 'should output parseable result for remove user') - t.end() - }) - }) - - t.test('--json', t => { - npm.flatOptions.json = true - - team.exec(['rm', '@npmcli:newteam', 'foo'], err => { - if (err) - throw err - - t.same( - JSON.parse(result), - { - removed: true, - team: 'npmcli:newteam', - user: 'foo', - }, - 'should output json result for remove user' - ) - t.end() - }) - }) - - t.test('--silent', t => { - npm.flatOptions.silent = true - - team.exec(['rm', '@npmcli:newteam', 'foo'], err => { - if (err) - throw err - - t.same(result, '', 'should not output rm result if silent') - t.end() - }) - }) - - t.end() -}) - -t.test('completion', t => { - const { completion } = team - - t.test('npm team autocomplete', async t => { - const res = await completion({ - conf: { - argv: { - remain: ['npm', 'team'], - }, - }, - }) - t.strictSame( - res, - ['create', 'destroy', 'add', 'rm', 'ls'], - 'should auto complete with subcommands' - ) - t.end() - }) - - t.test('npm team autocomplete', async t => { - for (const subcmd of ['create', 'destroy', 'add', 'rm', 'ls']) { - const res = await completion({ - conf: { - argv: { - remain: ['npm', 'team', subcmd], - }, - }, - }) - t.strictSame( - res, - [], - `should not autocomplete ${subcmd} subcommand` - ) - } - }) - - t.test('npm team unknown subcommand autocomplete', async t => { - t.rejects(completion({conf: {argv: {remain: ['npm', 'team', 'missing-subcommand'] } } }), - {message: 'missing-subcommand not recognized'}, 'should throw a a not recognized error' - ) - - t.end() - }) - - t.end() -}) diff --git a/deps/npm/test/lib/utils/did-you-mean.js b/deps/npm/test/lib/utils/did-you-mean.js index 1285d5300853bc..185368d61f2ed9 100644 --- a/deps/npm/test/lib/utils/did-you-mean.js +++ b/deps/npm/test/lib/utils/did-you-mean.js @@ -1,59 +1,57 @@ const t = require('tap') -const npm = require('../../../lib/npm.js') +const { real: mockNpm } = require('../../fixtures/mock-npm.js') +const { Npm } = mockNpm(t) +const npm = new Npm() const dym = require('../../../lib/utils/did-you-mean.js') -t.test('did-you-mean', t => { - npm.load(err => { - t.notOk(err) - t.test('with package.json', t => { - const testdir = t.testdir({ - 'package.json': JSON.stringify({ - bin: { - npx: 'exists', - }, - scripts: { - install: 'exists', - posttest: 'exists', - }, - }), - }) - t.test('nistall', async t => { - const result = await dym(npm, testdir, 'nistall') - t.match(result, 'npm install') - }) - t.test('sttest', async t => { - const result = await dym(npm, testdir, 'sttest') - t.match(result, 'npm test') - t.match(result, 'npm run posttest') - }) - t.test('npz', async t => { - const result = await dym(npm, testdir, 'npxx') - t.match(result, 'npm exec npx') - }) - t.test('qwuijbo', async t => { - const result = await dym(npm, testdir, 'qwuijbo') - t.match(result, '') - }) - t.end() +t.test('did-you-mean', async t => { + await npm.load() + t.test('with package.json', async t => { + const testdir = t.testdir({ + 'package.json': JSON.stringify({ + bin: { + npx: 'exists', + }, + scripts: { + install: 'exists', + posttest: 'exists', + }, + }), }) - t.test('with no package.json', t => { - const testdir = t.testdir({}) - t.test('nistall', async t => { - const result = await dym(npm, testdir, 'nistall') - t.match(result, 'npm install') - }) - t.end() + t.test('nistall', async t => { + const result = await dym(npm, testdir, 'nistall') + t.match(result, 'npm install') }) - t.test('missing bin and script properties', async t => { - const testdir = t.testdir({ - 'package.json': JSON.stringify({ - name: 'missing-bin', - }), - }) - + t.test('sttest', async t => { + const result = await dym(npm, testdir, 'sttest') + t.match(result, 'npm test') + t.match(result, 'npm run posttest') + }) + t.test('npz', async t => { + const result = await dym(npm, testdir, 'npxx') + t.match(result, 'npm exec npx') + }) + t.test('qwuijbo', async t => { + const result = await dym(npm, testdir, 'qwuijbo') + t.match(result, '') + }) + }) + t.test('with no package.json', t => { + const testdir = t.testdir({}) + t.test('nistall', async t => { const result = await dym(npm, testdir, 'nistall') t.match(result, 'npm install') }) t.end() }) + t.test('missing bin and script properties', async t => { + const testdir = t.testdir({ + 'package.json': JSON.stringify({ + name: 'missing-bin', + }), + }) + + const result = await dym(npm, testdir, 'nistall') + t.match(result, 'npm install') + }) }) diff --git a/deps/npm/test/lib/utils/error-message.js b/deps/npm/test/lib/utils/error-message.js index 6b2b5c9222e77a..aec4c3a1992711 100644 --- a/deps/npm/test/lib/utils/error-message.js +++ b/deps/npm/test/lib/utils/error-message.js @@ -1,43 +1,48 @@ const t = require('tap') const path = require('path') +const { real: mockNpm } = require('../../fixtures/mock-npm.js') +const { Npm } = mockNpm(t, { + '../../package.json': { + version: '123.456.789-npm', + }, +}) +const npm = new Npm() +const { Npm: UnloadedNpm } = mockNpm(t, { + '../../package.json': { + version: '123.456.789-npm', + }, +}) +const unloadedNpm = new UnloadedNpm() // make a bunch of stuff consistent for snapshots -process.getuid = () => 69 -process.getgid = () => 420 +process.getuid = () => 867 +process.getgid = () => 5309 Object.defineProperty(process, 'arch', { value: 'x64', configurable: true, }) -const { resolve } = require('path') -const npm = require('../../../lib/npm.js') -const CACHE = '/some/cache/dir' -npm.config = { - flat: { - color: false, - }, - loaded: false, - localPrefix: '/some/prefix/dir', - get: key => { - if (key === 'cache') - return CACHE - else if (key === 'node-version') - return '99.99.99' - else if (key === 'global') - return false - else - throw new Error('unexpected config lookup: ' + key) - }, -} - -npm.version = '123.69.420-npm' Object.defineProperty(process, 'version', { - value: '123.69.420-node', + value: '123.456.789-node', configurable: true, }) +const CACHE = '/some/cache/dir' +const testdir = t.testdir({}) +t.before(async () => { + await npm.load() + npm.localPrefix = testdir + unloadedNpm.localPrefix = testdir + npm.config.set('cache', CACHE) + npm.config.set('node-version', '99.99.99') + npm.version = '123.456.789-npm' + unloadedNpm.version = '123.456.789-npm' +}) + +const { resolve } = require('path') + const npmlog = require('npmlog') const verboseLogs = [] npmlog.verbose = (...message) => { @@ -137,11 +142,7 @@ t.test('replace message/stack sensistive info', t => { t.end() }) -t.test('bad engine with config loaded', t => { - npm.config.loaded = true - t.teardown(() => { - npm.config.loaded = false - }) +t.test('bad engine without config loaded', t => { const path = '/some/path' const pkgid = 'some@package' const file = '/some/file' @@ -153,7 +154,7 @@ t.test('bad engine with config loaded', t => { file, stack, }) - t.matchSnapshot(errorMessage(er, npm)) + t.matchSnapshot(errorMessage(er, unloadedNpm)) t.end() }) @@ -219,7 +220,6 @@ t.test('eacces/eperm', t => { else bePosix() - npm.config.loaded = loaded const path = `${cachePath ? CACHE : '/not/cache/dir'}/path` const dest = `${cacheDest ? CACHE : '/not/cache/dir'}/dest` const er = Object.assign(new Error('whoopsie'), { @@ -229,7 +229,11 @@ t.test('eacces/eperm', t => { stack: 'dummy stack trace', }) verboseLogs.length = 0 - t.matchSnapshot(errorMessage(er, npm)) + if (loaded) + t.matchSnapshot(errorMessage(er, npm)) + else + t.matchSnapshot(errorMessage(er, unloadedNpm)) + t.matchSnapshot(verboseLogs) t.end() verboseLogs.length = 0 @@ -471,7 +475,7 @@ t.test('bad platform', t => { }, required: { os: ['!yours', 'mine'], - cpu: ['x420', 'x69'], + cpu: ['x867', 'x5309'], }, code: 'EBADPLATFORM', }) @@ -489,7 +493,7 @@ t.test('explain ERESOLVE errors', t => { t.matchSnapshot(errorMessage(er, npm)) t.match(EXPLAIN_CALLED, [[ er, - false, + undefined, path.resolve(npm.cache, 'eresolve-report.txt'), ]]) t.end() diff --git a/deps/npm/test/lib/utils/exit-handler.js b/deps/npm/test/lib/utils/exit-handler.js index c88a1aef67927d..f74938750237e6 100644 --- a/deps/npm/test/lib/utils/exit-handler.js +++ b/deps/npm/test/lib/utils/exit-handler.js @@ -26,10 +26,14 @@ const cacheFolder = t.testdir({}) const logFile = path.resolve(cacheFolder, '_logs', 'expecteddate-debug.log') const timingFile = path.resolve(cacheFolder, '_timing.json') -const { npm } = mockNpm(t) +const { Npm } = mockNpm(t, { + '../../package.json': { + version: '1.0.0', + }, +}) +const npm = new Npm() t.before(async () => { - npm.version = '1.0.0' await npm.load() npm.config.set('cache', cacheFolder) }) @@ -233,7 +237,8 @@ t.test('update notification', (t) => { t.test('npm.config not ready', (t) => { t.plan(1) - const { npm: unloaded } = mockNpm(t) + const { Npm: Unloaded } = mockNpm(t) + const unloaded = new Unloaded() t.teardown(() => { exitHandler.setNpm(npm) @@ -315,7 +320,8 @@ t.test('call exitHandler with no error', (t) => { }) t.test('defaults to log error msg if stack is missing', (t) => { - const { npm: unloaded } = mockNpm(t) + const { Npm: Unloaded } = mockNpm(t) + const unloaded = new Unloaded() t.teardown(() => { exitHandler.setNpm(npm) diff --git a/deps/npm/test/lib/utils/lifecycle-cmd.js b/deps/npm/test/lib/utils/lifecycle-cmd.js deleted file mode 100644 index 862c87a8e032cf..00000000000000 --- a/deps/npm/test/lib/utils/lifecycle-cmd.js +++ /dev/null @@ -1,29 +0,0 @@ -const t = require('tap') -const LifecycleCmd = require('../../../lib/utils/lifecycle-cmd.js') -let runArgs = null -const npm = { - commands: { - 'run-script': (args, cb) => { - runArgs = args - cb(null, 'called npm.commands.run') - }, - }, -} -t.test('create a lifecycle command', t => { - t.plan(5) - class TestStage extends LifecycleCmd { - static get name () { - return 'test-stage' - } - } - const cmd = new TestStage(npm) - t.match(cmd.usage, /test-stage/) - cmd.exec(['some', 'args'], (er, result) => { - t.same(runArgs, ['test-stage', 'some', 'args']) - t.strictSame(result, 'called npm.commands.run') - }) - cmd.execWorkspaces(['some', 'args'], [], (er, result) => { - t.same(runArgs, ['test-stage', 'some', 'args']) - t.strictSame(result, 'called npm.commands.run') - }) -}) diff --git a/deps/npm/test/lib/utils/npm-usage.js b/deps/npm/test/lib/utils/npm-usage.js index f846a01109d2f2..77254a80d017da 100644 --- a/deps/npm/test/lib/utils/npm-usage.js +++ b/deps/npm/test/lib/utils/npm-usage.js @@ -1,7 +1,10 @@ const t = require('tap') -const npm = require('../../../lib/npm.js') +const { real: mockNpm } = require('../../fixtures/mock-npm.js') +const { Npm } = mockNpm(t) +const npm = new Npm() -t.test('usage', t => { +t.test('usage', async t => { + await npm.load() t.afterEach(() => { npm.config.set('viewer', null) npm.config.set('long', false) @@ -12,56 +15,48 @@ t.test('usage', t => { t.cleanSnapshot = str => str.split(basedir).join('{BASEDIR}') .split(require('../../../package.json').version).join('{VERSION}') - npm.load(err => { - if (err) - throw err + npm.config.set('viewer', null) + npm.config.set('long', false) + npm.config.set('userconfig', '/some/config/file/.npmrc') - npm.config.set('viewer', null) - npm.config.set('long', false) - npm.config.set('userconfig', '/some/config/file/.npmrc') + t.test('basic usage', async t => { + t.matchSnapshot(await npm.usage) + t.end() + }) - t.test('basic usage', t => { - t.matchSnapshot(npm.usage) - t.end() - }) + t.test('with browser', async t => { + npm.config.set('viewer', 'browser') + t.matchSnapshot(await npm.usage) + t.end() + }) - t.test('with browser', t => { - npm.config.set('viewer', 'browser') - t.matchSnapshot(npm.usage) - t.end() - }) + t.test('with long', async t => { + npm.config.set('long', true) + t.matchSnapshot(await npm.usage) + t.end() + }) - t.test('with long', t => { - npm.config.set('long', true) - t.matchSnapshot(npm.usage) - t.end() + t.test('set process.stdout.columns', async t => { + const { columns } = process.stdout + t.teardown(() => { + Object.defineProperty(process.stdout, 'columns', { + value: columns, + enumerable: true, + configurable: true, + writable: true, + }) }) - - t.test('set process.stdout.columns', t => { - const { columns } = process.stdout - t.teardown(() => { + const cases = [0, 90] + for (const cols of cases) { + t.test(`columns=${cols}`, async t => { Object.defineProperty(process.stdout, 'columns', { - value: columns, + value: cols, enumerable: true, configurable: true, writable: true, }) + t.matchSnapshot(await npm.usage) }) - 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, - }) - t.matchSnapshot(npm.usage) - t.end() - }) - } - t.end() - }) - t.end() + } }) }) diff --git a/deps/npm/test/lib/utils/reify-finish.js b/deps/npm/test/lib/utils/reify-finish.js index bbe8a3d99021d4..b66d5bcd3b53a3 100644 --- a/deps/npm/test/lib/utils/reify-finish.js +++ b/deps/npm/test/lib/utils/reify-finish.js @@ -76,11 +76,3 @@ t.test('should write if everything above passes', async t => { const data = fs.readFileSync(`${path}/npmrc`, 'utf8').replace(/\r\n/g, '\n') t.matchSnapshot(data, 'written config') }) - -t.test('works without fs.promises', async t => { - t.doesNotThrow(() => t.mock('../../../lib/utils/reify-finish.js', { - fs: { ...fs, promises: null }, - '../../../lib/npm.js': npm, - '../../../lib/utils/reify-output.js': reifyOutput, - })) -})