summaryrefslogtreecommitdiff
path: root/deps/npm/test/lib
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/test/lib')
-rw-r--r--deps/npm/test/lib/ci.js19
-rw-r--r--deps/npm/test/lib/completion.js587
-rw-r--r--deps/npm/test/lib/doctor.js943
-rw-r--r--deps/npm/test/lib/fund.js2
-rw-r--r--deps/npm/test/lib/npm.js1
-rw-r--r--deps/npm/test/lib/search.js193
-rw-r--r--deps/npm/test/lib/team.js572
-rw-r--r--deps/npm/test/lib/utils/flat-options.js22
-rw-r--r--deps/npm/test/lib/utils/reify-output.js2
9 files changed, 2335 insertions, 6 deletions
diff --git a/deps/npm/test/lib/ci.js b/deps/npm/test/lib/ci.js
index 8ddb8f8aad..c32fb83279 100644
--- a/deps/npm/test/lib/ci.js
+++ b/deps/npm/test/lib/ci.js
@@ -6,7 +6,16 @@ const { test } = require('tap')
const requireInject = require('require-inject')
-test('should use Arborist', (t) => {
+test('should use Arborist and run-script', (t) => {
+ const scripts = [
+ 'preinstall',
+ 'install',
+ 'postinstall',
+ 'prepublish', // XXX should we remove this finally??
+ 'preprepare',
+ 'prepare',
+ 'postprepare',
+ ]
const ci = requireInject('../../lib/ci.js', {
'../../lib/npm.js': {
prefix: 'foo',
@@ -15,6 +24,9 @@ test('should use Arborist', (t) => {
},
},
'../../lib/utils/reify-finish.js': async () => {},
+ '@npmcli/run-script': opts => {
+ t.match(opts, { event: scripts.shift() })
+ },
'@npmcli/arborist': function (args) {
t.ok(args, 'gets options object')
this.loadVirtual = () => {
@@ -40,6 +52,7 @@ test('should use Arborist', (t) => {
ci(null, er => {
if (er)
throw er
+ t.strictSame(scripts, [], 'called all scripts')
t.end()
})
})
@@ -53,6 +66,7 @@ test('should pass flatOptions to Arborist.reify', (t) => {
},
},
'../../lib/utils/reify-finish.js': async () => {},
+ '@npmcli/run-script': opts => {},
'@npmcli/arborist': function () {
this.loadVirtual = () => Promise.resolve(true)
this.reify = async (options) => {
@@ -80,6 +94,7 @@ test('should throw if package-lock.json or npm-shrinkwrap missing', (t) => {
global: false,
},
},
+ '@npmcli/run-script': opts => {},
'../../lib/utils/reify-finish.js': async () => {},
npmlog: {
verbose: () => {
@@ -102,6 +117,7 @@ test('should throw ECIGLOBAL', (t) => {
global: true,
},
},
+ '@npmcli/run-script': opts => {},
'../../lib/utils/reify-finish.js': async () => {},
})
ci(null, (err, res) => {
@@ -125,6 +141,7 @@ test('should remove existing node_modules before installing', (t) => {
global: false,
},
},
+ '@npmcli/run-script': opts => {},
'../../lib/utils/reify-finish.js': async () => {},
'@npmcli/arborist': function () {
this.loadVirtual = () => Promise.resolve(true)
diff --git a/deps/npm/test/lib/completion.js b/deps/npm/test/lib/completion.js
new file mode 100644
index 0000000000..367a1c03ab
--- /dev/null
+++ b/deps/npm/test/lib/completion.js
@@ -0,0 +1,587 @@
+const { test } = require('tap')
+const requireInject = require('require-inject')
+const fs = require('fs')
+const path = require('path')
+
+const completionScript = fs.readFileSync(path.resolve(__dirname, '../../lib/utils/completion.sh'), { encoding: 'utf8' }).replace(/^#!.*?\n/, '')
+
+const output = []
+const npmConfig = {}
+let accessCompletionError = false
+
+const npm = {
+ config: {
+ set: (key, value) => {
+ npmConfig[key] = value
+ },
+ clear: () => {
+ for (const key in npmConfig)
+ delete npmConfig[key]
+ },
+ },
+ commands: {
+ completion: {
+ completion: (opts, cb) => {
+ return cb(null, [['>>', '~/.bashrc']])
+ },
+ },
+ adduser: {},
+ access: {
+ completion: (opts, cb) => {
+ if (accessCompletionError)
+ return cb(new Error('access completion failed'))
+
+ return cb(null, ['public', 'restricted'])
+ },
+ },
+ donothing: {
+ completion: (opts, cb) => {
+ return cb(null, null)
+ },
+ },
+ driveaboat: {
+ completion: (opts, cb) => {
+ // the leading space here is to exercise the escape method
+ return cb(null, ' fast')
+ },
+ },
+ },
+}
+
+const cmdList = {
+ aliases: {
+ login: 'adduser',
+ },
+ cmdList: [
+ 'access',
+ 'adduser',
+ 'completion',
+ ],
+ plumbing: [],
+}
+
+const config = {
+ types: {
+ global: Boolean,
+ browser: [null, Boolean, String],
+ registry: [null, String],
+ },
+ shorthands: {
+ reg: ['--registry'],
+ },
+}
+
+const deref = (cmd) => {
+ return cmd
+}
+
+const completion = requireInject('../../lib/completion.js', {
+ '../../lib/npm.js': npm,
+ '../../lib/utils/cmd-list.js': cmdList,
+ '../../lib/utils/config.js': config,
+ '../../lib/utils/deref-command.js': deref,
+ '../../lib/utils/is-windows-shell.js': false,
+ '../../lib/utils/output.js': (line) => {
+ output.push(line)
+ },
+})
+
+test('completion completion', t => {
+ const home = process.env.HOME
+ t.teardown(() => {
+ process.env.HOME = home
+ })
+
+ process.env.HOME = t.testdir({
+ '.bashrc': '',
+ '.zshrc': '',
+ })
+
+ completion.completion({ w: 2 }, (err, res) => {
+ if (err)
+ throw err
+
+ t.strictSame(res, [
+ ['>>', '~/.zshrc'],
+ ['>>', '~/.bashrc'],
+ ], 'identifies both shells')
+ t.end()
+ })
+})
+
+test('completion completion no known shells', t => {
+ const home = process.env.HOME
+ t.teardown(() => {
+ process.env.HOME = home
+ })
+
+ process.env.HOME = t.testdir()
+
+ completion.completion({ w: 2 }, (err, res) => {
+ if (err)
+ throw err
+
+ t.strictSame(res, [], 'no responses')
+ t.end()
+ })
+})
+
+test('completion completion wrong word count', t => {
+ completion.completion({ w: 3 }, (err, res) => {
+ if (err)
+ throw err
+
+ t.strictSame(res, undefined, 'no responses')
+ t.end()
+ })
+})
+
+test('completion errors in windows without bash', t => {
+ const compl = requireInject('../../lib/completion.js', {
+ '../../lib/utils/is-windows-shell.js': true,
+ })
+
+ compl({}, (err) => {
+ t.match(err, {
+ code: 'ENOTSUP',
+ message: /completion supported only in MINGW/,
+ }, 'returns the correct error')
+ t.end()
+ })
+})
+
+test('dump script when completion is not being attempted', 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(() => {
+ callback()
+ errorHandler({ errno: 'EPIPE' })
+ })
+ }
+
+ completion({}, (err) => {
+ if (err)
+ throw err
+
+ t.equal(data, completionScript, 'wrote the completion script')
+ t.end()
+ })
+})
+
+test('dump script exits correctly when EPIPE is emitted on stdout', 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: 'EPIPE' })
+ callback()
+ })
+ }
+
+ completion({}, (err) => {
+ if (err)
+ throw err
+
+ t.equal(data, completionScript, 'wrote the completion script')
+ t.end()
+ })
+})
+
+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({}, (err) => {
+ t.equal(err.errno, 'ESOMETHINGELSE', 'propagated error')
+ t.equal(data, completionScript, 'wrote the completion script')
+ t.end()
+ })
+})
+
+test('completion completes single command name', t => {
+ process.env.COMP_CWORD = 1
+ process.env.COMP_LINE = 'npm c'
+ process.env.COMP_POINT = process.env.COMP_LINE.length
+
+ t.teardown(() => {
+ delete process.env.COMP_CWORD
+ delete process.env.COMP_LINE
+ delete process.env.COMP_POINT
+ npm.config.clear()
+ output.length = 0
+ })
+
+ completion(['npm', 'c'], (err, res) => {
+ if (err)
+ throw err
+
+ t.strictSame(output, ['completion'], 'correctly completed a command name')
+ t.end()
+ })
+})
+
+test('completion completes command names', t => {
+ process.env.COMP_CWORD = 1
+ process.env.COMP_LINE = 'npm a'
+ process.env.COMP_POINT = process.env.COMP_LINE.length
+
+ t.teardown(() => {
+ delete process.env.COMP_CWORD
+ delete process.env.COMP_LINE
+ delete process.env.COMP_POINT
+ npm.config.clear()
+ output.length = 0
+ })
+
+ completion(['npm', 'a'], (err, res) => {
+ if (err)
+ throw err
+
+ t.strictSame(output, [['access', 'adduser'].join('\n')], 'correctly completed a command name')
+ t.end()
+ })
+})
+
+test('completion of invalid command name does nothing', t => {
+ process.env.COMP_CWORD = 1
+ process.env.COMP_LINE = 'npm compute'
+ process.env.COMP_POINT = process.env.COMP_LINE.length
+
+ t.teardown(() => {
+ delete process.env.COMP_CWORD
+ delete process.env.COMP_LINE
+ delete process.env.COMP_POINT
+ npm.config.clear()
+ output.length = 0
+ })
+
+ completion(['npm', 'compute'], (err, res) => {
+ if (err)
+ throw err
+
+ t.strictSame(output, [], 'returns no results')
+ t.end()
+ })
+})
+
+test('completion triggers command completions', t => {
+ process.env.COMP_CWORD = 2
+ process.env.COMP_LINE = 'npm access '
+ process.env.COMP_POINT = process.env.COMP_LINE.length
+
+ t.teardown(() => {
+ delete process.env.COMP_CWORD
+ delete process.env.COMP_LINE
+ delete process.env.COMP_POINT
+ npm.config.clear()
+ output.length = 0
+ })
+
+ completion(['npm', 'access', ''], (err, res) => {
+ if (err)
+ throw err
+
+ 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()
+ })
+})
+
+test('completion triggers filtered command completions', t => {
+ process.env.COMP_CWORD = 2
+ process.env.COMP_LINE = 'npm access p'
+ process.env.COMP_POINT = process.env.COMP_LINE.length
+
+ t.teardown(() => {
+ delete process.env.COMP_CWORD
+ delete process.env.COMP_LINE
+ delete process.env.COMP_POINT
+ npm.config.clear()
+ output.length = 0
+ })
+
+ completion(['npm', 'access', 'p'], (err, res) => {
+ if (err)
+ throw err
+
+ 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()
+ })
+})
+
+test('completions for commands that return nested arrays are joined', t => {
+ process.env.COMP_CWORD = 2
+ process.env.COMP_LINE = 'npm completion '
+ process.env.COMP_POINT = process.env.COMP_LINE.length
+
+ t.teardown(() => {
+ delete process.env.COMP_CWORD
+ delete process.env.COMP_LINE
+ delete process.env.COMP_POINT
+ npm.config.clear()
+ output.length = 0
+ })
+
+ completion(['npm', 'completion', ''], (err, res) => {
+ if (err)
+ throw err
+
+ 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()
+ })
+})
+
+test('completions for commands that return nothing work correctly', t => {
+ process.env.COMP_CWORD = 2
+ process.env.COMP_LINE = 'npm donothing '
+ process.env.COMP_POINT = process.env.COMP_LINE.length
+
+ t.teardown(() => {
+ delete process.env.COMP_CWORD
+ delete process.env.COMP_LINE
+ delete process.env.COMP_POINT
+ npm.config.clear()
+ output.length = 0
+ })
+
+ completion(['npm', 'donothing', ''], (err, res) => {
+ if (err)
+ throw err
+
+ t.strictSame(npmConfig, {
+ argv: {
+ remain: ['npm', 'donothing'],
+ cooked: ['npm', 'donothing'],
+ original: ['npm', 'donothing'],
+ },
+ }, 'applies command config appropriately')
+ t.strictSame(output, [], 'returns nothing')
+ t.end()
+ })
+})
+
+test('completions for commands that return a single item work correctly', t => {
+ process.env.COMP_CWORD = 2
+ process.env.COMP_LINE = 'npm driveaboat '
+ process.env.COMP_POINT = process.env.COMP_LINE.length
+
+ t.teardown(() => {
+ delete process.env.COMP_CWORD
+ delete process.env.COMP_LINE
+ delete process.env.COMP_POINT
+ npm.config.clear()
+ output.length = 0
+ })
+
+ completion(['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()
+ })
+})
+
+test('command completion for commands with no completion return no results', t => {
+ process.env.COMP_CWORD = 2
+ process.env.COMP_LINE = 'npm adduser '
+ process.env.COMP_POINT = process.env.COMP_LINE.length
+
+ t.teardown(() => {
+ delete process.env.COMP_CWORD
+ delete process.env.COMP_LINE
+ delete process.env.COMP_POINT
+ npm.config.clear()
+ output.length = 0
+ })
+
+ // quotes around adduser are to ensure coverage when unescaping commands
+ completion(['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()
+ })
+})
+
+test('command completion errors propagate', t => {
+ process.env.COMP_CWORD = 2
+ process.env.COMP_LINE = 'npm access '
+ process.env.COMP_POINT = process.env.COMP_LINE.length
+ accessCompletionError = true
+
+ t.teardown(() => {
+ delete process.env.COMP_CWORD
+ delete process.env.COMP_LINE
+ delete process.env.COMP_POINT
+ npm.config.clear()
+ output.length = 0
+ accessCompletionError = false
+ })
+
+ completion(['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()
+ })
+})
+
+test('completion can complete flags', t => {
+ process.env.COMP_CWORD = 2
+ process.env.COMP_LINE = 'npm install --'
+ process.env.COMP_POINT = process.env.COMP_LINE.length
+
+ t.teardown(() => {
+ delete process.env.COMP_CWORD
+ delete process.env.COMP_LINE
+ delete process.env.COMP_POINT
+ npm.config.clear()
+ output.length = 0
+ })
+
+ completion(['npm', 'install', '--'], (err, res) => {
+ if (err)
+ throw err
+
+ 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()
+ })
+})
+
+test('double dashes escape from flag completion', t => {
+ process.env.COMP_CWORD = 2
+ process.env.COMP_LINE = 'npm -- install --'
+ process.env.COMP_POINT = process.env.COMP_LINE.length
+
+ t.teardown(() => {
+ delete process.env.COMP_CWORD
+ delete process.env.COMP_LINE
+ delete process.env.COMP_POINT
+ npm.config.clear()
+ output.length = 0
+ })
+
+ completion(['npm', '--', 'install', '--'], (err, res) => {
+ if (err)
+ throw err
+
+ t.strictSame(npmConfig, {}, 'does not apply command config')
+ t.strictSame(output, [['access', 'adduser', 'completion', 'login'].join('\n')], 'correctly completes flag names')
+ t.end()
+ })
+})
+
+test('completion cannot complete options that take a value in mid-command', t => {
+ process.env.COMP_CWORD = 2
+ process.env.COMP_LINE = 'npm --registry install'
+ process.env.COMP_POINT = process.env.COMP_LINE.length
+
+ t.teardown(() => {
+ delete process.env.COMP_CWORD
+ delete process.env.COMP_LINE
+ delete process.env.COMP_POINT
+ npm.config.clear()
+ output.length = 0
+ })
+
+ completion(['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()
+ })
+})
diff --git a/deps/npm/test/lib/doctor.js b/deps/npm/test/lib/doctor.js
new file mode 100644
index 0000000000..c2c3fdb978
--- /dev/null
+++ b/deps/npm/test/lib/doctor.js
@@ -0,0 +1,943 @@
+const { test } = require('tap')
+const requireInject = require('require-inject')
+
+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
+}
+
+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',
+}
+
+let latestNpm = npm.version
+const pacote = {
+ manifest: async () => {
+ return { version: latestNpm }
+ },
+}
+
+let whichError = null
+const which = async () => {
+ if (whichError)
+ throw whichError
+ return '/path/to/git'
+}
+
+let verifyResponse = { verifiedCount: 1, verifiedContent: 1 }
+const cacache = {
+ verify: async () => {
+ return verifyResponse
+ },
+}
+
+const doctor = requireInject('../../lib/doctor.js', {
+ '../../lib/utils/is-windows.js': false,
+ '../../lib/utils/ping.js': ping,
+ '../../lib/utils/output.js': (data) => {
+ output.push(data)
+ },
+ '../../lib/npm.js': npm,
+ cacache,
+ pacote,
+ 'make-fetch-happen': fetch,
+ which,
+})
+
+test('npm doctor checks ok', t => {
+ const dir = t.testdir()
+ npm.cache = npm.flatOptions.cache = dir
+ npm.localDir = dir
+ npm.globalDir = dir
+ npm.localBin = dir
+ npm.globalBin = dir
+
+ t.teardown(() => {
+ delete npm.cache
+ delete npm.flatOptions.cache
+ delete npm.localDir
+ delete npm.globalDir
+ delete npm.localBin
+ delete npm.globalBin
+ clearLogs()
+ })
+
+ doctor([], (err) => {
+ if (err) {
+ t.fail(output)
+ return t.end()
+ }
+
+ t.match(logs, {
+ checkPing: { finished: true },
+ getLatestNpmVersion: { finished: true },
+ getLatestNodejsVersion: { finished: true },
+ getGitPath: { finished: true },
+ [dir]: { finished: true },
+ verifyCachedFiles: { finished: true },
+ }, 'trackers all finished')
+ t.match(output, /npm ping\s*ok/, 'ping output is ok')
+ t.match(output, /npm -v\s*ok/, 'npm -v output is ok')
+ t.match(output, /node -v\s*ok/, 'node -v output is ok')
+ t.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok')
+ t.match(output, /which git\s*ok/, 'which git output is ok')
+ t.match(output, /cached files\s*ok/, 'cached files are ok')
+ t.match(output, /local node_modules\s*ok/, 'local node_modules are ok')
+ t.match(output, /global node_modules\s*ok/, 'global node_modules are ok')
+ t.match(output, /local bin folder\s*ok/, 'local bin is ok')
+ t.match(output, /global bin folder\s*ok/, 'global bin is ok')
+ t.match(output, /cache contents\s*ok/, 'cache contents is ok')
+ t.end()
+ })
+})
+
+test('npm doctor supports silent', t => {
+ const dir = t.testdir()
+ npm.cache = npm.flatOptions.cache = dir
+ npm.localDir = dir
+ npm.globalDir = dir
+ npm.localBin = dir
+ npm.globalBin = dir
+ npm.log.level = 'info'
+
+ t.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([], (err) => {
+ if (err) {
+ t.fail(err)
+ return t.end()
+ }
+
+ t.match(logs, {
+ checkPing: { finished: true },
+ getLatestNpmVersion: { finished: true },
+ getLatestNodejsVersion: { finished: true },
+ getGitPath: { finished: true },
+ [dir]: { finished: true },
+ verifyCachedFiles: { finished: true },
+ }, 'trackers all finished')
+ t.strictSame(output, [], 'did not print output')
+ t.end()
+ })
+})
+
+test('npm doctor supports color', t => {
+ const dir = t.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 = () => {}
+
+ t.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([], (err) => {
+ t.match(err, /Some problems found/, 'detected the ping error')
+ t.match(logs, {
+ checkPing: { finished: true },
+ getLatestNpmVersion: { finished: true },
+ getLatestNodejsVersion: { finished: true },
+ getGitPath: { finished: true },
+ [dir]: { finished: true },
+ verifyCachedFiles: { finished: true },
+ }, 'trackers all finished')
+ t.match(output, /npm ping.*not ok/, 'ping output is ok')
+ t.match(output, /npm -v.*ok/, 'npm -v output is ok')
+ t.match(output, /node -v.*ok/, 'node -v output is ok')
+ t.match(output, /npm config get registry.*ok.*using default/, 'npm config get registry output is ok')
+ t.match(output, /which git.*ok/, 'which git output is ok')
+ t.match(output, /cached files.*ok/, 'cached files are ok')
+ t.match(output, /local node_modules.*ok/, 'local node_modules are ok')
+ t.match(output, /global node_modules.*ok/, 'global node_modules are ok')
+ t.match(output, /local bin folder.*ok/, 'local bin is ok')
+ t.match(output, /global bin folder.*ok/, 'global bin is ok')
+ t.match(output, /cache contents.*ok/, 'cache contents is ok')
+ t.notEqual(output[0], ansiTrim(output[0]), 'output should contain color codes')
+ t.end()
+ })
+})
+
+test('npm doctor skips some tests in windows', t => {
+ const winDoctor = requireInject('../../lib/doctor.js', {
+ '../../lib/utils/is-windows.js': true,
+ '../../lib/utils/ping.js': ping,
+ '../../lib/utils/output.js': (data) => {
+ output.push(data)
+ },
+ '../../lib/npm.js': npm,
+ cacache,
+ pacote,
+ 'make-fetch-happen': fetch,
+ which,
+ })
+
+ const dir = t.testdir()
+ npm.cache = npm.flatOptions.cache = dir
+ npm.localDir = dir
+ npm.globalDir = dir
+ npm.localBin = dir
+ npm.globalBin = dir
+
+ t.teardown(() => {
+ delete npm.cache
+ delete npm.flatOptions.cache
+ delete npm.localDir
+ delete npm.globalDir
+ delete npm.localBin
+ delete npm.globalBin
+ clearLogs()
+ })
+
+ winDoctor([], (err) => {
+ if (err) {
+ t.fail(output)
+ return t.end()
+ }
+
+ t.match(logs, {
+ checkPing: { finished: true },
+ getLatestNpmVersion: { finished: true },
+ getLatestNodejsVersion: { finished: true },
+ getGitPath: { finished: true },
+ [dir]: undefined,
+ verifyCachedFiles: { finished: true },
+ }, 'trackers all finished')
+ t.match(output, /npm ping\s*ok/, 'ping output is ok')
+ t.match(output, /npm -v\s*ok/, 'npm -v output is ok')
+ t.match(output, /node -v\s*ok/, 'node -v output is ok')
+ t.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok')
+ t.match(output, /which git\s*ok/, 'which git output is ok')
+ t.match(output, /cache contents\s*ok/, 'cache contents is ok')
+ t.end()
+ })
+})
+
+test('npm doctor ping error E{3}', t => {
+ const dir = t.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 = () => {}
+
+ t.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([], (err) => {
+ t.match(err, /Some problems found/, 'detected the ping error')
+ t.match(logs, {
+ checkPing: { finished: true },
+ getLatestNpmVersion: { finished: true },
+ getLatestNodejsVersion: { finished: true },
+ getGitPath: { finished: true },
+ [dir]: { finished: true },
+ verifyCachedFiles: { finished: true },
+ }, 'trackers all finished')
+ t.match(output, /npm ping\s*not ok\s*111 this error is 111/, 'ping output contains trimmed error')
+ t.match(output, /npm -v\s*ok/, 'npm -v output is ok')
+ t.match(output, /node -v\s*ok/, 'node -v output is ok')
+ t.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok')
+ t.match(output, /which git\s*ok/, 'which git output is ok')
+ t.match(output, /cached files\s*ok/, 'cached files are ok')
+ t.match(output, /local node_modules\s*ok/, 'local node_modules are ok')
+ t.match(output, /global node_modules\s*ok/, 'global node_modules are ok')
+ t.match(output, /local bin folder\s*ok/, 'local bin is ok')
+ t.match(output, /global bin folder\s*ok/, 'global bin is ok')
+ t.match(output, /cache contents\s*ok/, 'cache contents is ok')
+ t.end()
+ })
+})
+
+test('npm doctor generic ping error', t => {
+ const dir = t.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 = () => {}
+
+ t.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([], (err) => {
+ t.match(err, /Some problems found/, 'detected the ping error')
+ t.match(logs, {
+ checkPing: { finished: true },
+ getLatestNpmVersion: { finished: true },
+ getLatestNodejsVersion: { finished: true },
+ getGitPath: { finished: true },
+ [dir]: { finished: true },
+ verifyCachedFiles: { finished: true },
+ }, 'trackers all finished')
+ t.match(output, /npm ping\s*not ok\s*generic error/, 'ping output contains trimmed error')
+ t.match(output, /npm -v\s*ok/, 'npm -v output is ok')
+ t.match(output, /node -v\s*ok/, 'node -v output is ok')
+ t.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok')
+ t.match(output, /which git\s*ok/, 'which git output is ok')
+ t.match(output, /cached files\s*ok/, 'cached files are ok')
+ t.match(output, /local node_modules\s*ok/, 'local node_modules are ok')
+ t.match(output, /global node_modules\s*ok/, 'global node_modules are ok')
+ t.match(output, /local bin folder\s*ok/, 'local bin is ok')
+ t.match(output, /global bin folder\s*ok/, 'global bin is ok')
+ t.match(output, /cache contents\s*ok/, 'cache contents is ok')
+ t.end()
+ })
+})
+
+test('npm doctor outdated npm version', t => {
+ const dir = t.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 = () => {}
+
+ t.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([], (err) => {
+ t.match(err, /Some problems found/, 'detected the out of date npm')
+ t.match(logs, {
+ checkPing: { finished: true },
+ getLatestNpmVersion: { finished: true },
+ getLatestNodejsVersion: { finished: true },
+ getGitPath: { finished: true },
+ [dir]: { finished: true },
+ verifyCachedFiles: { finished: true },
+ }, 'trackers all finished')
+ t.match(output, /npm ping\s*ok/, 'ping output is ok')
+ t.match(output, /npm -v\s*not ok/, 'npm -v output is not ok')
+ t.match(output, /node -v\s*ok/, 'node -v output is ok')
+ t.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok')
+ t.match(output, /which git\s*ok/, 'which git output is ok')
+ t.match(output, /cached files\s*ok/, 'cached files are ok')
+ t.match(output, /local node_modules\s*ok/, 'local node_modules are ok')
+ t.match(output, /global node_modules\s*ok/, 'global node_modules are ok')
+ t.match(output, /local bin folder\s*ok/, 'local bin is ok')
+ t.match(output, /global bin folder\s*ok/, 'global bin is ok')
+ t.match(output, /cache contents\s*ok/, 'cache contents is ok')
+ t.end()
+ })
+})
+
+test('npm doctor outdated nodejs version', t => {
+ const dir = t.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 = () => {}
+
+ t.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([], (err) => {
+ t.match(err, /Some problems found/, 'detected the out of date nodejs')
+ t.match(logs, {
+ checkPing: { finished: true },
+ getLatestNpmVersion: { finished: true },
+ getLatestNodejsVersion: { finished: true },
+ getGitPath: { finished: true },
+ [dir]: { finished: true },
+ verifyCachedFiles: { finished: true },
+ }, 'trackers all finished')
+ t.match(output, /npm ping\s*ok/, 'ping output is ok')
+ t.match(output, /npm -v\s*ok/, 'npm -v output is ok')
+ t.match(output, /node -v\s*not ok/, 'node -v output is not ok')
+ t.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok')
+ t.match(output, /which git\s*ok/, 'which git output is ok')
+ t.match(output, /cached files\s*ok/, 'cached files are ok')
+ t.match(output, /local node_modules\s*ok/, 'local node_modules are ok')
+ t.match(output, /global node_modules\s*ok/, 'global node_modules are ok')
+ t.match(output, /local bin folder\s*ok/, 'local bin is ok')
+ t.match(output, /global bin folder\s*ok/, 'global bin is ok')
+ t.match(output, /cache contents\s*ok/, 'cache contents is ok')
+ t.end()
+ })
+})
+
+test('npm doctor file permission checks', t => {
+ const dir = t.testdir({
+ cache: {
+ one: 'one',
+ link: t.fixture('symlink', './one'),
+ 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 = requireInject('../../lib/doctor.js', {
+ '../../lib/utils/is-windows.js': false,
+ '../../lib/utils/ping.js': ping,
+ '../../lib/utils/output.js': (data) => {
+ output.push(data)
+ },
+ '../../lib/npm.js': npm,
+ cacache,
+ pacote,
+ 'make-fetch-happen': fetch,
+ which,
+ fs,
+ })
+ // 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 = () => {}
+
+ t.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([], (err) => {
+ t.match(err, /Some problems found/, 'identified problems')
+ t.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')
+ t.match(output, /npm ping\s*ok/, 'ping output is ok')
+ t.match(output, /npm -v\s*ok/, 'npm -v output is ok')
+ t.match(output, /node -v\s*ok/, 'node -v output is ok')
+ t.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok')
+ t.match(output, /which git\s*ok/, 'which git output is ok')
+ t.match(output, /cached files\s*not ok/, 'cached files are not ok')
+ t.match(output, /local node_modules\s*not ok/, 'local node_modules are not ok')
+ t.match(output, /global node_modules\s*not ok/, 'global node_modules are not ok')
+ t.match(output, /local bin folder\s*not ok/, 'local bin is not ok')
+ t.match(output, /global bin folder\s*not ok/, 'global bin is not ok')
+ t.match(output, /cache contents\s*ok/, 'cache contents is ok')
+ t.end()
+ })
+})
+
+test('npm doctor missing git', t => {
+ const dir = t.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 = () => {}
+
+ t.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([], (err) => {
+ t.match(err, /Some problems found/, 'detected the missing git')
+ t.match(logs, {
+ checkPing: { finished: true },
+ getLatestNpmVersion: { finished: true },
+ getLatestNodejsVersion: { finished: true },
+ getGitPath: { finished: true },
+ [dir]: { finished: true },
+ verifyCachedFiles: { finished: true },
+ }, 'trackers all finished')
+ t.match(output, /npm ping\s*ok/, 'ping output is ok')
+ t.match(output, /npm -v\s*ok/, 'npm -v output is ok')
+ t.match(output, /node -v\s*ok/, 'node -v output is ok')
+ t.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok')
+ t.match(output, /which git\s*not ok/, 'which git output is not ok')
+ t.match(output, /cached files\s*ok/, 'cached files are ok')
+ t.match(output, /local node_modules\s*ok/, 'local node_modules are ok')
+ t.match(output, /global node_modules\s*ok/, 'global node_modules are ok')
+ t.match(output, /local bin folder\s*ok/, 'local bin is ok')
+ t.match(output, /global bin folder\s*ok/, 'global bin is ok')
+ t.match(output, /cache contents\s*ok/, 'cache contents is ok')
+ t.end()
+ })
+})
+
+test('npm doctor cache verification showed bad content', t => {
+ 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,
+ badContentCount: 1,
+ }
+ const consoleError = console.error
+ // we just print an empty line here, so swallow it and ignore
+ console.error = () => {}
+
+ t.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([], (err) => {
+ // cache verification problems get fixed and so do not throw an error
+ if (err) {
+ t.fail(output)
+ return t.end()
+ }
+
+ t.match(logs, {
+ checkPing: { finished: true },
+ getLatestNpmVersion: { finished: true },
+ getLatestNodejsVersion: { finished: true },
+ getGitPath: { finished: true },
+ [dir]: { finished: true },
+ verifyCachedFiles: { finished: true },
+ }, 'trackers all finished')
+ t.match(output, /npm ping\s*ok/, 'ping output is ok')
+ t.match(output, /npm -v\s*ok/, 'npm -v output is ok')
+ t.match(output, /node -v\s*ok/, 'node -v output is ok')
+ t.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok')
+ t.match(output, /which git\s*ok/, 'which git output is ok')
+ t.match(output, /cached files\s*ok/, 'cached files are ok')
+ t.match(output, /local node_modules\s*ok/, 'local node_modules are ok')
+ t.match(output, /global node_modules\s*ok/, 'global node_modules are ok')
+ t.match(output, /local bin folder\s*ok/, 'local bin is ok')
+ t.match(output, /global bin folder\s*ok/, 'global bin is ok')
+ t.match(output, /cache contents\s*ok/, 'cache contents is not ok')
+ t.end()
+ })
+})
+
+test('npm doctor cache verification showed reclaimed content', t => {
+ 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,
+ reclaimedCount: 1,
+ reclaimedSize: 100,
+ }
+ const consoleError = console.error
+ // we just print an empty line here, so swallow it and ignore
+ console.error = () => {}
+
+ t.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([], (err) => {
+ // cache verification problems get fixed and so do not throw an error
+ if (err) {
+ t.fail(output)
+ return t.end()
+ }
+
+ t.match(logs, {
+ checkPing: { finished: true },
+ getLatestNpmVersion: { finished: true },
+ getLatestNodejsVersion: { finished: true },
+ getGitPath: { finished: true },
+ [dir]: { finished: true },
+ verifyCachedFiles: { finished: true },
+ }, 'trackers all finished')
+ t.match(output, /npm ping\s*ok/, 'ping output is ok')
+ t.match(output, /npm -v\s*ok/, 'npm -v output is ok')
+ t.match(output, /node -v\s*ok/, 'node -v output is ok')
+ t.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok')
+ t.match(output, /which git\s*ok/, 'which git output is ok')
+ t.match(output, /cached files\s*ok/, 'cached files are ok')
+ t.match(output, /local node_modules\s*ok/, 'local node_modules are ok')
+ t.match(output, /global node_modules\s*ok/, 'global node_modules are ok')
+ t.match(output, /local bin folder\s*ok/, 'local bin is ok')
+ t.match(output, /global bin folder\s*ok/, 'global bin is ok')
+ t.match(output, /cache contents\s*ok/, 'cache contents is not ok')
+ t.end()
+ })
+})
+
+test('npm doctor cache verification showed missing content', t => {
+ 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 = () => {}
+
+ t.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([], (err) => {
+ // cache verification problems get fixed and so do not throw an error
+ if (err) {
+ t.fail(output)
+ return t.end()
+ }
+
+ t.match(logs, {
+ checkPing: { finished: true },
+ getLatestNpmVersion: { finished: true },
+ getLatestNodejsVersion: { finished: true },
+ getGitPath: { finished: true },
+ [dir]: { finished: true },
+ verifyCachedFiles: { finished: true },
+ }, 'trackers all finished')
+ t.match(output, /npm ping\s*ok/, 'ping output is ok')
+ t.match(output, /npm -v\s*ok/, 'npm -v output is ok')
+ t.match(output, /node -v\s*ok/, 'node -v output is ok')
+ t.match(output, /npm config get registry\s*ok\s*using default/, 'npm config get registry output is ok')
+ t.match(output, /which git\s*ok/, 'which git output is ok')
+ t.match(output, /cached files\s*ok/, 'cached files are ok')
+ t.match(output, /local node_modules\s*ok/, 'local node_modules are ok')
+ t.match(output, /global node_modules\s*ok/, 'global node_modules are ok')
+ t.match(output, /local bin folder\s*ok/, 'local bin is ok')
+ t.match(output, /global bin folder\s*ok/, 'global bin is ok')
+ t.match(output, /cache contents\s*ok/, 'cache contents is not ok')
+ t.end()
+ })
+})
+
+test('npm doctor not using default registry', t => {
+ const dir = t.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 = () => {}
+
+ t.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([], (err) => {
+ // cache verification problems get fixed and so do not throw an error
+ t.match(err, /Some problems found/, 'detected the non-default registry')
+ t.match(logs, {
+ checkPing: { finished: true },
+ getLatestNpmVersion: { finished: true },
+ getLatestNodejsVersion: { finished: true },
+ getGitPath: { finished: true },
+ [dir]: { finished: true },
+ verifyCachedFiles: { finished: true },
+ }, 'trackers all finished')
+ t.match(output, /npm ping\s*ok/, 'ping output is ok')
+ t.match(output, /npm -v\s*ok/, 'npm -v output is ok')
+ t.match(output, /node -v\s*ok/, 'node -v output is ok')
+ t.match(output, /npm config get registry\s*not ok/, 'npm config get registry output is not ok')
+ t.match(output, /which git\s*ok/, 'which git output is ok')
+ t.match(output, /cached files\s*ok/, 'cached files are ok')
+ t.match(output, /local node_modules\s*ok/, 'local node_modules are ok')
+ t.match(output, /global node_modules\s*ok/, 'global node_modules are ok')
+ t.match(output, /local bin folder\s*ok/, 'local bin is ok')
+ t.match(output, /global bin folder\s*ok/, 'global bin is ok')
+ t.match(output, /cache contents\s*ok/, 'cache contents is ok')
+ t.end()
+ })
+})
diff --git a/deps/npm/test/lib/fund.js b/deps/npm/test/lib/fund.js
index a23fc88ced..73f639b6ce 100644
--- a/deps/npm/test/lib/fund.js
+++ b/deps/npm/test/lib/fund.js
@@ -1,5 +1,3 @@
-'use strict'
-
const { test } = require('tap')
const requireInject = require('require-inject')
diff --git a/deps/npm/test/lib/npm.js b/deps/npm/test/lib/npm.js
index 6bfb5b4376..2c71d229a7 100644
--- a/deps/npm/test/lib/npm.js
+++ b/deps/npm/test/lib/npm.js
@@ -1,4 +1,3 @@
-'use strict'
const t = require('tap')
const fs = require('fs')
diff --git a/deps/npm/test/lib/search.js b/deps/npm/test/lib/search.js
new file mode 100644
index 0000000000..1dba1250e0
--- /dev/null
+++ b/deps/npm/test/lib/search.js
@@ -0,0 +1,193 @@
+const Minipass = require('minipass')
+const t = require('tap')
+const requireInject = require('require-inject')
+const libnpmsearchResultFixture =
+ require('../fixtures/libnpmsearch-stream-result.js')
+
+let result = ''
+const flatOptions = {
+ search: {
+ exclude: null,
+ limit: 20,
+ opts: '',
+ },
+}
+const npm = { flatOptions: { ...flatOptions } }
+const npmlog = {
+ silly () {},
+ clearProgress () {},
+}
+const libnpmsearch = {
+ stream () {},
+}
+const mocks = {
+ npmlog,
+ libnpmsearch,
+ '../../lib/npm.js': npm,
+ '../../lib/utils/output.js': (...msg) => {
+ result += msg.join('\n')
+ },
+ '../../lib/utils/usage.js': () => 'usage instructions',
+ // '../../lib/search/format-package-stream.js': a => a,
+}
+
+t.afterEach(cb => {
+ result = ''
+ npm.flatOptions = flatOptions
+ cb()
+})
+
+const search = requireInject('../../lib/search.js', mocks)
+
+t.test('no args', t => {
+ search([], err => {
+ t.match(
+ err,
+ /search must be called with arguments/,
+ 'should throw usage instructions'
+ )
+ t.end()
+ })
+})
+
+t.test('search <name>', t => {
+ const src = new Minipass()
+ src.objectMode = true
+ const libnpmsearch = {
+ stream () {
+ return src
+ },
+ }
+
+ const search = requireInject('../../lib/search.js', {
+ ...mocks,
+ libnpmsearch,
+ })
+
+ search(['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()
+})
+
+t.test('search <name> --searchexclude --searchopts', t => {
+ npm.flatOptions.search = {
+ ...flatOptions.search,
+ exclude: '',
+ }
+
+ const src = new Minipass()
+ src.objectMode = true
+ const libnpmsearch = {
+ stream () {
+ return src
+ },
+ }
+
+ const search = requireInject('../../lib/search.js', {
+ ...mocks,
+ libnpmsearch,
+ })
+
+ search(['foo'], err => {
+ if (err)
+ throw err
+
+ t.matchSnapshot(result, 'should have filtered expected search results')
+
+ t.end()
+ })
+
+ src.write({
+ name: 'foo',
+ scope: 'unscoped',
+ version: '1.0.0',
+ description: '',
+ keywords: [],
+ date: null,
+ author: { name: 'Foo', email: 'foo@npmjs.com' },
+ publisher: { name: 'Foo', email: 'foo@npmjs.com' },
+ maintainers: [
+ { username: 'foo', email: 'foo@npmjs.com' },
+ ],
+ })
+ src.write({
+ name: 'libnpmversion',
+ scope: 'unscoped',
+ version: '1.0.0',
+ description: '',
+ keywords: [],
+ date: null,
+ author: { name: 'Foo', email: 'foo@npmjs.com' },
+ publisher: { name: 'Foo', email: 'foo@npmjs.com' },
+ maintainers: [
+ { username: 'foo', email: 'foo@npmjs.com' },
+ ],
+ })
+
+ src.end()
+})
+
+t.test('empty search results', t => {
+ const src = new Minipass()
+ src.objectMode = true
+ const libnpmsearch = {
+ stream () {
+ return src
+ },
+ }
+
+ const search = requireInject('../../lib/search.js', {
+ ...mocks,
+ libnpmsearch,
+ })
+
+ search(['foo'], err => {
+ if (err)
+ throw err
+
+ t.matchSnapshot(result, 'should have expected search results')
+
+ t.end()
+ })
+
+ src.end()
+})
+
+t.test('search api response error', t => {
+ const src = new Minipass()
+ src.objectMode = true
+ const libnpmsearch = {
+ stream () {
+ return src
+ },
+ }
+
+ const search = requireInject('../../lib/search.js', {
+ ...mocks,
+ libnpmsearch,
+ })
+
+ search(['foo'], err => {
+ t.match(
+ err,
+ /ERR/,
+ 'should throw response error'
+ )
+
+ t.end()
+ })
+
+ src.emit('error', new Error('ERR'))
+
+ src.end()
+})
diff --git a/deps/npm/test/lib/team.js b/deps/npm/test/lib/team.js
new file mode 100644
index 0000000000..c534cc8327
--- /dev/null
+++ b/deps/npm/test/lib/team.js
@@ -0,0 +1,572 @@
+const t = require('tap')
+const requireInject = require('require-inject')
+
+let result = ''
+const libnpmteam = {
+ async add () {},
+ async create () {},
+ async destroy () {},
+ async lsTeams () {},
+ async lsUsers () {},
+ async rm () {},
+}
+const npm = { flatOptions: {} }
+const mocks = {
+ libnpmteam,
+ 'cli-columns': a => a.join(' '),
+ '../../lib/npm.js': npm,
+ '../../lib/utils/output.js': (...msg) => {
+ result += msg.join('\n')
+ },
+ '../../lib/utils/otplease.js': async (opts, fn) => fn(opts),
+ '../../lib/utils/usage.js': () => 'usage instructions',
+}
+
+t.afterEach(cb => {
+ result = ''
+ npm.flatOptions = {}
+ cb()
+})
+
+const team = requireInject('../../lib/team.js', mocks)
+
+t.test('no args', t => {
+ team([], err => {
+ t.match(
+ err,
+ 'usage instructions',
+ 'should throw usage instructions'
+ )
+ t.end()
+ })
+})
+
+t.test('team add <scope:team> <user>', t => {
+ t.test('default output', t => {
+ team(['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(['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(['add', '@npmcli:developers', 'foo'], err => {
+ if (err)
+ throw err
+
+ t.deepEqual(
+ 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(['add', '@npmcli:developers', 'foo'], err => {
+ if (err)
+ throw err
+
+ t.deepEqual(result, '', 'should not output success if silent')
+ t.end()
+ })
+ })
+
+ t.end()
+})
+
+t.test('team create <scope:team>', t => {
+ t.test('default output', t => {
+ team(['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(['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(['create', '@npmcli:newteam'], err => {
+ if (err)
+ throw err
+
+ t.deepEqual(
+ 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(['create', '@npmcli:newteam'], err => {
+ if (err)
+ throw err
+
+ t.deepEqual(result, '', 'should not output create success if silent')
+ t.end()
+ })
+ })
+
+ t.end()
+})
+
+t.test('team destroy <scope:team>', t => {
+ t.test('default output', t => {
+ team(['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(['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(['destroy', '@npmcli:newteam'], err => {
+ if (err)
+ throw err
+
+ t.deepEqual(
+ 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(['destroy', '@npmcli:newteam'], err => {
+ if (err)
+ throw err
+
+ t.deepEqual(result, '', 'should not output destroy if silent')
+ t.end()
+ })
+ })
+
+ t.end()
+})
+
+t.test('team ls <scope>', t => {
+ const libnpmteam = {
+ async lsTeams () {
+ return [
+ 'npmcli:developers',
+ 'npmcli:designers',
+ 'npmcli:product',
+ ]
+ },
+ }
+
+ const team = requireInject('../../lib/team.js', {
+ ...mocks,
+ libnpmteam,
+ })
+
+ t.test('default output', t => {
+ team(['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(['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(['ls', '@npmcli'], err => {
+ if (err)
+ throw err
+
+ t.deepEqual(
+ 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(['ls', '@npmcli'], err => {
+ if (err)
+ throw err
+
+ t.deepEqual(result, '', 'should not list teams if silent')
+ t.end()
+ })
+ })
+
+ t.test('no teams', t => {
+ const libnpmteam = {
+ async lsTeams () {
+ return []
+ },
+ }
+
+ const team = requireInject('../../lib/team.js', {
+ ...mocks,
+ libnpmteam,
+ })
+
+ team(['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 = requireInject('../../lib/team.js', {
+ ...mocks,
+ libnpmteam,
+ })
+
+ team(['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 <scope:team>', t => {
+ const libnpmteam = {
+ async lsUsers () {
+ return ['nlf', 'ruyadorno', 'darcyclarke', 'isaacs']
+ },
+ }
+ const team = requireInject('../../lib/team.js', {
+ ...mocks,
+ libnpmteam,
+ })
+
+ t.test('default output', t => {
+ team(['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(['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(['ls', '@npmcli:developers'], err => {
+ if (err)
+ throw err
+
+ t.deepEqual(
+ 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(['ls', '@npmcli:developers'], err => {
+ if (err)
+ throw err
+
+ t.deepEqual(result, '', 'should not output users if silent')
+ t.end()
+ })
+ })
+
+ t.test('no users', t => {
+ const libnpmteam = {
+ async lsUsers () {
+ return []
+ },
+ }
+
+ const team = requireInject('../../lib/team.js', {
+ ...mocks,
+ libnpmteam,
+ })
+
+ team(['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 = requireInject('../../lib/team.js', {
+ ...mocks,
+ libnpmteam,
+ })
+
+ team(['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 <scope:team> <user>', t => {
+ t.test('default output', t => {
+ team(['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(['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(['rm', '@npmcli:newteam', 'foo'], err => {
+ if (err)
+ throw err
+
+ t.deepEqual(
+ 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(['rm', '@npmcli:newteam', 'foo'], err => {
+ if (err)
+ throw err
+
+ t.deepEqual(result, '', 'should not output rm result if silent')
+ t.end()
+ })
+ })
+
+ t.end()
+})
+
+t.test('completion', t => {
+ const { completion } = team
+
+ t.test('npm team autocomplete', t => {
+ completion({
+ conf: {
+ argv: {
+ remain: ['npm', 'team'],
+ },
+ },
+ }, (err, res) => {
+ if (err)
+ throw err
+
+ t.strictSame(
+ res,
+ ['create', 'destroy', 'add', 'rm', 'ls'],
+ 'should auto complete with subcommands'
+ )
+
+ t.end()
+ })
+ })
+
+ t.test('npm team <subcommand> autocomplete', async t => {
+ const check = (subcmd) => new Promise((res, rej) =>
+ completion({
+ conf: {
+ argv: {
+ remain: ['npm', 'team', subcmd],
+ },
+ },
+ }, (err, response) => {
+ if (err)
+ rej(err)
+
+ t.strictSame(
+ response,
+ [],
+ `should not autocomplete ${subcmd} subcommand`
+ )
+ res()
+ }))
+
+ await ['create', 'destroy', 'add', 'rm', 'ls'].map(check)
+ })
+
+ t.test('npm team unknown subcommand autocomplete', t => {
+ completion({
+ conf: {
+ argv: {
+ remain: ['npm', 'team', 'missing-subcommand'],
+ },
+ },
+ }, (err, res) => {
+ t.match(
+ err,
+ /missing-subcommand not recognized/,
+ 'should throw a a not recognized error'
+ )
+
+ t.end()
+ })
+ })
+
+ t.end()
+})
diff --git a/deps/npm/test/lib/utils/flat-options.js b/deps/npm/test/lib/utils/flat-options.js
index 3cbf06a48b..ee7620fa78 100644
--- a/deps/npm/test/lib/utils/flat-options.js
+++ b/deps/npm/test/lib/utils/flat-options.js
@@ -1,6 +1,7 @@
const t = require('tap')
process.env.NODE = '/path/to/some/node'
+process.env.NODE_ENV = 'development'
const logs = []
const log = require('npmlog')
@@ -195,43 +196,56 @@ t.test('tag emits warning', t => {
t.test('omit/include options', t => {
t.test('omit explicitly', t => {
+ const { NODE_ENV } = process.env
const npm = new Mocknpm({
omit: ['dev', 'optional', 'peer'],
})
t.strictSame(flatOptions(npm).omit, ['dev', 'optional', 'peer'])
+ t.equal(process.env.NODE_ENV, 'production')
+ process.env.NODE_ENV = NODE_ENV
t.end()
})
t.test('omit and include some', t => {
+ const { NODE_ENV } = process.env
const npm = new Mocknpm({
omit: ['dev', 'optional', 'peer'],
include: ['peer'],
})
t.strictSame(flatOptions(npm).omit, ['dev', 'optional'])
+ t.equal(process.env.NODE_ENV, 'production')
+ process.env.NODE_ENV = NODE_ENV
t.end()
})
t.test('dev flag', t => {
+ const { NODE_ENV } = process.env
const npm = new Mocknpm({
omit: ['dev', 'optional', 'peer'],
include: [],
dev: true,
})
t.strictSame(flatOptions(npm).omit, ['optional', 'peer'])
+ t.equal(process.env.NODE_ENV, NODE_ENV)
+ process.env.NODE_ENV = NODE_ENV
t.end()
})
t.test('production flag', t => {
+ const { NODE_ENV } = process.env
const npm = new Mocknpm({
omit: [],
include: [],
production: true,
})
t.strictSame(flatOptions(npm).omit, ['dev'])
+ t.equal(process.env.NODE_ENV, 'production')
+ process.env.NODE_ENV = NODE_ENV
t.end()
})
t.test('only', t => {
+ const { NODE_ENV } = process.env
const cases = ['prod', 'production']
t.plan(cases.length)
cases.forEach(c => t.test(c, t => {
@@ -241,26 +255,34 @@ t.test('omit/include options', t => {
only: c,
})
t.strictSame(flatOptions(npm).omit, ['dev'])
+ t.equal(process.env.NODE_ENV, 'production')
+ process.env.NODE_ENV = NODE_ENV
t.end()
}))
})
t.test('also dev', t => {
+ const { NODE_ENV } = process.env
const npm = new Mocknpm({
omit: ['dev', 'optional', 'peer'],
also: 'dev',
})
t.strictSame(flatOptions(npm).omit, ['optional', 'peer'])
+ t.equal(process.env.NODE_ENV, NODE_ENV)
+ process.env.NODE_ENV = NODE_ENV
t.end()
})
t.test('no-optional', t => {
+ const { NODE_ENV } = process.env
const npm = new Mocknpm({
optional: false,
omit: null,
include: null,
})
t.strictSame(flatOptions(npm).omit, ['optional'])
+ t.equal(process.env.NODE_ENV, NODE_ENV)
+ process.env.NODE_ENV = NODE_ENV
t.end()
})
diff --git a/deps/npm/test/lib/utils/reify-output.js b/deps/npm/test/lib/utils/reify-output.js
index b905c9ab0f..f7fd96ee87 100644
--- a/deps/npm/test/lib/utils/reify-output.js
+++ b/deps/npm/test/lib/utils/reify-output.js
@@ -1,5 +1,3 @@
-'use strict'
-
const t = require('tap')
const requireInject = require('require-inject')