Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/test/lib
diff options
context:
space:
mode:
Diffstat (limited to 'test/lib')
-rw-r--r--test/lib/auth/legacy.js2
-rw-r--r--test/lib/auth/sso.js2
-rw-r--r--test/lib/cli.js182
-rw-r--r--test/lib/commands/access.js307
-rw-r--r--test/lib/commands/adduser.js9
-rw-r--r--test/lib/commands/audit.js143
-rw-r--r--test/lib/commands/birthday.js13
-rw-r--r--test/lib/commands/cache.js19
-rw-r--r--test/lib/commands/ci.js2
-rw-r--r--test/lib/commands/completion.js249
-rw-r--r--test/lib/commands/dedupe.js61
-rw-r--r--test/lib/commands/diff.js2
-rw-r--r--test/lib/commands/dist-tag.js2
-rw-r--r--test/lib/commands/doctor.js83
-rw-r--r--test/lib/commands/exec.js30
-rw-r--r--test/lib/commands/explore.js11
-rw-r--r--test/lib/commands/find-dupes.js35
-rw-r--r--test/lib/commands/get.js6
-rw-r--r--test/lib/commands/init.js32
-rw-r--r--test/lib/commands/install.js62
-rw-r--r--test/lib/commands/logout.js131
-rw-r--r--test/lib/commands/owner.js22
-rw-r--r--test/lib/commands/pack.js146
-rw-r--r--test/lib/commands/ping.js6
-rw-r--r--test/lib/commands/prefix.js5
-rw-r--r--test/lib/commands/profile.js32
-rw-r--r--test/lib/commands/prune.js26
-rw-r--r--test/lib/commands/publish.js31
-rw-r--r--test/lib/commands/repo.js91
-rw-r--r--test/lib/commands/restart.js34
-rw-r--r--test/lib/commands/root.js5
-rw-r--r--test/lib/commands/run-script.js12
-rw-r--r--test/lib/commands/set-script.js2
-rw-r--r--test/lib/commands/set.js1
-rw-r--r--test/lib/commands/shrinkwrap.js34
-rw-r--r--test/lib/commands/star.js10
-rw-r--r--test/lib/commands/stars.js12
-rw-r--r--test/lib/commands/start.js33
-rw-r--r--test/lib/commands/stop.js30
-rw-r--r--test/lib/commands/test.js32
-rw-r--r--test/lib/commands/token.js24
-rw-r--r--test/lib/commands/unpublish.js9
-rw-r--r--test/lib/commands/update.js28
-rw-r--r--test/lib/commands/version.js504
-rw-r--r--test/lib/commands/view.js18
-rw-r--r--test/lib/commands/whoami.js20
-rw-r--r--test/lib/fixtures/mock-globals.js321
-rw-r--r--test/lib/load-all-commands.js13
-rw-r--r--test/lib/load-all.js39
-rw-r--r--test/lib/npm.js528
-rw-r--r--test/lib/utils/audit-error.js9
-rw-r--r--test/lib/utils/cleanup-log-files.js79
-rw-r--r--test/lib/utils/config/definitions.js107
-rw-r--r--test/lib/utils/did-you-mean.js6
-rw-r--r--test/lib/utils/display.js85
-rw-r--r--test/lib/utils/error-message.js264
-rw-r--r--test/lib/utils/exit-handler.js618
-rw-r--r--test/lib/utils/is-windows-bash.js34
-rw-r--r--test/lib/utils/log-file.js333
-rw-r--r--test/lib/utils/log-shim.js100
-rw-r--r--test/lib/utils/npm-usage.js6
-rw-r--r--test/lib/utils/proc-log-listener.js41
-rw-r--r--test/lib/utils/pulse-till-done.js19
-rw-r--r--test/lib/utils/read-user-info.js30
-rw-r--r--test/lib/utils/reify-output.js7
-rw-r--r--test/lib/utils/setup-log.js296
-rw-r--r--test/lib/utils/tar.js52
-rw-r--r--test/lib/utils/timers.js82
-rw-r--r--test/lib/utils/unsupported.js52
-rw-r--r--test/lib/utils/update-notifier.js70
70 files changed, 3072 insertions, 2669 deletions
diff --git a/test/lib/auth/legacy.js b/test/lib/auth/legacy.js
index 7b61e9f6e..0c23f8ba6 100644
--- a/test/lib/auth/legacy.js
+++ b/test/lib/auth/legacy.js
@@ -6,7 +6,7 @@ const token = '24528a24f240'
const profile = {}
const read = {}
const legacy = t.mock('../../../lib/auth/legacy.js', {
- npmlog: {
+ 'proc-log': {
info: (...msgs) => {
log += msgs.join(' ')
},
diff --git a/test/lib/auth/sso.js b/test/lib/auth/sso.js
index d59220559..473c8cc24 100644
--- a/test/lib/auth/sso.js
+++ b/test/lib/auth/sso.js
@@ -11,7 +11,7 @@ const SSO_URL = 'https://registry.npmjs.org/{SSO_URL}'
const profile = {}
const npmFetch = {}
const sso = t.mock('../../../lib/auth/sso.js', {
- npmlog: {
+ 'proc-log': {
info: (...msgs) => {
log += msgs.join(' ') + '\n'
},
diff --git a/test/lib/cli.js b/test/lib/cli.js
index d762943b4..f02c57d8c 100644
--- a/test/lib/cli.js
+++ b/test/lib/cli.js
@@ -1,176 +1,153 @@
const t = require('tap')
-const { real: mockNpm } = require('../fixtures/mock-npm.js')
-
-const unsupportedMock = {
- checkForBrokenNode: () => {},
- checkForUnsupportedNode: () => {},
-}
-
-let exitHandlerCalled = null
-let exitHandlerNpm = null
-let exitHandlerCb
-const exitHandlerMock = (...args) => {
- exitHandlerCalled = args
- if (exitHandlerCb) {
- exitHandlerCb()
+const mockGlobals = require('../fixtures/mock-globals.js')
+const { load: loadMockNpm } = require('../fixtures/mock-npm.js')
+
+const cliMock = async (t, mocks) => {
+ let exitHandlerArgs = null
+ let npm = null
+ const exitHandlerMock = (...args) => {
+ exitHandlerArgs = args
+ npm.unload()
}
-}
-exitHandlerMock.setNpm = npm => {
- exitHandlerNpm = npm
-}
-
-const logs = []
-const npmlogMock = {
- pause: () => logs.push('pause'),
- verbose: (...msg) => logs.push(['verbose', ...msg]),
- info: (...msg) => logs.push(['info', ...msg]),
-}
+ exitHandlerMock.setNpm = _npm => npm = _npm
-const cliMock = Npm =>
- t.mock('../../lib/cli.js', {
+ const { Npm, outputs, logMocks, logs } = await loadMockNpm(t, { mocks, init: false })
+ const cli = t.mock('../../lib/cli.js', {
'../../lib/npm.js': Npm,
'../../lib/utils/update-notifier.js': async () => null,
- '../../lib/utils/unsupported.js': unsupportedMock,
+ '../../lib/utils/unsupported.js': {
+ checkForBrokenNode: () => {},
+ checkForUnsupportedNode: () => {},
+ },
'../../lib/utils/exit-handler.js': exitHandlerMock,
- npmlog: npmlogMock,
+ ...logMocks,
})
-const processMock = proc => {
- const mocked = {
- ...process,
- on: () => {},
- ...proc,
+ return {
+ Npm,
+ cli,
+ outputs,
+ exitHandlerCalled: () => exitHandlerArgs,
+ exitHandlerNpm: () => npm,
+ logs,
}
- // nopt looks at process directly
- process.argv = mocked.argv
- return mocked
}
-const { argv } = process
-
t.afterEach(() => {
- logs.length = 0
- process.argv = argv
- exitHandlerCalled = null
- exitHandlerNpm = null
+ delete process.exitCode
})
t.test('print the version, and treat npm_g as npm -g', async t => {
- const proc = processMock({
- argv: ['node', 'npm_g', '-v'],
- version: process.version,
+ mockGlobals(t, {
+ 'process.argv': ['node', 'npm_g', '-v'],
})
- const { Npm, outputs } = mockNpm(t)
- const cli = cliMock(Npm)
- await cli(proc)
+ const { logs, cli, Npm, outputs, exitHandlerCalled } = await cliMock(t)
+ await cli(process)
- t.strictSame(proc.argv, ['node', 'npm', '-g', '-v'], 'npm process.argv was rewritten')
t.strictSame(process.argv, ['node', 'npm', '-g', '-v'], 'system process.argv was rewritten')
- t.strictSame(logs, [
- 'pause',
- ['verbose', 'cli', proc.argv],
- ['info', 'using', 'npm@%s', Npm.version],
- ['info', 'using', 'node@%s', process.version],
+ t.strictSame(logs.verbose.filter(([p]) => p !== 'logfile'), [
+ ['cli', process.argv],
+ ])
+ t.strictSame(logs.info, [
+ ['using', 'npm@%s', Npm.version],
+ ['using', 'node@%s', process.version],
])
t.strictSame(outputs, [[Npm.version]])
- t.strictSame(exitHandlerCalled, [])
+ 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'],
+ t.plan(6)
+ mockGlobals(t, {
+ 'process.argv': ['node', 'npm', 'install', 'or', 'whatever', '--versions'],
})
- const { Npm, outputs } = mockNpm(t, {
+ const { logs, cli, Npm, outputs, exitHandlerCalled } = await cliMock(t, {
'../../lib/commands/version.js': class Version {
async exec (args) {
t.strictSame(args, [])
}
},
})
- const cli = cliMock(Npm)
- await cli(proc)
- t.equal(proc.title, 'npm')
- t.strictSame(logs, [
- 'pause',
- ['verbose', 'cli', proc.argv],
- ['info', 'using', 'npm@%s', Npm.version],
- ['info', 'using', 'node@%s', process.version],
+
+ await cli(process)
+ t.equal(process.title, 'npm install or whatever')
+ t.strictSame(logs.verbose.filter(([p]) => p !== 'logfile'), [
+ ['cli', process.argv],
+ ])
+ t.strictSame(logs.info, [
+ ['using', 'npm@%s', Npm.version],
+ ['using', 'node@%s', process.version],
])
t.strictSame(outputs, [])
- t.strictSame(exitHandlerCalled, [])
+ t.strictSame(exitHandlerCalled(), [])
})
t.test('logged argv is sanitized', async t => {
- const proc = processMock({
- argv: [
+ mockGlobals(t, {
+ 'process.argv': [
'node',
'npm',
'version',
'https://username:password@npmjs.org/test_url_with_a_password',
],
})
- const { Npm } = mockNpm(t, {
+ const { logs, cli, Npm } = await cliMock(t, {
'../../lib/commands/version.js': class Version {
async exec (args) {}
},
})
- const cli = cliMock(Npm)
-
- await cli(proc)
- t.equal(proc.title, 'npm')
- t.strictSame(logs, [
- 'pause',
+ await cli(process)
+ t.ok(process.title.startsWith('npm version https://username:***@npmjs.org'))
+ t.strictSame(logs.verbose.filter(([p]) => p !== 'logfile'), [
[
- 'verbose',
'cli',
['node', 'npm', 'version', 'https://username:***@npmjs.org/test_url_with_a_password'],
],
- ['info', 'using', 'npm@%s', Npm.version],
- ['info', 'using', 'node@%s', process.version],
+ ])
+ t.strictSame(logs.info, [
+ ['using', 'npm@%s', Npm.version],
+ ['using', 'node@%s', process.version],
])
})
t.test('print usage if no params provided', async t => {
- const proc = processMock({
- argv: ['node', 'npm'],
+ mockGlobals(t, {
+ 'process.argv': ['node', 'npm'],
})
- const { Npm, outputs } = mockNpm(t)
- const cli = cliMock(Npm)
- await cli(proc)
+ const { cli, outputs, exitHandlerCalled, exitHandlerNpm } = await cliMock(t)
+ await cli(process)
t.match(outputs[0][0], 'Usage:', 'outputs npm usage')
- t.match(exitHandlerCalled, [], 'should call exitHandler with no args')
- t.ok(exitHandlerNpm, 'exitHandler npm is set')
- t.match(proc.exitCode, 1)
+ t.match(exitHandlerCalled(), [], 'should call exitHandler with no args')
+ t.ok(exitHandlerNpm(), 'exitHandler npm is set')
+ t.match(process.exitCode, 1)
})
t.test('print usage if non-command param provided', async t => {
- const proc = processMock({
- argv: ['node', 'npm', 'tset'],
+ mockGlobals(t, {
+ 'process.argv': ['node', 'npm', 'tset'],
})
- const { Npm, outputs } = mockNpm(t)
- const cli = cliMock(Npm)
- await cli(proc)
+ const { cli, outputs, exitHandlerCalled, exitHandlerNpm } = await cliMock(t)
+ await cli(process)
t.match(outputs[0][0], 'Unknown command: "tset"')
t.match(outputs[0][0], 'Did you mean this?')
- t.match(exitHandlerCalled, [], 'should call exitHandler with no args')
- t.ok(exitHandlerNpm, 'exitHandler npm is set')
- t.match(proc.exitCode, 1)
+ t.match(exitHandlerCalled(), [], 'should call exitHandler with no args')
+ t.ok(exitHandlerNpm(), 'exitHandler npm is set')
+ t.match(process.exitCode, 1)
})
t.test('load error calls error handler', async t => {
- const proc = processMock({
- argv: ['node', 'npm', 'asdf'],
+ mockGlobals(t, {
+ 'process.argv': ['node', 'npm', 'asdf'],
})
const err = new Error('test load error')
- const { Npm } = mockNpm(t, {
+ const { cli, exitHandlerCalled } = await cliMock(t, {
'../../lib/utils/config/index.js': {
definitions: null,
flatten: null,
@@ -182,7 +159,6 @@ t.test('load error calls error handler', async t => {
}
},
})
- const cli = cliMock(Npm)
- await cli(proc)
- t.strictSame(exitHandlerCalled, [err])
+ await cli(process)
+ t.strictSame(exitHandlerCalled(), [err])
})
diff --git a/test/lib/commands/access.js b/test/lib/commands/access.js
index fdf132aff..298897e4f 100644
--- a/test/lib/commands/access.js
+++ b/test/lib/commands/access.js
@@ -1,18 +1,9 @@
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
-})
+const { load: loadMockNpm } = require('../../fixtures/mock-npm.js')
t.test('completion', async t => {
+ const { npm } = await loadMockNpm(t)
const access = await npm.cmd('access')
const testComp = (argv, expect) => {
const res = access.completion({ conf: { argv: { remain: argv } } })
@@ -42,6 +33,7 @@ t.test('completion', async t => {
})
t.test('subcommand required', async t => {
+ const { npm } = await loadMockNpm(t)
const access = await npm.cmd('access')
await t.rejects(
npm.exec('access', []),
@@ -50,6 +42,7 @@ t.test('subcommand required', async t => {
})
t.test('unrecognized subcommand', async t => {
+ const { npm } = await loadMockNpm(t)
await t.rejects(
npm.exec('access', ['blerg']),
/Usage: blerg is not a recognized subcommand/,
@@ -58,6 +51,7 @@ t.test('unrecognized subcommand', async t => {
})
t.test('edit', async t => {
+ const { npm } = await loadMockNpm(t)
await t.rejects(
npm.exec('access', ['edit', '@scoped/another']),
/edit subcommand is not implemented yet/,
@@ -66,15 +60,13 @@ t.test('edit', async t => {
})
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',
- }),
+ const { npm } = await loadMockNpm(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/,
@@ -84,30 +76,30 @@ t.test('access public on unscoped package', async t => {
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 name = '@scoped/npm-access-public-pkg'
+ const { npm } = await loadMockNpm(t, {
+ mocks: {
+ 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
+ },
},
},
+ testdir: {
+ 'package.json': JSON.stringify({ name }),
+ },
})
- 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 => {
+ const { npm } = await loadMockNpm(t)
await t.rejects(
npm.exec('access', ['public']),
/no package name passed to command and no package.json found/,
@@ -116,14 +108,12 @@ t.test('access public on missing package.json', async t => {
})
t.test('access public on invalid package.json', async t => {
- t.teardown(() => {
- npm.prefix = prefix
- })
- const testdir = t.testdir({
- 'package.json': '{\n',
- node_modules: {},
+ const { npm } = await loadMockNpm(t, {
+ testdir: {
+ 'package.json': '{\n',
+ node_modules: {},
+ },
})
- npm.prefix = testdir
await t.rejects(
npm.exec('access', ['public']),
{ code: 'EJSONPARSE' },
@@ -132,15 +122,13 @@ t.test('access public on invalid package.json', async t => {
})
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',
- }),
+ const { npm } = await loadMockNpm(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/,
@@ -150,30 +138,30 @@ t.test('access restricted on unscoped package', async t => {
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 name = '@scoped/npm-access-restricted-pkg'
+ const { npm } = await loadMockNpm(t, {
+ mocks: {
+ 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
+ },
},
},
+ testdir: {
+ 'package.json': JSON.stringify({ name }),
+ },
})
- 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 => {
+ const { npm } = await loadMockNpm(t)
await t.rejects(
npm.exec('access', ['restricted']),
/no package name passed to command and no package.json found/,
@@ -182,14 +170,12 @@ t.test('access restricted on missing package.json', async t => {
})
t.test('access restricted on invalid package.json', async t => {
- t.teardown(() => {
- npm.prefix = prefix
- })
- const testdir = t.testdir({
- 'package.json': '{\n',
- node_modules: {},
+ const { npm } = await loadMockNpm(t, {
+ testdir: {
+ 'package.json': '{\n',
+ node_modules: {},
+ },
})
- npm.prefix = testdir
await t.rejects(
npm.exec('access', ['restricted']),
{ code: 'EJSONPARSE' },
@@ -199,17 +185,18 @@ t.test('access restricted on invalid package.json', async t => {
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 } = await loadMockNpm(t, {
+ mocks: {
+ 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',
@@ -220,17 +207,18 @@ t.test('access grant read-only', async t => {
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 } = await loadMockNpm(t, {
+ mocks: {
+ 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',
@@ -241,24 +229,23 @@ t.test('access grant read-write', async t => {
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 } = await loadMockNpm(t, {
+ mocks: {
+ 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
+ },
},
},
+ testdir: {
+ 'package.json': JSON.stringify({
+ name: 'yargs',
+ }),
+ },
})
- const npm = new Npm()
- await npm.load()
- npm.prefix = testdir
await npm.exec('access', [
'grant',
'read-write',
@@ -267,6 +254,7 @@ t.test('access grant current cwd', async t => {
})
t.test('access grant others', async t => {
+ const { npm } = await loadMockNpm(t)
await t.rejects(
npm.exec('access', [
'grant',
@@ -280,6 +268,7 @@ t.test('access grant others', async t => {
})
t.test('access grant missing team args', async t => {
+ const { npm } = await loadMockNpm(t)
await t.rejects(
npm.exec('access', [
'grant',
@@ -293,6 +282,7 @@ t.test('access grant missing team args', async t => {
})
t.test('access grant malformed team arg', async t => {
+ const { npm } = await loadMockNpm(t)
await t.rejects(
npm.exec('access', [
'grant',
@@ -307,36 +297,37 @@ t.test('access grant malformed team arg', async t => {
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 } = await loadMockNpm(t, {
+ mocks: {
+ 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 } = await loadMockNpm(t, {
+ mocks: {
+ 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',
@@ -345,6 +336,7 @@ t.test('access revoke', async t => {
})
t.test('access revoke missing team args', async t => {
+ const { npm } = await loadMockNpm(t)
await t.rejects(
npm.exec('access', [
'revoke',
@@ -357,6 +349,7 @@ t.test('access revoke missing team args', async t => {
})
t.test('access revoke malformed team arg', async t => {
+ const { npm } = await loadMockNpm(t)
await t.rejects(
npm.exec('access', [
'revoke',
@@ -370,30 +363,32 @@ t.test('access revoke malformed team arg', async t => {
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 {}
+ const { npm } = await loadMockNpm(t, {
+ mocks: {
+ libnpmaccess: {
+ lsPackages: (entity) => {
+ t.equal(entity, 'foo', 'should use expected entity')
+ return {}
+ },
},
+ '../../lib/utils/get-identity.js': () => Promise.resolve('foo'),
},
- '../../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 } = await loadMockNpm(t, {
+ mocks: {
+ 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',
@@ -402,36 +397,36 @@ t.test('access ls-packages on team', async t => {
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 } = await loadMockNpm(t, {
+ mocks: {
+ libnpmaccess: {
+ lsCollaborators: (spec) => {
+ t.equal(spec, 'yargs', 'should use expected spec')
+ return {}
+ },
},
},
+ testdir: {
+ 'package.json': JSON.stringify({
+ name: 'yargs',
+ }),
+ },
})
- 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 } = await loadMockNpm(t, {
+ mocks: {
+ 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/test/lib/commands/adduser.js b/test/lib/commands/adduser.js
index 71d79ea93..8a9358f9a 100644
--- a/test/lib/commands/adduser.js
+++ b/test/lib/commands/adduser.js
@@ -20,6 +20,13 @@ const authDummy = (npm, options) => {
throw new Error('did not pass full flatOptions to auth function')
}
+ if (!options.log) {
+ // A quick to test to make sure a log gets passed to auth
+ // XXX: should be refactored with change to real mock npm
+ // https://github.com/npm/statusboard/issues/411
+ throw new Error('pass log to auth')
+ }
+
return Promise.resolve({
message: 'success',
newCreds: {
@@ -71,6 +78,8 @@ const AddUser = t.mock('../../../lib/commands/adduser.js', {
npmlog: {
clearProgress: () => null,
disableProgress: () => null,
+ },
+ 'proc-log': {
notice: (_, msg) => {
registryOutput = msg
},
diff --git a/test/lib/commands/audit.js b/test/lib/commands/audit.js
index 3c87c76a8..05f268d6b 100644
--- a/test/lib/commands/audit.js
+++ b/test/lib/commands/audit.js
@@ -1,5 +1,5 @@
const t = require('tap')
-const { real: mockNpm } = require('../../fixtures/mock-npm')
+const { load: _loadMockNpm } = require('../../fixtures/mock-npm')
t.test('should audit using Arborist', async t => {
let ARB_ARGS = null
@@ -8,36 +8,35 @@ t.test('should audit using Arborist', async t => {
let AUDIT_REPORT_CALLED = false
let ARB_OBJ = null
- const { Npm, outputs } = mockNpm(t, {
- 'npm-audit-report': () => {
- AUDIT_REPORT_CALLED = true
- return {
- report: 'there are vulnerabilities',
- exitCode: 0,
- }
- },
- '@npmcli/arborist': function (args) {
- ARB_ARGS = args
- ARB_OBJ = this
- this.audit = () => {
- AUDIT_CALLED = true
- this.auditReport = {}
- }
- },
- '../../lib/utils/reify-finish.js': (npm, arb) => {
- if (arb !== ARB_OBJ) {
- throw new Error('got wrong object passed to reify-output')
- }
+ const loadMockNpm = (t) => _loadMockNpm(t, {
+ mocks: {
+ 'npm-audit-report': () => {
+ AUDIT_REPORT_CALLED = true
+ return {
+ report: 'there are vulnerabilities',
+ exitCode: 0,
+ }
+ },
+ '@npmcli/arborist': function (args) {
+ ARB_ARGS = args
+ ARB_OBJ = this
+ this.audit = () => {
+ AUDIT_CALLED = true
+ this.auditReport = {}
+ }
+ },
+ '../../lib/utils/reify-finish.js': (npm, arb) => {
+ if (arb !== ARB_OBJ) {
+ throw new Error('got wrong object passed to reify-output')
+ }
- REIFY_FINISH_CALLED = true
+ REIFY_FINISH_CALLED = true
+ },
},
})
- const npm = new Npm()
- await npm.load()
- npm.prefix = t.testdir()
-
t.test('audit', async t => {
+ const { npm, outputs } = await loadMockNpm(t)
await npm.exec('audit', [])
t.match(ARB_ARGS, { audit: true, path: npm.prefix })
t.equal(AUDIT_CALLED, true, 'called audit')
@@ -46,6 +45,7 @@ t.test('should audit using Arborist', async t => {
})
t.test('audit fix', async t => {
+ const { npm } = await loadMockNpm(t)
await npm.exec('audit', ['fix'])
t.equal(REIFY_FINISH_CALLED, true, 'called reify output')
})
@@ -53,69 +53,67 @@ t.test('should audit using Arborist', async t => {
t.test('should audit - json', async t => {
t.plan(1)
- const { Npm } = mockNpm(t, {
- 'npm-audit-report': (_, opts) => {
- t.match(opts.reporter, 'json')
- return {
- report: 'there are vulnerabilities',
- exitCode: 0,
- }
+ const { npm } = await _loadMockNpm(t, {
+ mocks: {
+ 'npm-audit-report': (_, opts) => {
+ t.match(opts.reporter, 'json')
+ return {
+ report: 'there are vulnerabilities',
+ exitCode: 0,
+ }
+ },
+ '@npmcli/arborist': function () {
+ this.audit = () => {
+ this.auditReport = {}
+ }
+ },
+ '../../lib/utils/reify-output.js': () => {},
},
- '@npmcli/arborist': function () {
- this.audit = () => {
- this.auditReport = {}
- }
+ config: {
+ json: true,
},
- '../../lib/utils/reify-output.js': () => {},
})
- const npm = new Npm()
- await npm.load()
- npm.prefix = t.testdir()
- npm.config.set('json', true)
await npm.exec('audit', [])
})
t.test('report endpoint error', async t => {
- const { Npm, outputs, filteredLogs } = mockNpm(t, {
- 'npm-audit-report': () => {
- throw new Error('should not call audit report when there are errors')
- },
- '@npmcli/arborist': function () {
- this.audit = () => {
- this.auditReport = {
- error: {
- message: 'hello, this didnt work',
- method: 'POST',
- uri: 'https://example.com/',
- headers: {
- head: ['ers'],
+ const loadMockNpm = (t, options) => _loadMockNpm(t, {
+ mocks: {
+ 'npm-audit-report': () => {
+ throw new Error('should not call audit report when there are errors')
+ },
+ '@npmcli/arborist': function () {
+ this.audit = () => {
+ this.auditReport = {
+ error: {
+ message: 'hello, this didnt work',
+ method: 'POST',
+ uri: 'https://example.com/',
+ headers: {
+ head: ['ers'],
+ },
+ statusCode: 420,
+ body: 'this is a string',
},
- statusCode: 420,
- body: 'this is a string',
- // body: json ? { nope: 'lol' } : Buffer.from('i had a vuln but i eated it lol'),
- },
+ }
}
- }
+ },
+ '../../lib/utils/reify-output.js': () => {},
},
- '../../lib/utils/reify-output.js': () => {},
+ ...options,
})
- const npm = new Npm()
- await npm.load()
- npm.prefix = t.testdir()
- // npm.config.set('json', )
+
t.test('json=false', async t => {
+ const { npm, outputs, logs } = await loadMockNpm(t, { config: { json: false } })
await t.rejects(npm.exec('audit', []), 'audit endpoint returned an error')
- t.match(filteredLogs('warn'), ['hello, this didnt work'])
+ t.match(logs.warn, [['audit', 'hello, this didnt work']])
t.strictSame(outputs, [['this is a string']])
})
t.test('json=true', async t => {
- t.teardown(() => {
- npm.config.set('json', false)
- })
- npm.config.set('json', true)
+ const { npm, outputs, logs } = await loadMockNpm(t, { config: { json: true } })
await t.rejects(npm.exec('audit', []), 'audit endpoint returned an error')
- t.match(filteredLogs('warn'), ['hello, this didnt work'])
+ t.match(logs.warn, [['audit', 'hello, this didnt work']])
t.strictSame(outputs, [[
'{\n' +
' "message": "hello, this didnt work",\n' +
@@ -135,8 +133,7 @@ t.test('report endpoint error', async t => {
})
t.test('completion', async t => {
- const { Npm } = mockNpm(t)
- const npm = new Npm()
+ const { npm } = await _loadMockNpm(t)
const audit = await npm.cmd('audit')
t.test('fix', async t => {
await t.resolveMatch(
diff --git a/test/lib/commands/birthday.js b/test/lib/commands/birthday.js
index 8c95dd57b..9156d3df0 100644
--- a/test/lib/commands/birthday.js
+++ b/test/lib/commands/birthday.js
@@ -1,14 +1,15 @@
const t = require('tap')
-const { real: mockNpm } = require('../../fixtures/mock-npm')
+const { load: loadMockNpm } = require('../../fixtures/mock-npm')
t.test('birthday', async t => {
t.plan(2)
- const { Npm } = mockNpm(t, {
- libnpmexec: ({ args, yes }) => {
- t.ok(yes)
- t.match(args, ['@npmcli/npm-birthday'])
+ const { npm } = await loadMockNpm(t, {
+ mocks: {
+ libnpmexec: ({ args, yes }) => {
+ t.ok(yes)
+ t.match(args, ['@npmcli/npm-birthday'])
+ },
},
})
- const npm = new Npm()
await npm.exec('birthday', [])
})
diff --git a/test/lib/commands/cache.js b/test/lib/commands/cache.js
index 70a8ba1b2..fc92facff 100644
--- a/test/lib/commands/cache.js
+++ b/test/lib/commands/cache.js
@@ -12,11 +12,6 @@ const rimraf = (path, cb) => {
}
let logOutput = []
-const npmlog = {
- silly: (...args) => {
- logOutput.push(['silly', ...args])
- },
-}
let tarballStreamSpec = ''
let tarballStreamOpts = {}
@@ -141,9 +136,16 @@ const cacache = {
const Cache = t.mock('../../../lib/commands/cache.js', {
cacache,
- npmlog,
pacote,
rimraf,
+ 'proc-log': {
+ silly: (...args) => {
+ logOutput.push(['silly', ...args])
+ },
+ warn: (...args) => {
+ logOutput.push(['warn', ...args])
+ },
+ },
})
const npm = mockNpm({
@@ -153,11 +155,6 @@ const npm = mockNpm({
output: (msg) => {
outputOutput.push(msg)
},
- log: {
- warn: (...args) => {
- logOutput.push(['warn', ...args])
- },
- },
})
const cache = new Cache(npm)
diff --git a/test/lib/commands/ci.js b/test/lib/commands/ci.js
index 1091f9125..537d0784f 100644
--- a/test/lib/commands/ci.js
+++ b/test/lib/commands/ci.js
@@ -159,7 +159,7 @@ t.test('should throw if package-lock.json or npm-shrinkwrap missing', async t =>
const CI = t.mock('../../../lib/commands/ci.js', {
'@npmcli/run-script': opts => {},
'../../../lib/utils/reify-finish.js': async () => {},
- npmlog: {
+ 'proc-log': {
verbose: () => {
t.ok(true, 'log fn called')
},
diff --git a/test/lib/commands/completion.js b/test/lib/commands/completion.js
index 51212f06d..dd571baf7 100644
--- a/test/lib/commands/completion.js
+++ b/test/lib/commands/completion.js
@@ -6,189 +6,153 @@ const completionScript = fs
.readFileSync(path.resolve(__dirname, '../../../lib/utils/completion.sh'), { encoding: 'utf8' })
.replace(/^#!.*?\n/, '')
-const { real: mockNpm } = require('../../fixtures/mock-npm')
-
-const { Npm, outputs } = mockNpm(t, {
- '../../lib/utils/is-windows-shell.js': false,
-})
-const npm = new Npm()
+const { load: _loadMockNpm } = require('../../fixtures/mock-npm')
+const mockGlobals = require('../../fixtures/mock-globals')
+
+const loadMockCompletion = async (t, o = {}) => {
+ const { globals, windows, ...options } = o
+ let resetGlobals = {}
+ if (globals) {
+ resetGlobals = mockGlobals(t, globals).reset
+ }
+ const res = await _loadMockNpm(t, {
+ mocks: {
+ '../../lib/utils/is-windows-shell.js': !!windows,
+ ...options.mocks,
+ },
+ ...options,
+ })
+ const completion = await res.npm.cmd('completion')
+ return {
+ resetGlobals,
+ completion,
+ ...res,
+ }
+}
+
+const loadMockCompletionComp = async (t, word, line) =>
+ loadMockCompletion(t, {
+ globals: {
+ 'process.env.COMP_CWORD': word,
+ 'process.env.COMP_LINE': line,
+ 'process.env.COMP_POINT': line.length,
+ },
+ })
t.test('completion', async t => {
- const completion = await npm.cmd('completion')
t.test('completion completion', async t => {
- const home = process.env.HOME
- t.teardown(() => {
- process.env.HOME = home
- })
-
- process.env.HOME = t.testdir({
- '.bashrc': '',
- '.zshrc': '',
+ const { outputs, completion, prefix } = await loadMockCompletion(t, {
+ testdir: {
+ '.bashrc': 'aaa',
+ '.zshrc': 'aaa',
+ },
})
+ mockGlobals(t, { 'process.env.HOME': prefix })
await completion.completion({ w: 2 })
t.matchSnapshot(outputs, 'both shells')
})
t.test('completion completion no known shells', async t => {
- const home = process.env.HOME
- t.teardown(() => {
- process.env.HOME = home
- })
-
- process.env.HOME = t.testdir()
+ const { outputs, completion, prefix } = await loadMockCompletion(t)
+ mockGlobals(t, { 'process.env.HOME': prefix })
await completion.completion({ w: 2 })
t.matchSnapshot(outputs, 'no responses')
})
t.test('completion completion wrong word count', async t => {
+ const { outputs, completion } = await loadMockCompletion(t)
+
await completion.completion({ w: 3 })
t.matchSnapshot(outputs, 'no responses')
})
t.test('dump script when completion is not being attempted', async t => {
- const _write = process.stdout.write
- const _on = process.stdout.on
- t.teardown(() => {
- process.stdout.write = _write
- process.stdout.on = _on
+ let errorHandler, data
+ const { completion, resetGlobals } = await loadMockCompletion(t, {
+ globals: {
+ 'process.stdout.on': (event, handler) => {
+ errorHandler = handler
+ resetGlobals['process.stdout.on']()
+ },
+ 'process.stdout.write': (chunk, callback) => {
+ data = chunk
+ process.nextTick(() => {
+ callback()
+ errorHandler({ errno: 'EPIPE' })
+ })
+ resetGlobals['process.stdout.write']()
+ },
+ },
})
- 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' })
- })
- }
-
await completion.exec({})
-
t.equal(data, completionScript, 'wrote the completion script')
})
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(() => {
- process.stdout.write = _write
- process.stdout.on = _on
+ let errorHandler, data
+ const { completion, resetGlobals } = await loadMockCompletion(t, {
+ globals: {
+ 'process.stdout.on': (event, handler) => {
+ if (event === 'error') {
+ errorHandler = handler
+ }
+ resetGlobals['process.stdout.on']()
+ },
+ 'process.stdout.write': (chunk, callback) => {
+ data = chunk
+ process.nextTick(() => {
+ errorHandler({ errno: 'EPIPE' })
+ callback()
+ })
+ resetGlobals['process.stdout.write']()
+ },
+ },
})
- 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()
- })
- }
-
await completion.exec({})
t.equal(data, completionScript, 'wrote the completion script')
})
t.test('single command name', async t => {
- process.env.COMP_CWORD = 1
- process.env.COMP_LINE = 'npm conf'
- 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
- })
+ const { outputs, completion } = await loadMockCompletionComp(t, 1, 'npm conf')
await completion.exec(['npm', 'conf'])
t.matchSnapshot(outputs, 'single command name')
})
t.test('multiple command names', async 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
- })
+ const { outputs, completion } = await loadMockCompletionComp(t, 1, 'npm a')
await completion.exec(['npm', 'a'])
t.matchSnapshot(outputs, 'multiple command names')
})
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
-
- t.teardown(() => {
- delete process.env.COMP_CWORD
- delete process.env.COMP_LINE
- delete process.env.COMP_POINT
- })
+ const { outputs, completion } = await loadMockCompletionComp(t, 1, 'npm compute')
await completion.exec(['npm', 'compute'])
t.matchSnapshot(outputs, 'no results')
})
t.test('subcommand completion', async 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
- })
+ const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm access ')
await completion.exec(['npm', 'access', ''])
t.matchSnapshot(outputs, 'subcommands')
})
t.test('filtered subcommands', async 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
- })
+ const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm access p')
await completion.exec(['npm', 'access', 'p'])
t.matchSnapshot(outputs, 'filtered subcommands')
})
t.test('commands with no completion', async 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
- })
+ const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm adduser ')
// quotes around adduser are to ensure coverage when unescaping commands
await completion.exec(['npm', "'adduser'", ''])
@@ -196,63 +160,28 @@ t.test('completion', async t => {
})
t.test('flags', async t => {
- process.env.COMP_CWORD = 2
- process.env.COMP_LINE = 'npm install --v'
- 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
- })
+ const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm install --v')
await completion.exec(['npm', 'install', '--v'])
-
t.matchSnapshot(outputs, 'flags')
})
t.test('--no- flags', async t => {
- process.env.COMP_CWORD = 2
- process.env.COMP_LINE = 'npm install --no-v'
- 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
- })
+ const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm install --no-v')
await completion.exec(['npm', 'install', '--no-v'])
-
t.matchSnapshot(outputs, 'flags')
})
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
-
- t.teardown(() => {
- delete process.env.COMP_CWORD
- delete process.env.COMP_LINE
- delete process.env.COMP_POINT
- })
+ const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm -- install --')
await completion.exec(['npm', '--', 'install', '--'])
-
t.matchSnapshot(outputs, 'full command list')
})
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
-
- t.teardown(() => {
- delete process.env.COMP_CWORD
- delete process.env.COMP_LINE
- delete process.env.COMP_POINT
- })
+ const { outputs, completion } = await loadMockCompletionComp(t, 2, 'npm --registry install')
await completion.exec(['npm', '--registry', 'install'])
t.matchSnapshot(outputs, 'does not try to complete option arguments in the middle of a command')
@@ -260,11 +189,7 @@ t.test('completion', async t => {
})
t.test('windows without bash', async t => {
- const { Npm, outputs } = mockNpm(t, {
- '../../lib/utils/is-windows-shell.js': true,
- })
- const npm = new Npm()
- const completion = await npm.cmd('completion')
+ const { outputs, completion } = await loadMockCompletion(t, { windows: true })
await t.rejects(
completion.exec({}),
{ code: 'ENOTSUP', message: /completion supported only in MINGW/ },
diff --git a/test/lib/commands/dedupe.js b/test/lib/commands/dedupe.js
index 8fc0be061..2e2fae238 100644
--- a/test/lib/commands/dedupe.js
+++ b/test/lib/commands/dedupe.js
@@ -1,11 +1,12 @@
const t = require('tap')
-const { real: mockNpm } = require('../../fixtures/mock-npm')
+const { load: loadMockNpm } = require('../../fixtures/mock-npm')
t.test('should throw in global mode', async (t) => {
- const { Npm } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.config.set('global', true)
+ const { npm } = await loadMockNpm(t, {
+ config: {
+ global: true,
+ },
+ })
t.rejects(
npm.exec('dedupe', []),
{ code: 'EDEDUPEGLOBAL' },
@@ -15,39 +16,41 @@ t.test('should throw in global mode', async (t) => {
t.test('should remove dupes using Arborist', async (t) => {
t.plan(5)
- const { Npm } = mockNpm(t, {
- '@npmcli/arborist': function (args) {
- t.ok(args, 'gets options object')
- t.ok(args.path, 'gets path option')
- t.ok(args.dryRun, 'gets dryRun from user')
- this.dedupe = () => {
- t.ok(true, 'dedupe is called')
- }
+ const { npm } = await loadMockNpm(t, {
+ mocks: {
+ '@npmcli/arborist': function (args) {
+ t.ok(args, 'gets options object')
+ t.ok(args.path, 'gets path option')
+ t.ok(args.dryRun, 'gets dryRun from user')
+ this.dedupe = () => {
+ t.ok(true, 'dedupe is called')
+ }
+ },
+ '../../lib/utils/reify-finish.js': (npm, arb) => {
+ t.ok(arb, 'gets arborist tree')
+ },
},
- '../../lib/utils/reify-finish.js': (npm, arb) => {
- t.ok(arb, 'gets arborist tree')
+ config: {
+ 'dry-run': 'true',
},
})
- const npm = new Npm()
- await npm.load()
- npm.config.set('prefix', 'foo')
- npm.config.set('dry-run', 'true')
await npm.exec('dedupe', [])
})
t.test('should remove dupes using Arborist - no arguments', async (t) => {
t.plan(1)
- const { Npm } = mockNpm(t, {
- '@npmcli/arborist': function (args) {
- t.ok(args.dryRun, 'gets dryRun from config')
- this.dedupe = () => {}
+ const { npm } = await loadMockNpm(t, {
+ mocks: {
+ '@npmcli/arborist': function (args) {
+ t.ok(args.dryRun, 'gets dryRun from config')
+ this.dedupe = () => {}
+ },
+ '../../lib/utils/reify-output.js': () => {},
+ '../../lib/utils/reify-finish.js': () => {},
+ },
+ config: {
+ 'dry-run': true,
},
- '../../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 npm.exec('dedupe', [])
})
diff --git a/test/lib/commands/diff.js b/test/lib/commands/diff.js
index 811936fe6..ed0702e37 100644
--- a/test/lib/commands/diff.js
+++ b/test/lib/commands/diff.js
@@ -31,7 +31,7 @@ const npm = mockNpm({
})
const mocks = {
- npmlog: { info: noop, verbose: noop },
+ 'proc-log': { info: noop, verbose: noop },
libnpmdiff: (...args) => libnpmdiff(...args),
'npm-registry-fetch': async () => ({}),
'../../../lib/utils/usage.js': () => 'usage instructions',
diff --git a/test/lib/commands/dist-tag.js b/test/lib/commands/dist-tag.js
index 6b45dc116..756a09d7d 100644
--- a/test/lib/commands/dist-tag.js
+++ b/test/lib/commands/dist-tag.js
@@ -61,7 +61,7 @@ const logger = (...msgs) => {
}
const DistTag = t.mock('../../../lib/commands/dist-tag.js', {
- npmlog: {
+ 'proc-log': {
error: logger,
info: logger,
verbose: logger,
diff --git a/test/lib/commands/doctor.js b/test/lib/commands/doctor.js
index e3ad5cc72..51b6111a0 100644
--- a/test/lib/commands/doctor.js
+++ b/test/lib/commands/doctor.js
@@ -50,13 +50,13 @@ const logs = {
info: [],
}
-const clearLogs = (obj = logs) => {
+const clearLogs = () => {
output.length = 0
- for (const key in obj) {
- if (Array.isArray(obj[key])) {
- obj[key].length = 0
+ for (const key in logs) {
+ if (Array.isArray(logs[key])) {
+ logs[key].length = 0
} else {
- delete obj[key]
+ delete logs[key]
}
}
}
@@ -65,13 +65,41 @@ const npm = {
flatOptions: {
registry: 'https://registry.npmjs.org/',
},
- log: {
+ 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 mocks = {
+ '../../../lib/utils/is-windows.js': false,
+ '../../../lib/utils/ping.js': ping,
+ cacache,
+ pacote,
+ 'make-fetch-happen': fetch,
+ which,
+ 'proc-log': {
info: msg => {
logs.info.push(msg)
},
+ },
+ npmlog: {
newItem: name => {
logs[name] = {}
-
return {
info: (_, msg) => {
if (!logs[name].info) {
@@ -109,33 +137,11 @@ const npm = {
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,
+ ...mocks,
})
const doctor = new Doctor(npm)
@@ -205,7 +211,7 @@ t.test('node versions', t => {
npm.globalDir = dir
npm.localBin = dir
npm.globalBin = dir
- npm.log.level = 'info'
+ mocks.npmlog.level = 'info'
st.teardown(() => {
delete npm.cache
@@ -214,7 +220,7 @@ t.test('node versions', t => {
delete npm.globalDir
delete npm.localBin
delete npm.globalBin
- npm.log.level = 'error'
+ mocks.npmlog.level = 'error'
clearLogs()
})
@@ -293,12 +299,8 @@ t.test('node versions', t => {
vt.test('npm doctor skips some tests in windows', async st => {
const WinDoctor = t.mock('../../../lib/commands/doctor.js', {
+ ...mocks,
'../../../lib/utils/is-windows.js': true,
- '../../../lib/utils/ping.js': ping,
- cacache,
- pacote,
- 'make-fetch-happen': fetch,
- which,
})
const winDoctor = new WinDoctor(npm)
@@ -592,12 +594,7 @@ t.test('node versions', t => {
}
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,
+ ...mocks,
fs,
})
const doctor = new Doctor(npm)
diff --git a/test/lib/commands/exec.js b/test/lib/commands/exec.js
index 4ab26568f..3c75c1d8d 100644
--- a/test/lib/commands/exec.js
+++ b/test/lib/commands/exec.js
@@ -44,17 +44,6 @@ const npm = mockNpm({
localPrefix: 'local-prefix',
localBin: 'local-bin',
globalBin: 'global-bin',
- log: {
- disableProgress: () => {
- PROGRESS_ENABLED = false
- },
- enableProgress: () => {
- PROGRESS_ENABLED = true
- },
- warn: (...args) => {
- LOG_WARN.push(args)
- },
- },
})
const RUN_SCRIPTS = []
@@ -87,6 +76,23 @@ const PATH = require('../../../lib/utils/path.js')
let CI_NAME = 'travis-ci'
+const log = {
+ 'proc-log': {
+ warn: (...args) => {
+ LOG_WARN.push(args)
+ },
+ },
+ npmlog: {
+ disableProgress: () => {
+ PROGRESS_ENABLED = false
+ },
+ enableProgress: () => {
+ PROGRESS_ENABLED = true
+ },
+ clearProgress: () => {},
+ },
+}
+
const mocks = {
libnpmexec: t.mock('libnpmexec', {
'@npmcli/arborist': Arborist,
@@ -95,7 +101,9 @@ const mocks = {
pacote,
read,
'mkdirp-infer-owner': mkdirp,
+ ...log,
}),
+ ...log,
}
const Exec = t.mock('../../../lib/commands/exec.js', mocks)
const exec = new Exec(npm)
diff --git a/test/lib/commands/explore.js b/test/lib/commands/explore.js
index b2e7be213..d1355d767 100644
--- a/test/lib/commands/explore.js
+++ b/test/lib/commands/explore.js
@@ -51,14 +51,17 @@ const getExplore = (windows) => {
path: require('path')[windows ? 'win32' : 'posix'],
'read-package-json-fast': mockRPJ,
'@npmcli/run-script': mockRunScript,
- })
- const npm = {
- dir: windows ? 'c:\\npm\\dir' : '/npm/dir',
- log: {
+ 'proc-log': {
error: (...msg) => logs.push(msg),
+ warn: () => {},
+ },
+ npmlog: {
disableProgress: () => {},
enableProgress: () => {},
},
+ })
+ const npm = {
+ dir: windows ? 'c:\\npm\\dir' : '/npm/dir',
flatOptions: {
shell: 'shell-command',
},
diff --git a/test/lib/commands/find-dupes.js b/test/lib/commands/find-dupes.js
index c1b9c71df..06bd097b6 100644
--- a/test/lib/commands/find-dupes.js
+++ b/test/lib/commands/find-dupes.js
@@ -1,27 +1,28 @@
const t = require('tap')
-const { real: mockNpm } = require('../../fixtures/mock-npm')
+const { load: loadMockNpm } = require('../../fixtures/mock-npm')
t.test('should run dedupe in dryRun mode', async (t) => {
t.plan(5)
- const { Npm } = mockNpm(t, {
- '@npmcli/arborist': function (args) {
- t.ok(args, 'gets options object')
- t.ok(args.path, 'gets path option')
- t.ok(args.dryRun, 'is called in dryRun mode')
- this.dedupe = () => {
- t.ok(true, 'dedupe is called')
- }
+ const { npm } = await loadMockNpm(t, {
+ mocks: {
+ '@npmcli/arborist': function (args) {
+ t.ok(args, 'gets options object')
+ t.ok(args.path, 'gets path option')
+ t.ok(args.dryRun, 'is called in dryRun mode')
+ this.dedupe = () => {
+ t.ok(true, 'dedupe is called')
+ }
+ },
+ '../../lib/utils/reify-finish.js': (npm, arb) => {
+ t.ok(arb, 'gets arborist tree')
+ },
},
- '../../lib/utils/reify-finish.js': (npm, arb) => {
- t.ok(arb, 'gets arborist tree')
+ config: {
+ // explicitly set to false so we can be 100% sure it's always true when it
+ // hits arborist
+ 'dry-run': false,
},
})
- 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 npm.exec('find-dupes', [])
})
diff --git a/test/lib/commands/get.js b/test/lib/commands/get.js
index ba9e770e3..597cccc3f 100644
--- a/test/lib/commands/get.js
+++ b/test/lib/commands/get.js
@@ -1,12 +1,10 @@
const t = require('tap')
-const { real: mockNpm } = require('../../fixtures/mock-npm')
+const { load: loadMockNpm } = require('../../fixtures/mock-npm')
t.test('should retrieve values from config', async t => {
- const { joinedOutput, Npm } = mockNpm(t)
- const npm = new Npm()
+ const { joinedOutput, npm } = await loadMockNpm(t)
const name = 'editor'
const value = 'vigor'
- await npm.load()
npm.config.set(name, value)
await npm.exec('get', [name])
t.equal(
diff --git a/test/lib/commands/init.js b/test/lib/commands/init.js
index 74b33168a..215ebc581 100644
--- a/test/lib/commands/init.js
+++ b/test/lib/commands/init.js
@@ -3,14 +3,6 @@ const fs = require('fs')
const { resolve } = require('path')
const { fake: mockNpm } = require('../../fixtures/mock-npm')
-const npmLog = {
- disableProgress: () => null,
- enableProgress: () => null,
- info: () => null,
- pause: () => null,
- resume: () => null,
- silly: () => null,
-}
const config = {
cache: 'bad-cache-dir',
'init-module': '~/.npm-init.js',
@@ -23,10 +15,19 @@ const flatOptions = {
const npm = mockNpm({
flatOptions,
config,
- log: npmLog,
})
const mocks = {
'../../../lib/utils/usage.js': () => 'usage instructions',
+ npmlog: {
+ disableProgress: () => null,
+ enableProgress: () => null,
+ },
+ 'proc-log': {
+ info: () => null,
+ pause: () => null,
+ resume: () => null,
+ silly: () => null,
+ },
}
const Init = t.mock('../../../lib/commands/init.js', mocks)
const init = new Init(npm)
@@ -37,7 +38,6 @@ const noop = () => {}
t.afterEach(() => {
config.yes = true
config.package = undefined
- npm.log = npmLog
process.chdir(_cwd)
console.log = _consolelog
})
@@ -251,13 +251,15 @@ t.test('npm init cancel', async t => {
'init-package-json': (dir, initFile, config, cb) => cb(
new Error('canceled')
),
+ 'proc-log': {
+ ...mocks['proc-log'],
+ warn: (title, msg) => {
+ t.equal(title, 'init', 'should have init title')
+ t.equal(msg, 'canceled', 'should log canceled')
+ },
+ },
})
const init = new Init(npm)
- npm.log = { ...npm.log }
- npm.log.warn = (title, msg) => {
- t.equal(title, 'init', 'should have init title')
- t.equal(msg, 'canceled', 'should log canceled')
- }
process.chdir(npm.localPrefix)
await init.exec([])
diff --git a/test/lib/commands/install.js b/test/lib/commands/install.js
index 994684596..d5db3af67 100644
--- a/test/lib/commands/install.js
+++ b/test/lib/commands/install.js
@@ -1,7 +1,10 @@
const t = require('tap')
const path = require('path')
-const { real: mockNpm } = require('../../fixtures/mock-npm')
+const { load: _loadMockNpm } = require('../../fixtures/mock-npm')
+
+// Make less churn in the test to pass in mocks only signature
+const loadMockNpm = (t, mocks) => _loadMockNpm(t, { mocks })
t.test('with args, dev=true', async t => {
const SCRIPTS = []
@@ -9,7 +12,7 @@ t.test('with args, dev=true', async t => {
let REIFY_CALLED = false
let ARB_OBJ = null
- const { Npm, filteredLogs } = mockNpm(t, {
+ const { npm, logs } = await loadMockNpm(t, {
'@npmcli/run-script': ({ event }) => {
SCRIPTS.push(event)
},
@@ -27,8 +30,6 @@ t.test('with args, dev=true', async t => {
},
})
- const npm = new Npm()
- await npm.load()
// This is here because CI calls tests with `--ignore-scripts`, which config
// picks up from argv
npm.config.set('ignore-scripts', false)
@@ -41,8 +42,8 @@ t.test('with args, dev=true', async t => {
await npm.exec('install', ['fizzbuzz'])
t.match(
- filteredLogs('warn'),
- ['Usage of the `--dev` option is deprecated. Use `--include=dev` instead.']
+ logs.warn,
+ [['install', 'Usage of the `--dev` option is deprecated. Use `--include=dev` instead.']]
)
t.match(
ARB_ARGS,
@@ -59,7 +60,7 @@ t.test('without args', async t => {
let REIFY_CALLED = false
let ARB_OBJ = null
- const { Npm } = mockNpm(t, {
+ const { npm } = await loadMockNpm(t, {
'@npmcli/run-script': ({ event }) => {
SCRIPTS.push(event)
},
@@ -77,8 +78,6 @@ t.test('without args', async t => {
},
})
- const npm = new Npm()
- await npm.load()
npm.prefix = path.resolve(t.testdir({}))
npm.config.set('ignore-scripts', false)
await npm.exec('install', [])
@@ -98,7 +97,7 @@ t.test('without args', async t => {
t.test('should ignore scripts with --ignore-scripts', async t => {
const SCRIPTS = []
let REIFY_CALLED = false
- const { Npm } = mockNpm(t, {
+ const { npm } = await loadMockNpm(t, {
'../../lib/utils/reify-finish.js': async () => {},
'@npmcli/run-script': ({ event }) => {
SCRIPTS.push(event)
@@ -109,8 +108,6 @@ t.test('should ignore scripts with --ignore-scripts', async t => {
}
},
})
- const npm = new Npm()
- await npm.load()
npm.config.set('ignore-scripts', true)
npm.prefix = path.resolve(t.testdir({}))
await npm.exec('install', [])
@@ -122,7 +119,7 @@ t.test('should install globally using Arborist', async t => {
const SCRIPTS = []
let ARB_ARGS = null
let REIFY_CALLED
- const { Npm } = mockNpm(t, {
+ const { npm } = await loadMockNpm(t, {
'@npmcli/run-script': ({ event }) => {
SCRIPTS.push(event)
},
@@ -134,8 +131,6 @@ t.test('should install globally using Arborist', async t => {
}
},
})
- const npm = new Npm()
- await npm.load()
npm.config.set('global', true)
npm.globalPrefix = path.resolve(t.testdir({}))
await npm.exec('install', [])
@@ -148,7 +143,7 @@ t.test('should install globally using Arborist', async t => {
})
t.test('npm i -g npm engines check success', async t => {
- const { Npm } = mockNpm(t, {
+ const { npm } = await loadMockNpm(t, {
'../../lib/utils/reify-finish.js': async () => {},
'@npmcli/arborist': function () {
this.reify = () => {}
@@ -164,8 +159,6 @@ t.test('npm i -g npm engines check success', async t => {
},
},
})
- const npm = new Npm()
- await npm.load()
npm.globalDir = t.testdir({})
npm.config.set('global', true)
await npm.exec('install', ['npm'])
@@ -173,7 +166,7 @@ t.test('npm i -g npm engines check success', async t => {
})
t.test('npm i -g npm engines check failure', async t => {
- const { Npm } = mockNpm(t, {
+ const { npm } = await loadMockNpm(t, {
pacote: {
manifest: () => {
return {
@@ -186,8 +179,6 @@ t.test('npm i -g npm engines check failure', async t => {
},
},
})
- const npm = new Npm()
- await npm.load()
npm.globalDir = t.testdir({})
npm.config.set('global', true)
await t.rejects(
@@ -208,7 +199,7 @@ t.test('npm i -g npm engines check failure', async t => {
})
t.test('npm i -g npm engines check failure forced override', async t => {
- const { Npm } = mockNpm(t, {
+ const { npm } = await loadMockNpm(t, {
'../../lib/utils/reify-finish.js': async () => {},
'@npmcli/arborist': function () {
this.reify = () => {}
@@ -225,8 +216,6 @@ t.test('npm i -g npm engines check failure forced override', async t => {
},
},
})
- const npm = new Npm()
- await npm.load()
npm.globalDir = t.testdir({})
npm.config.set('global', true)
npm.config.set('force', true)
@@ -235,7 +224,7 @@ t.test('npm i -g npm engines check failure forced override', async t => {
})
t.test('npm i -g npm@version engines check failure', async t => {
- const { Npm } = mockNpm(t, {
+ const { npm } = await loadMockNpm(t, {
pacote: {
manifest: () => {
return {
@@ -248,8 +237,6 @@ t.test('npm i -g npm@version engines check failure', async t => {
},
},
})
- const npm = new Npm()
- await npm.load()
npm.globalDir = t.testdir({})
npm.config.set('global', true)
await t.rejects(
@@ -283,8 +270,7 @@ t.test('completion', async t => {
})
t.test('completion to folder - has a match', async t => {
- const { Npm } = mockNpm(t)
- const npm = new Npm()
+ const { npm } = await _loadMockNpm(t, { load: false })
const install = await npm.cmd('install')
process.chdir(testdir)
const res = await install.completion({ partialWord: './ar' })
@@ -292,16 +278,14 @@ t.test('completion', async t => {
})
t.test('completion to folder - invalid dir', async t => {
- const { Npm } = mockNpm(t)
- const npm = new Npm()
+ const { npm } = await _loadMockNpm(t, { load: false })
const install = await npm.cmd('install')
const res = await install.completion({ partialWord: '/does/not/exist' })
t.strictSame(res, [], 'invalid dir: no matching')
})
t.test('completion to folder - no matches', async t => {
- const { Npm } = mockNpm(t)
- const npm = new Npm()
+ const { npm } = await _loadMockNpm(t, { load: false })
const install = await npm.cmd('install')
process.chdir(testdir)
const res = await install.completion({ partialWord: './pa' })
@@ -309,8 +293,7 @@ t.test('completion', async t => {
})
t.test('completion to folder - match is not a package', async t => {
- const { Npm } = mockNpm(t)
- const npm = new Npm()
+ const { npm } = await _loadMockNpm(t, { load: false })
const install = await npm.cmd('install')
process.chdir(testdir)
const res = await install.completion({ partialWord: './othe' })
@@ -318,8 +301,7 @@ t.test('completion', async t => {
})
t.test('completion to url', async t => {
- const { Npm } = mockNpm(t)
- const npm = new Npm()
+ const { npm } = await _loadMockNpm(t, { load: false })
const install = await npm.cmd('install')
process.chdir(testdir)
const res = await install.completion({ partialWord: 'http://path/to/url' })
@@ -327,8 +309,7 @@ t.test('completion', async t => {
})
t.test('no /', async t => {
- const { Npm } = mockNpm(t)
- const npm = new Npm()
+ const { npm } = await _loadMockNpm(t, { load: false })
const install = await npm.cmd('install')
process.chdir(testdir)
const res = await install.completion({ partialWord: 'toto' })
@@ -336,8 +317,7 @@ t.test('completion', async t => {
})
t.test('only /', async t => {
- const { Npm } = mockNpm(t)
- const npm = new Npm()
+ const { npm } = await _loadMockNpm(t, { load: false })
const install = await npm.cmd('install')
process.chdir(testdir)
const res = await install.completion({ partialWord: '/' })
diff --git a/test/lib/commands/logout.js b/test/lib/commands/logout.js
index 39ef86c84..ee01e7500 100644
--- a/test/lib/commands/logout.js
+++ b/test/lib/commands/logout.js
@@ -10,45 +10,31 @@ const flatOptions = {
scope: '',
}
const npm = mockNpm({ config, flatOptions })
-
-const npmlog = {}
-
let result = null
-const npmFetch = (url, opts) => {
- result = { url, opts }
-}
-const mocks = {
- npmlog,
- 'npm-registry-fetch': npmFetch,
+const mockLogout = (otherMocks) => {
+ const Logout = t.mock('../../../lib/commands/logout.js', {
+ 'npm-registry-fetch': (url, opts) => {
+ result = { url, opts }
+ },
+ ...otherMocks,
+ })
+ return new Logout(npm)
}
-const Logout = t.mock('../../../lib/commands/logout.js', mocks)
-const logout = new Logout(npm)
+t.afterEach(() => {
+ delete flatOptions.token
+ result = null
+ config.clearCredentialsByURI = null
+ config.delete = null
+ config.save = null
+})
t.test('token logout', async t => {
- 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/'
- npmlog.verbose = (title, msg) => {
- t.equal(title, 'logout', 'should have correcct log prefix')
- t.equal(
- msg,
- 'clearing token for https://registry.npmjs.org/',
- 'should log message with correct registry'
- )
- }
-
npm.config.clearCredentialsByURI = registry => {
t.equal(
registry,
@@ -61,6 +47,19 @@ t.test('token logout', async t => {
t.equal(type, 'user', 'should save to user config')
}
+ const logout = mockLogout({
+ 'proc-log': {
+ verbose: (title, msg) => {
+ t.equal(title, 'logout', 'should have correcct log prefix')
+ t.equal(
+ msg,
+ 'clearing token for https://registry.npmjs.org/',
+ 'should log message with correct registry'
+ )
+ },
+ },
+ })
+
await logout.exec([])
t.same(
@@ -87,12 +86,11 @@ t.test('token scoped logout', async t => {
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/'
@@ -102,15 +100,6 @@ t.test('token scoped logout', async t => {
flatOptions.scope = '@myscope'
flatOptions['@myscope:registry'] = 'https://diff-registry.npmjs.com/'
- npmlog.verbose = (title, msg) => {
- t.equal(title, 'logout', 'should have correcct log prefix')
- t.equal(
- msg,
- 'clearing token for https://diff-registry.npmjs.com/',
- 'should log message with correct registry'
- )
- }
-
npm.config.clearCredentialsByURI = registry => {
t.equal(
registry,
@@ -128,6 +117,19 @@ t.test('token scoped logout', async t => {
t.equal(type, 'user', 'should save to user config')
}
+ const logout = mockLogout({
+ 'proc-log': {
+ verbose: (title, msg) => {
+ t.equal(title, 'logout', 'should have correcct log prefix')
+ t.equal(
+ msg,
+ 'clearing token for https://diff-registry.npmjs.com/',
+ 'should log message with correct registry'
+ )
+ },
+ },
+ })
+
await logout.exec([])
t.same(
@@ -154,29 +156,34 @@ t.test('user/pass logout', async t => {
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'
- npmlog.verbose = (title, msg) => {
- t.equal(title, 'logout', 'should have correct log prefix')
- t.equal(
- msg,
- 'clearing user credentials for https://registry.npmjs.org/',
- 'should log message with correct registry'
- )
- }
-
npm.config.clearCredentialsByURI = () => null
npm.config.save = () => null
+ const logout = mockLogout({
+ 'proc-log': {
+ verbose: (title, msg) => {
+ t.equal(title, 'logout', 'should have correct log prefix')
+ t.equal(
+ msg,
+ 'clearing user credentials for https://registry.npmjs.org/',
+ 'should log message with correct registry'
+ )
+ },
+ },
+ })
+
await logout.exec([])
})
t.test('missing credentials', async t => {
+ const logout = mockLogout()
+
await t.rejects(
logout.exec([]),
{
@@ -191,11 +198,9 @@ t.test('ignore invalid scoped registry config', async t => {
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)
@@ -203,15 +208,6 @@ t.test('ignore invalid scoped registry config', async t => {
config.scope = '@myscope'
flatOptions['@myscope:registry'] = ''
- npmlog.verbose = (title, msg) => {
- t.equal(title, 'logout', 'should have correcct log prefix')
- t.equal(
- msg,
- 'clearing token for https://registry.npmjs.org/',
- 'should log message with correct registry'
- )
- }
-
npm.config.clearCredentialsByURI = registry => {
t.equal(
registry,
@@ -223,6 +219,19 @@ t.test('ignore invalid scoped registry config', async t => {
npm.config.delete = () => null
npm.config.save = () => null
+ const logout = mockLogout({
+ 'proc-log': {
+ verbose: (title, msg) => {
+ t.equal(title, 'logout', 'should have correcct log prefix')
+ t.equal(
+ msg,
+ 'clearing token for https://registry.npmjs.org/',
+ 'should log message with correct registry'
+ )
+ },
+ },
+ })
+
await logout.exec([])
t.same(
diff --git a/test/lib/commands/owner.js b/test/lib/commands/owner.js
index 8645b349f..b5d4d1584 100644
--- a/test/lib/commands/owner.js
+++ b/test/lib/commands/owner.js
@@ -14,11 +14,11 @@ const npm = mockNpm({
})
const npmFetch = { json: noop }
-const npmlog = { error: noop, info: noop, verbose: noop }
+const log = { error: noop, info: noop, verbose: noop }
const pacote = { packument: noop }
const mocks = {
- npmlog,
+ 'proc-log': log,
'npm-registry-fetch': npmFetch,
pacote,
'../../../lib/utils/otplease.js': async (opts, fn) => fn({ otp: '123456', opts }),
@@ -97,7 +97,7 @@ t.test('owner ls no args no cwd package', async t => {
result = ''
t.teardown(() => {
result = ''
- npmlog.error = noop
+ log.error = noop
})
await t.rejects(
@@ -114,14 +114,14 @@ t.test('owner ls fails to retrieve packument', async t => {
pacote.packument = () => {
throw new Error('ERR')
}
- npmlog.error = (title, msg, pkgName) => {
+ log.error = (title, msg, pkgName) => {
t.equal(title, 'owner ls', 'should list npm owner ls title')
t.equal(msg, "Couldn't get owner data", 'should use expected msg')
t.equal(pkgName, '@npmcli/map-workspaces', 'should use pkg name')
}
t.teardown(() => {
result = ''
- npmlog.error = noop
+ log.error = noop
pacote.packument = noop
})
@@ -276,7 +276,7 @@ t.test('owner add <user> <pkg> already an owner', async t => {
t.plan(2)
result = ''
- npmlog.info = (title, msg) => {
+ log.info = (title, msg) => {
t.equal(title, 'owner add', 'should use expected title')
t.equal(
msg,
@@ -304,7 +304,7 @@ t.test('owner add <user> <pkg> already an owner', async t => {
}
t.teardown(() => {
result = ''
- npmlog.info = noop
+ log.info = noop
npmFetch.json = noop
pacote.packument = noop
})
@@ -385,7 +385,7 @@ t.test('owner add <user> <pkg> fails to retrieve user info', async t => {
t.plan(3)
result = ''
- npmlog.error = (title, msg) => {
+ log.error = (title, msg) => {
t.equal(title, 'owner mutate', 'should use expected title')
t.equal(msg, 'Error getting user data for foo')
}
@@ -406,7 +406,7 @@ t.test('owner add <user> <pkg> fails to retrieve user info', async t => {
})
t.teardown(() => {
result = ''
- npmlog.error = noop
+ log.error = noop
npmFetch.json = noop
pacote.packument = noop
})
@@ -552,7 +552,7 @@ t.test('owner rm <user> <pkg> not a current owner', async t => {
t.plan(2)
result = ''
- npmlog.info = (title, msg) => {
+ log.info = (title, msg) => {
t.equal(title, 'owner rm', 'should log expected title')
t.equal(msg, 'Not a package owner: foo', 'should log.info not a package owner msg')
}
@@ -578,7 +578,7 @@ t.test('owner rm <user> <pkg> not a current owner', async t => {
}
t.teardown(() => {
result = ''
- npmlog.info = noop
+ log.info = noop
npmFetch.json = noop
pacote.packument = noop
})
diff --git a/test/lib/commands/pack.js b/test/lib/commands/pack.js
index bc8877208..21057e207 100644
--- a/test/lib/commands/pack.js
+++ b/test/lib/commands/pack.js
@@ -1,5 +1,5 @@
const t = require('tap')
-const { real: mockNpm } = require('../../fixtures/mock-npm')
+const { load: loadMockNpm } = require('../../fixtures/mock-npm')
const path = require('path')
const fs = require('fs')
@@ -9,33 +9,31 @@ t.afterEach(t => {
})
t.test('should pack current directory with no arguments', async t => {
- const { Npm, outputs, filteredLogs } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.prefix = t.testdir({
- 'package.json': JSON.stringify({
- name: 'test-package',
- version: '1.0.0',
- }),
+ const { npm, outputs, logs } = await loadMockNpm(t, {
+ testdir: {
+ 'package.json': JSON.stringify({
+ name: 'test-package',
+ version: '1.0.0',
+ }),
+ },
})
process.chdir(npm.prefix)
await npm.exec('pack', [])
const filename = 'test-package-1.0.0.tgz'
t.strictSame(outputs, [[filename]])
- t.matchSnapshot(filteredLogs('notice'), 'logs pack contents')
+ t.matchSnapshot(logs.notice.map(([, m]) => m), 'logs pack contents')
t.ok(fs.statSync(path.resolve(npm.prefix, filename)))
})
t.test('follows pack-destination config', async t => {
- const { Npm, outputs } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.prefix = t.testdir({
- 'package.json': JSON.stringify({
- name: 'test-package',
- version: '1.0.0',
- }),
- 'tar-destination': {},
+ const { npm, outputs } = await loadMockNpm(t, {
+ testdir: {
+ 'package.json': JSON.stringify({
+ name: 'test-package',
+ version: '1.0.0',
+ }),
+ 'tar-destination': {},
+ },
})
process.chdir(npm.prefix)
npm.config.set('pack-destination', path.join(npm.prefix, 'tar-destination'))
@@ -46,14 +44,13 @@ t.test('follows pack-destination config', async t => {
})
t.test('should pack given directory for scoped package', async t => {
- const { Npm, outputs } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.prefix = t.testdir({
- 'package.json': JSON.stringify({
- name: '@npm/test-package',
- version: '1.0.0',
- }),
+ const { npm, outputs } = await loadMockNpm(t, {
+ testdir: {
+ 'package.json': JSON.stringify({
+ name: '@npm/test-package',
+ version: '1.0.0',
+ }),
+ },
})
process.chdir(npm.prefix)
await npm.exec('pack', [])
@@ -63,49 +60,46 @@ t.test('should pack given directory for scoped package', async t => {
})
t.test('should log output as valid json', async t => {
- const { Npm, outputs, filteredLogs } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.prefix = t.testdir({
- 'package.json': JSON.stringify({
- name: 'test-package',
- version: '1.0.0',
- }),
+ const { npm, outputs, logs } = await loadMockNpm(t, {
+ testdir: {
+ 'package.json': JSON.stringify({
+ name: 'test-package',
+ version: '1.0.0',
+ }),
+ },
})
process.chdir(npm.prefix)
npm.config.set('json', true)
await npm.exec('pack', [])
const filename = 'test-package-1.0.0.tgz'
t.matchSnapshot(outputs.map(JSON.parse), 'outputs as json')
- t.matchSnapshot(filteredLogs('notice'), 'logs pack contents')
+ t.matchSnapshot(logs.notice.map(([, m]) => m), 'logs pack contents')
t.ok(fs.statSync(path.resolve(npm.prefix, filename)))
})
t.test('dry run', async t => {
- const { Npm, outputs, filteredLogs } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.prefix = t.testdir({
- 'package.json': JSON.stringify({
- name: 'test-package',
- version: '1.0.0',
- }),
+ const { npm, outputs, logs } = await loadMockNpm(t, {
+ testdir: {
+ 'package.json': JSON.stringify({
+ name: 'test-package',
+ version: '1.0.0',
+ }),
+ },
})
npm.config.set('dry-run', true)
process.chdir(npm.prefix)
await npm.exec('pack', [])
const filename = 'test-package-1.0.0.tgz'
t.strictSame(outputs, [[filename]])
- t.matchSnapshot(filteredLogs('notice'), 'logs pack contents')
+ t.matchSnapshot(logs.notice.map(([, m]) => m), 'logs pack contents')
t.throws(() => fs.statSync(path.resolve(npm.prefix, filename)))
})
t.test('invalid packument', async t => {
- const { Npm, outputs } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.prefix = t.testdir({
- 'package.json': '{}',
+ const { npm, outputs } = await loadMockNpm(t, {
+ testdir: {
+ 'package.json': '{}',
+ },
})
process.chdir(npm.prefix)
await t.rejects(
@@ -116,52 +110,58 @@ t.test('invalid packument', async t => {
})
t.test('workspaces', async t => {
- const { Npm, outputs } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.prefix = t.testdir({
- 'package.json': JSON.stringify(
- {
- name: 'workspaces-test',
- version: '1.0.0',
- workspaces: ['workspace-a', 'workspace-b'],
+ const loadWorkspaces = (t) => loadMockNpm(t, {
+ testdir: {
+ 'package.json': JSON.stringify(
+ {
+ name: 'workspaces-test',
+ version: '1.0.0',
+ workspaces: ['workspace-a', 'workspace-b'],
+ },
+ null,
+ 2
+ ),
+ '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',
+ }),
},
- null,
- 2
- ),
- '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',
- }),
+ config: {
+ workspaces: true,
},
})
- npm.config.set('workspaces', true)
+
t.test('all workspaces', async t => {
+ const { npm, outputs } = await loadWorkspaces(t)
process.chdir(npm.prefix)
await npm.exec('pack', [])
t.strictSame(outputs, [['workspace-a-1.0.0.tgz'], ['workspace-b-1.0.0.tgz']])
})
t.test('all workspaces, `.` first arg', async t => {
+ const { npm, outputs } = await loadWorkspaces(t)
process.chdir(npm.prefix)
await npm.exec('pack', ['.'])
t.strictSame(outputs, [['workspace-a-1.0.0.tgz'], ['workspace-b-1.0.0.tgz']])
})
t.test('one workspace', async t => {
+ const { npm, outputs } = await loadWorkspaces(t)
process.chdir(npm.prefix)
await npm.exec('pack', ['workspace-a'])
t.strictSame(outputs, [['workspace-a-1.0.0.tgz']])
})
t.test('specific package', async t => {
+ const { npm, outputs } = await loadWorkspaces(t)
process.chdir(npm.prefix)
await npm.exec('pack', [npm.prefix])
t.strictSame(outputs, [['workspaces-test-1.0.0.tgz']])
diff --git a/test/lib/commands/ping.js b/test/lib/commands/ping.js
index 7011c709b..f808e0ac3 100644
--- a/test/lib/commands/ping.js
+++ b/test/lib/commands/ping.js
@@ -11,7 +11,7 @@ t.test('pings', async t => {
t.equal(spec.registry, registry, 'passes flatOptions')
return {}
},
- npmlog: {
+ 'proc-log': {
notice: (type, spec) => {
++noticeCalls
if (noticeCalls === 1) {
@@ -45,7 +45,7 @@ t.test('pings and logs details', async t => {
t.equal(spec.registry, registry, 'passes flatOptions')
return details
},
- npmlog: {
+ 'proc-log': {
notice: (type, spec) => {
++noticeCalls
if (noticeCalls === 1) {
@@ -83,7 +83,7 @@ t.test('pings and returns json', async t => {
t.equal(spec.registry, registry, 'passes flatOptions')
return details
},
- npmlog: {
+ 'proc-log': {
notice: (type, spec) => {
++noticeCalls
if (noticeCalls === 1) {
diff --git a/test/lib/commands/prefix.js b/test/lib/commands/prefix.js
index 6f059e73a..e8295cf6a 100644
--- a/test/lib/commands/prefix.js
+++ b/test/lib/commands/prefix.js
@@ -1,9 +1,8 @@
const t = require('tap')
-const { real: mockNpm } = require('../../fixtures/mock-npm')
+const { load: loadMockNpm } = require('../../fixtures/mock-npm')
t.test('prefix', async t => {
- const { joinedOutput, Npm } = mockNpm(t)
- const npm = new Npm()
+ const { joinedOutput, npm } = await loadMockNpm(t, { load: false })
await npm.exec('prefix', [])
t.equal(
joinedOutput(),
diff --git a/test/lib/commands/profile.js b/test/lib/commands/profile.js
index 6554ca89e..0f16c1db1 100644
--- a/test/lib/commands/profile.js
+++ b/test/lib/commands/profile.js
@@ -22,6 +22,8 @@ const mocks = {
ansistyles: { bright: a => a },
npmlog: {
gauge: { show () {} },
+ },
+ 'proc-log': {
info () {},
notice () {},
warn () {},
@@ -489,23 +491,23 @@ t.test('profile set <key> <value>', t => {
},
}
- const npmlog = {
- gauge: {
- show () {},
- },
- warn (title, msg) {
- t.equal(title, 'profile', 'should use expected profile')
- t.equal(
- msg,
- 'Passwords do not match, please try again.',
- 'should log password mismatch message'
- )
- },
- }
-
const Profile = t.mock('../../../lib/commands/profile.js', {
...mocks,
- npmlog,
+ npmlog: {
+ gauge: {
+ show () {},
+ },
+ },
+ 'proc-log': {
+ warn (title, msg) {
+ t.equal(title, 'profile', 'should use expected profile')
+ t.equal(
+ msg,
+ 'Passwords do not match, please try again.',
+ 'should log password mismatch message'
+ )
+ },
+ },
'npm-profile': npmProfile,
'../../../lib/utils/read-user-info.js': readUserInfo,
})
diff --git a/test/lib/commands/prune.js b/test/lib/commands/prune.js
index 49d5ab9be..a7f56547b 100644
--- a/test/lib/commands/prune.js
+++ b/test/lib/commands/prune.js
@@ -1,20 +1,22 @@
const t = require('tap')
-const { real: mockNpm } = require('../../fixtures/mock-npm')
+const { load: loadMockNpm } = require('../../fixtures/mock-npm')
t.test('should prune using Arborist', async (t) => {
t.plan(4)
- const { Npm } = mockNpm(t, {
- '@npmcli/arborist': function (args) {
- t.ok(args, 'gets options object')
- t.ok(args.path, 'gets path option')
- this.prune = () => {
- t.ok(true, 'prune is called')
- }
- },
- '../../lib/utils/reify-finish.js': (arb) => {
- t.ok(arb, 'gets arborist tree')
+ const { npm } = await loadMockNpm(t, {
+ load: false,
+ mocks: {
+ '@npmcli/arborist': function (args) {
+ t.ok(args, 'gets options object')
+ t.ok(args.path, 'gets path option')
+ this.prune = () => {
+ t.ok(true, 'prune is called')
+ }
+ },
+ '../../lib/utils/reify-finish.js': (arb) => {
+ t.ok(arb, 'gets arborist tree')
+ },
},
})
- const npm = new Npm()
await npm.exec('prune', [])
})
diff --git a/test/lib/commands/publish.js b/test/lib/commands/publish.js
index 5f4fb4010..1178cd6ee 100644
--- a/test/lib/commands/publish.js
+++ b/test/lib/commands/publish.js
@@ -1,13 +1,15 @@
const t = require('tap')
const { fake: mockNpm } = require('../../fixtures/mock-npm')
const fs = require('fs')
+const log = require('../../../lib/utils/log-shim')
// The way we set loglevel is kind of convoluted, and there is no way to affect
// it from these tests, which only interact with lib/publish.js, which assumes
// that the code that is requiring and calling lib/publish.js has already
// taken care of the loglevel
-const log = require('npmlog')
-log.level = 'silent'
+const _level = log.level
+t.beforeEach(() => (log.level = 'silent'))
+t.teardown(() => (log.level = _level))
t.cleanSnapshot = data => {
return data.replace(/^ *"gitHead": .*$\n/gm, '')
@@ -19,8 +21,6 @@ const defaults = Object.entries(definitions).reduce((defaults, [key, def]) => {
return defaults
}, {})
-t.afterEach(() => (log.level = 'silent'))
-
t.test(
/* eslint-disable-next-line max-len */
'should publish with libnpmpublish, passing through flatOptions and respecting publishConfig.registry',
@@ -147,7 +147,7 @@ t.test('if loglevel=info and json, should not output package contents', async t
id: 'someid',
}),
logTar: () => {
- t.pass('logTar is called')
+ t.fail('logTar is not called in json mode')
},
},
libnpmpublish: {
@@ -188,7 +188,6 @@ t.test(
),
})
- log.level = 'silent'
const Publish = t.mock('../../../lib/commands/publish.js', {
'../../../lib/utils/tar.js': {
getContents: () => ({
@@ -681,9 +680,12 @@ t.test('private workspaces', async t => {
}
t.test('with color', async t => {
+ t.plan(4)
+
+ log.level = 'info'
const Publish = t.mock('../../../lib/commands/publish.js', {
...mocks,
- npmlog: {
+ 'proc-log': {
notice () {},
verbose () {},
warn (title, msg) {
@@ -707,9 +709,12 @@ t.test('private workspaces', async t => {
})
t.test('colorless', async t => {
+ t.plan(4)
+
+ log.level = 'info'
const Publish = t.mock('../../../lib/commands/publish.js', {
...mocks,
- npmlog: {
+ 'proc-log': {
notice () {},
verbose () {},
warn (title, msg) {
@@ -730,6 +735,8 @@ t.test('private workspaces', async t => {
})
t.test('unexpected error', async t => {
+ t.plan(1)
+
const Publish = t.mock('../../../lib/commands/publish.js', {
...mocks,
libnpmpublish: {
@@ -741,7 +748,7 @@ t.test('private workspaces', async t => {
publishes.push(manifest)
},
},
- npmlog: {
+ 'proc-log': {
notice () {},
verbose () {},
},
@@ -755,6 +762,8 @@ t.test('private workspaces', async t => {
})
t.test('runs correct lifecycle scripts', async t => {
+ t.plan(5)
+
const testDir = t.testdir({
'package.json': JSON.stringify(
{
@@ -773,6 +782,7 @@ t.test('runs correct lifecycle scripts', async t => {
})
const scripts = []
+ log.level = 'info'
const Publish = t.mock('../../../lib/commands/publish.js', {
'@npmcli/run-script': args => {
scripts.push(args)
@@ -810,6 +820,8 @@ t.test('runs correct lifecycle scripts', async t => {
})
t.test('does not run scripts on --ignore-scripts', async t => {
+ t.plan(4)
+
const testDir = t.testdir({
'package.json': JSON.stringify(
{
@@ -821,6 +833,7 @@ t.test('does not run scripts on --ignore-scripts', async t => {
),
})
+ log.level = 'info'
const Publish = t.mock('../../../lib/commands/publish.js', {
'@npmcli/run-script': () => {
t.fail('should not call run-script')
diff --git a/test/lib/commands/repo.js b/test/lib/commands/repo.js
index 4e61047b4..93eb6d031 100644
--- a/test/lib/commands/repo.js
+++ b/test/lib/commands/repo.js
@@ -1,8 +1,8 @@
const t = require('tap')
-const { real: mockNpm } = require('../../fixtures/mock-npm.js')
-const { join, sep } = require('path')
+const { load: _loadMockNpm } = require('../../fixtures/mock-npm.js')
+const { sep } = require('path')
-const pkgDirs = t.testdir({
+const fixture = {
'package.json': JSON.stringify({
name: 'thispkg',
version: '1.2.3',
@@ -149,35 +149,36 @@ const pkgDirs = t.testdir({
},
}),
},
- workspaces: {
+}
+
+const workspaceFixture = {
+ 'package.json': JSON.stringify({
+ name: 'workspaces-test',
+ version: '1.2.3-test',
+ workspaces: ['workspace-a', 'workspace-b', 'workspace-c'],
+ repository: 'https://github.com/npm/workspaces-test',
+ }),
+ 'workspace-a': {
'package.json': JSON.stringify({
- name: 'workspaces-test',
- version: '1.2.3-test',
- workspaces: ['workspace-a', 'workspace-b', 'workspace-c'],
- repository: 'https://github.com/npm/workspaces-test',
+ name: 'workspace-a',
+ version: '1.2.3-a',
+ repository: 'http://repo.workspace-a/',
}),
- 'workspace-a': {
- 'package.json': JSON.stringify({
- name: 'workspace-a',
- version: '1.2.3-a',
- repository: 'http://repo.workspace-a/',
- }),
- },
- 'workspace-b': {
- 'package.json': JSON.stringify({
- name: 'workspace-b',
- version: '1.2.3-n',
- repository: 'https://github.com/npm/workspace-b',
- }),
- },
- 'workspace-c': JSON.stringify({
- 'package.json': {
- name: 'workspace-n',
- version: '1.2.3-n',
- },
+ },
+ 'workspace-b': {
+ 'package.json': JSON.stringify({
+ name: 'workspace-b',
+ version: '1.2.3-n',
+ repository: 'https://github.com/npm/workspace-b',
}),
},
-})
+ 'workspace-c': JSON.stringify({
+ 'package.json': {
+ name: 'workspace-n',
+ version: '1.2.3-n',
+ },
+ }),
+}
// keep a tally of which urls got opened
let opened = {}
@@ -185,20 +186,18 @@ const openUrl = async (npm, url, errMsg) => {
opened[url] = opened[url] || 0
opened[url]++
}
-
-const { Npm } = mockNpm(t, {
- '../../lib/utils/open-url.js': openUrl,
-})
-const npm = new Npm()
-
-t.before(async () => {
- await npm.load()
-})
-
t.afterEach(() => opened = {})
-t.test('open repo urls', t => {
- npm.localPrefix = pkgDirs
+const loadMockNpm = async (t, prefix) => {
+ const res = await _loadMockNpm(t, {
+ mocks: { '../../lib/utils/open-url.js': openUrl },
+ testdir: prefix,
+ })
+ return res
+}
+
+t.test('open repo urls', async t => {
+ const { npm } = await loadMockNpm(t, fixture)
const expect = {
hostedgit: 'https://github.com/foo/hostedgit',
hostedgitat: 'https://github.com/foo/hostedgitat',
@@ -239,8 +238,9 @@ t.test('open repo urls', t => {
})
})
-t.test('fail if cannot figure out repo url', t => {
- npm.localPrefix = pkgDirs
+t.test('fail if cannot figure out repo url', async t => {
+ const { npm } = await loadMockNpm(t, fixture)
+
const cases = [
'norepo',
'repoobbj-nourl',
@@ -261,13 +261,13 @@ t.test('fail if cannot figure out repo url', t => {
})
t.test('open default package if none specified', async t => {
- npm.localPrefix = pkgDirs
+ const { npm } = await loadMockNpm(t, fixture)
await npm.exec('repo', [])
t.equal(opened['https://example.com/thispkg'], 1, 'opened expected url', { opened })
})
-t.test('workspaces', t => {
- npm.localPrefix = join(pkgDirs, 'workspaces')
+t.test('workspaces', async t => {
+ const { npm } = await loadMockNpm(t, workspaceFixture)
t.afterEach(() => {
npm.config.set('workspaces', null)
@@ -311,5 +311,4 @@ t.test('workspaces', t => {
)
t.match({}, opened, 'opened no repo urls')
})
- t.end()
})
diff --git a/test/lib/commands/restart.js b/test/lib/commands/restart.js
index 608de0331..7730f1a30 100644
--- a/test/lib/commands/restart.js
+++ b/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 { load: loadMockNpm } = require('../../fixtures/mock-npm')
spawk.preventUnmatched()
t.teardown(() => {
@@ -12,24 +12,24 @@ t.teardown(() => {
// pretty specific internals of runScript
const makeSpawnArgs = require('@npmcli/run-script/lib/make-spawn-args.js')
-t.test('should run stop script from package.json', async t => {
- const prefix = t.testdir({
- 'package.json': JSON.stringify({
- name: 'x',
- version: '1.2.3',
- scripts: {
- restart: 'node ./test-restart.js',
- },
- }),
+t.test('should run restart script from package.json', async t => {
+ const { npm } = await loadMockNpm(t, {
+ testdir: {
+ 'package.json': JSON.stringify({
+ name: 'x',
+ version: '1.2.3',
+ scripts: {
+ restart: 'node ./test-restart.js',
+ },
+ }),
+ },
+ config: {
+ loglevel: 'silent',
+ },
})
- const { Npm } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.log.level = 'silent'
- npm.localPrefix = prefix
- const [scriptShell] = makeSpawnArgs({ path: prefix })
+ const [scriptShell] = makeSpawnArgs({ path: npm.prefix })
const script = spawk.spawn(scriptShell, (args) => {
- t.ok(args.includes('node ./test-restart.js "foo"'), 'ran stop script with extra args')
+ t.ok(args.includes('node ./test-restart.js "foo"'), 'ran restart script with extra args')
return true
})
await npm.exec('restart', ['foo'])
diff --git a/test/lib/commands/root.js b/test/lib/commands/root.js
index 9871ddb25..a886b30c3 100644
--- a/test/lib/commands/root.js
+++ b/test/lib/commands/root.js
@@ -1,9 +1,8 @@
const t = require('tap')
-const { real: mockNpm } = require('../../fixtures/mock-npm')
+const { load: loadMockNpm } = require('../../fixtures/mock-npm')
t.test('prefix', async (t) => {
- const { joinedOutput, Npm } = mockNpm(t)
- const npm = new Npm()
+ const { joinedOutput, npm } = await loadMockNpm(t, { load: false })
await npm.exec('root', [])
t.equal(
joinedOutput(),
diff --git a/test/lib/commands/run-script.js b/test/lib/commands/run-script.js
index e421c655e..ea0227cda 100644
--- a/test/lib/commands/run-script.js
+++ b/test/lib/commands/run-script.js
@@ -31,13 +31,16 @@ const output = []
const npmlog = {
disableProgress: () => null,
level: 'warn',
+}
+
+const log = {
error: () => null,
}
t.afterEach(() => {
npm.color = false
npmlog.level = 'warn'
- npmlog.error = () => null
+ log.error = () => null
output.length = 0
RUN_SCRIPTS.length = 0
config['if-present'] = false
@@ -56,6 +59,7 @@ const getRS = windows => {
}
),
npmlog,
+ 'proc-log': log,
'../../../lib/utils/is-windows-shell.js': windows,
})
return new RunScript(npm)
@@ -758,7 +762,7 @@ t.test('workspaces', t => {
t.test('missing scripts in all workspaces', async t => {
const LOG = []
- npmlog.error = err => {
+ log.error = err => {
LOG.push(String(err))
}
await t.rejects(
@@ -805,7 +809,7 @@ t.test('workspaces', t => {
t.test('missing scripts in some workspaces', async t => {
const LOG = []
- npmlog.error = err => {
+ log.error = err => {
LOG.push(String(err))
}
await runScript.execWorkspaces(['test'], ['a', 'b', 'c', 'd'])
@@ -857,6 +861,7 @@ t.test('workspaces', t => {
throw new Error('err')
},
npmlog,
+ 'proc-log': log,
'../../../lib/utils/is-windows-shell.js': false,
})
const runScript = new RunScript(npm)
@@ -875,6 +880,7 @@ t.test('workspaces', t => {
RUN_SCRIPTS.push(opts)
},
npmlog,
+ 'proc-log': log,
'../../../lib/utils/is-windows-shell.js': false,
})
const runScript = new RunScript(npm)
diff --git a/test/lib/commands/set-script.js b/test/lib/commands/set-script.js
index 592a2431c..2c4fe57d6 100644
--- a/test/lib/commands/set-script.js
+++ b/test/lib/commands/set-script.js
@@ -10,7 +10,7 @@ const npm = mockNpm(flatOptions)
const ERROR_OUTPUT = []
const WARN_OUTPUT = []
const SetScript = t.mock('../../../lib/commands/set-script.js', {
- npmlog: {
+ 'proc-log': {
error: (...args) => {
ERROR_OUTPUT.push(args)
},
diff --git a/test/lib/commands/set.js b/test/lib/commands/set.js
index a57ea1a54..feeb90157 100644
--- a/test/lib/commands/set.js
+++ b/test/lib/commands/set.js
@@ -2,6 +2,7 @@ const t = require('tap')
// can't run this until npm set can save to project level npmrc
t.skip('npm set', async t => {
+ // XXX: convert to loadMockNpm
const { real: mockNpm } = require('../../fixtures/mock-npm')
const { joinedOutput, Npm } = mockNpm(t)
const npm = new Npm()
diff --git a/test/lib/commands/shrinkwrap.js b/test/lib/commands/shrinkwrap.js
index db4021abd..2b9e46c70 100644
--- a/test/lib/commands/shrinkwrap.js
+++ b/test/lib/commands/shrinkwrap.js
@@ -1,7 +1,7 @@
const t = require('tap')
const fs = require('fs')
const { resolve } = require('path')
-const { real: mockNpm } = require('../../fixtures/mock-npm')
+const { load: loadMockNpm } = require('../../fixtures/mock-npm')
// Attempt to parse json values in snapshots before
// stringifying to remove escaped values like \\"
@@ -13,7 +13,7 @@ t.formatSnapshot = obj =>
(k, v) => {
try {
return JSON.parse(v)
- } catch (_) {}
+ } catch {}
return v
},
2
@@ -23,33 +23,25 @@ t.formatSnapshot = obj =>
// 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, filteredLogs } = 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)
- }
+ const { npm, logs } = await loadMockNpm(t, {
+ mocks,
+ config,
+ testdir,
+ })
await npm.exec('shrinkwrap', [])
- const newFile = resolve(npm.localPrefix, 'npm-shrinkwrap.json')
- const oldFile = resolve(npm.localPrefix, 'package-lock.json')
- const notices = filteredLogs('notice')
- const warnings = filteredLogs('warn')
+ const newFile = resolve(npm.prefix, 'npm-shrinkwrap.json')
+ const oldFile = resolve(npm.prefix, 'package-lock.json')
t.notOk(fs.existsSync(oldFile), 'package-lock is always deleted')
- t.same(warnings, [], 'no warnings')
+ t.same(logs.warn, [], 'no warnings')
t.teardown(() => delete t.context)
t.context = {
localPrefix: testdir,
config,
shrinkwrap: JSON.parse(fs.readFileSync(newFile)),
- logs: notices,
+ logs: logs.notice.map(([, m]) => m),
}
}
@@ -58,8 +50,8 @@ const shrinkwrap = async (t, testdir = {}, config = {}, mocks = {}) => {
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 }
+ const upgrade = { 'lockfile-version': 3 }
+ const downgrade = { 'lockfile-version': 1 }
let ancientDir = {}
let existingDir = null
diff --git a/test/lib/commands/star.js b/test/lib/commands/star.js
index 13838bb10..9a4903642 100644
--- a/test/lib/commands/star.js
+++ b/test/lib/commands/star.js
@@ -15,9 +15,9 @@ const npm = mockNpm({
},
})
const npmFetch = { json: noop }
-const npmlog = { error: noop, info: noop, verbose: noop }
+const log = { error: noop, info: noop, verbose: noop }
const mocks = {
- npmlog,
+ 'proc-log': log,
'npm-registry-fetch': npmFetch,
'../../../lib/utils/get-identity.js': async () => 'foo',
'../../../lib/utils/usage.js': () => 'usage instructions',
@@ -29,7 +29,7 @@ const star = new Star(npm)
t.afterEach(() => {
config.unicode = false
config['star.unstar'] = false
- npmlog.info = noop
+ log.info = noop
result = ''
})
@@ -53,7 +53,7 @@ t.test('star a package', async t => {
: {}
),
})
- npmlog.info = (title, msg, id) => {
+ log.info = (title, msg, id) => {
t.equal(title, 'star', 'should use expected title')
t.equal(msg, 'starring', 'should use expected msg')
t.equal(id, pkgName, 'should use expected id')
@@ -78,7 +78,7 @@ t.test('unstar a package', async t => {
: { foo: true }
),
})
- npmlog.info = (title, msg, id) => {
+ log.info = (title, msg, id) => {
t.equal(title, 'unstar', 'should use expected title')
t.equal(msg, 'unstarring', 'should use expected msg')
t.equal(id, pkgName, 'should use expected id')
diff --git a/test/lib/commands/stars.js b/test/lib/commands/stars.js
index 4ed643858..959739653 100644
--- a/test/lib/commands/stars.js
+++ b/test/lib/commands/stars.js
@@ -11,9 +11,9 @@ const npm = {
},
}
const npmFetch = { json: noop }
-const npmlog = { warn: noop }
+const log = { warn: noop }
const mocks = {
- npmlog,
+ 'proc-log': log,
'npm-registry-fetch': npmFetch,
'../../../lib/utils/get-identity.js': async () => 'foo',
'../../../lib/utils/usage.js': () => 'usage instructions',
@@ -24,7 +24,7 @@ const stars = new Stars(npm)
t.afterEach(() => {
npm.config = { get () {} }
- npmlog.warn = noop
+ log.warn = noop
result = ''
})
@@ -81,7 +81,7 @@ t.test('unauthorized request', async t => {
)
}
- npmlog.warn = (title, msg) => {
+ log.warn = (title, msg) => {
t.equal(title, 'stars', 'should use expected title')
t.equal(
msg,
@@ -108,7 +108,7 @@ t.test('unexpected error', async t => {
throw new Error('ERROR')
}
- npmlog.warn = (title, msg) => {
+ log.warn = (title, msg) => {
throw new Error('Should not output extra warning msgs')
}
@@ -123,7 +123,7 @@ t.test('no pkg starred', async t => {
t.plan(2)
npmFetch.json = async (uri, opts) => ({ rows: [] })
- npmlog.warn = (title, msg) => {
+ log.warn = (title, msg) => {
t.equal(title, 'stars', 'should use expected title')
t.equal(
msg,
diff --git a/test/lib/commands/start.js b/test/lib/commands/start.js
index 1f26f38ea..4f7dc366d 100644
--- a/test/lib/commands/start.js
+++ b/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 { load: loadMockNpm } = require('../../fixtures/mock-npm')
spawk.preventUnmatched()
t.teardown(() => {
@@ -12,22 +12,23 @@ t.teardown(() => {
// pretty specific internals of runScript
const makeSpawnArgs = require('@npmcli/run-script/lib/make-spawn-args.js')
-t.test('should run stop script from package.json', async t => {
- const prefix = t.testdir({
- 'package.json': JSON.stringify({
- name: 'x',
- version: '1.2.3',
- scripts: {
- start: 'node ./test-start.js',
- },
- }),
+t.test('should run start script from package.json', async t => {
+ t.plan(2)
+ const { npm } = await loadMockNpm(t, {
+ testdir: {
+ 'package.json': JSON.stringify({
+ name: 'x',
+ version: '1.2.3',
+ scripts: {
+ start: 'node ./test-start.js',
+ },
+ }),
+ },
+ config: {
+ loglevel: 'silent',
+ },
})
- const { Npm } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.log.level = 'silent'
- npm.localPrefix = prefix
- const [scriptShell] = makeSpawnArgs({ path: prefix })
+ const [scriptShell] = makeSpawnArgs({ path: npm.prefix })
const script = spawk.spawn(scriptShell, (args) => {
t.ok(args.includes('node ./test-start.js "foo"'), 'ran start script with extra args')
return true
diff --git a/test/lib/commands/stop.js b/test/lib/commands/stop.js
index 4f189449b..53d057b71 100644
--- a/test/lib/commands/stop.js
+++ b/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 { load: loadMockNpm } = require('../../fixtures/mock-npm')
spawk.preventUnmatched()
t.teardown(() => {
@@ -13,21 +13,21 @@ t.teardown(() => {
const makeSpawnArgs = require('@npmcli/run-script/lib/make-spawn-args.js')
t.test('should run stop script from package.json', async t => {
- const prefix = t.testdir({
- 'package.json': JSON.stringify({
- name: 'x',
- version: '1.2.3',
- scripts: {
- stop: 'node ./test-stop.js',
- },
- }),
+ const { npm } = await loadMockNpm(t, {
+ testdir: {
+ 'package.json': JSON.stringify({
+ name: 'x',
+ version: '1.2.3',
+ scripts: {
+ stop: 'node ./test-stop.js',
+ },
+ }),
+ },
+ config: {
+ loglevel: 'silent',
+ },
})
- const { Npm } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.log.level = 'silent'
- npm.localPrefix = prefix
- const [scriptShell] = makeSpawnArgs({ path: prefix })
+ const [scriptShell] = makeSpawnArgs({ path: npm.prefix })
const script = spawk.spawn(scriptShell, (args) => {
t.ok(args.includes('node ./test-stop.js "foo"'), 'ran stop script with extra args')
return true
diff --git a/test/lib/commands/test.js b/test/lib/commands/test.js
index 4e5ce289b..a3dbd3ff4 100644
--- a/test/lib/commands/test.js
+++ b/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 { load: loadMockNpm } = require('../../fixtures/mock-npm')
spawk.preventUnmatched()
t.teardown(() => {
@@ -12,22 +12,22 @@ t.teardown(() => {
// pretty specific internals of runScript
const makeSpawnArgs = require('@npmcli/run-script/lib/make-spawn-args.js')
-t.test('should run stop script from package.json', async t => {
- const prefix = t.testdir({
- 'package.json': JSON.stringify({
- name: 'x',
- version: '1.2.3',
- scripts: {
- test: 'node ./test-test.js',
- },
- }),
+t.test('should run test script from package.json', async t => {
+ const { npm } = await loadMockNpm(t, {
+ testdir: {
+ 'package.json': JSON.stringify({
+ name: 'x',
+ version: '1.2.3',
+ scripts: {
+ test: 'node ./test-test.js',
+ },
+ }),
+ },
+ config: {
+ loglevel: 'silent',
+ },
})
- const { Npm } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.log.level = 'silent'
- npm.localPrefix = prefix
- const [scriptShell] = makeSpawnArgs({ path: prefix })
+ const [scriptShell] = makeSpawnArgs({ path: npm.prefix })
const script = spawk.spawn(scriptShell, (args) => {
t.ok(args.includes('node ./test-test.js "foo"'), 'ran test script with extra args')
return true
diff --git a/test/lib/commands/token.js b/test/lib/commands/token.js
index 6d0dc9d7e..65a094a0b 100644
--- a/test/lib/commands/token.js
+++ b/test/lib/commands/token.js
@@ -3,25 +3,24 @@ const t = require('tap')
const mocks = {
profile: {},
output: () => {},
- log: {},
readUserInfo: {},
}
const npm = {
output: (...args) => mocks.output(...args),
}
-const Token = t.mock('../../../lib/commands/token.js', {
+const mockToken = (otherMocks) => 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,
'npm-profile': mocks.profile,
- npmlog: mocks.log,
+ ...otherMocks,
})
-const token = new Token(npm)
+const tokenWithMocks = (options = {}) => {
+ const { log, ...mockRequests } = options
-const tokenWithMocks = mockRequests => {
for (const mod in mockRequests) {
if (mod === 'npm') {
mockRequests.npm = { ...npm, ...mockRequests.npm }
@@ -50,13 +49,24 @@ const tokenWithMocks = mockRequests => {
}
}
- const token = new Token(mockRequests.npm || npm)
+ const MockedToken = mockToken(log ? {
+ 'proc-log': {
+ info: log.info,
+ },
+ npmlog: {
+ gauge: log.gauge,
+ newItem: log.newItem,
+ },
+ } : {})
+ const token = new MockedToken(mockRequests.npm || npm)
return [token, reset]
}
t.test('completion', t => {
t.plan(5)
+ const [token] = tokenWithMocks()
+
const testComp = (argv, expect) => {
t.resolveMatch(token.completion({ conf: { argv: { remain: argv } } }), expect, argv.join(' '))
}
@@ -74,7 +84,7 @@ t.test('completion', t => {
t.test('token foobar', async t => {
t.plan(2)
- const [, reset] = tokenWithMocks({
+ const [token, reset] = tokenWithMocks({
log: {
gauge: {
show: name => {
diff --git a/test/lib/commands/unpublish.js b/test/lib/commands/unpublish.js
index 6ac206753..1424adf5c 100644
--- a/test/lib/commands/unpublish.js
+++ b/test/lib/commands/unpublish.js
@@ -17,7 +17,6 @@ const testDir = t.testdir({
const npm = mockNpm({
localPrefix: testDir,
- log: { silly () {}, verbose () {} },
config,
output: (...msg) => {
result += msg.join('\n')
@@ -30,10 +29,10 @@ const mocks = {
'npm-registry-fetch': { json: noop },
'../../../lib/utils/otplease.js': async (opts, fn) => fn(opts),
'../../../lib/utils/get-identity.js': async () => 'foo',
+ 'proc-log': { silly () {}, verbose () {} },
}
t.afterEach(() => {
- npm.log = { silly () {}, verbose () {} }
npm.localPrefix = testDir
result = ''
config['dry-run'] = false
@@ -44,7 +43,7 @@ t.afterEach(() => {
t.test('no args --force', async t => {
config.force = true
- npm.log = {
+ const log = {
silly (title) {
t.equal(title, 'unpublish', 'should silly log args')
},
@@ -74,6 +73,7 @@ t.test('no args --force', async t => {
const Unpublish = t.mock('../../../lib/commands/unpublish.js', {
...mocks,
libnpmpublish,
+ 'proc-log': log,
})
const unpublish = new Unpublish(npm)
@@ -147,7 +147,7 @@ t.test('too many args', async t => {
})
t.test('unpublish <pkg>@version', async t => {
- npm.log = {
+ const log = {
silly (title, key, value) {
t.equal(title, 'unpublish', 'should silly log args')
if (key === 'spec') {
@@ -172,6 +172,7 @@ t.test('unpublish <pkg>@version', async t => {
const Unpublish = t.mock('../../../lib/commands/unpublish.js', {
...mocks,
libnpmpublish,
+ 'proc-log': log,
})
const unpublish = new Unpublish(npm)
diff --git a/test/lib/commands/update.js b/test/lib/commands/update.js
index 6ca6dbc87..aecb2c32b 100644
--- a/test/lib/commands/update.js
+++ b/test/lib/commands/update.js
@@ -9,12 +9,10 @@ const config = {
const noop = () => null
const npm = mockNpm({
globalDir: '',
- log: noop,
config,
prefix: '',
})
const mocks = {
- npmlog: { warn () {} },
'@npmcli/arborist': class {
reify () {}
},
@@ -29,22 +27,23 @@ t.afterEach(() => {
})
t.test('no args', async t => {
- t.plan(3)
+ t.plan(4)
npm.prefix = '/project/a'
class Arborist {
constructor (args) {
+ const { log, ...rest } = args
t.same(
- args,
+ rest,
{
...npm.flatOptions,
path: npm.prefix,
- log: noop,
workspaces: null,
},
'should call arborist contructor with expected args'
)
+ t.match(log, {}, 'log is passed in')
}
reify ({ update }) {
@@ -65,22 +64,23 @@ t.test('no args', async t => {
})
t.test('with args', async t => {
- t.plan(3)
+ t.plan(4)
npm.prefix = '/project/a'
class Arborist {
constructor (args) {
+ const { log, ...rest } = args
t.same(
- args,
+ rest,
{
...npm.flatOptions,
path: npm.prefix,
- log: noop,
workspaces: null,
},
'should call arborist contructor with expected args'
)
+ t.match(log, {}, 'log is passed in')
}
reify ({ update }) {
@@ -108,7 +108,7 @@ t.test('update --depth=<number>', async t => {
const Update = t.mock('../../../lib/commands/update.js', {
...mocks,
- npmlog: {
+ 'proc-log': {
warn: (title, msg) => {
t.equal(title, 'update', 'should print expected title')
t.match(
@@ -125,7 +125,7 @@ t.test('update --depth=<number>', async t => {
})
t.test('update --global', async t => {
- t.plan(2)
+ t.plan(3)
const normalizePath = p => p.replace(/\\+/g, '/')
const redactCwd = (path) => normalizePath(path)
@@ -137,13 +137,15 @@ t.test('update --global', async t => {
class Arborist {
constructor (args) {
- const { path, ...opts } = args
+ const { path, log, ...rest } = args
t.same(
- opts,
- { ...npm.flatOptions, log: noop, workspaces: undefined },
+ rest,
+ { ...npm.flatOptions, workspaces: undefined },
'should call arborist contructor with expected options'
)
+ t.match(log, {}, 'log is passed in')
+
t.equal(
redactCwd(path),
'{CWD}/global/lib',
diff --git a/test/lib/commands/version.js b/test/lib/commands/version.js
index 6603b5810..980353897 100644
--- a/test/lib/commands/version.js
+++ b/test/lib/commands/version.js
@@ -1,5 +1,6 @@
const t = require('tap')
const { fake: mockNpm } = require('../../fixtures/mock-npm')
+const mockGlobals = require('../../fixtures/mock-globals.js')
let result = []
@@ -26,294 +27,301 @@ const mocks = {
const Version = t.mock('../../../lib/commands/version.js', mocks)
const version = new Version(npm)
-const _processVersions = process.versions
t.afterEach(() => {
config.json = false
npm.prefix = ''
- process.versions = _processVersions
result = []
})
-t.test('no args', async t => {
- const prefix = t.testdir({
- 'package.json': JSON.stringify({
- name: 'test-version-no-args',
- version: '3.2.1',
- }),
- })
- npm.prefix = prefix
- Object.defineProperty(process, 'versions', { value: { node: '1.0.0' } })
-
- 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.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 => {
- const testComp = async (argv, expect) => {
- const res = await version.completion({ conf: { argv: { remain: argv } } })
- t.strictSame(res, expect, argv.join(' '))
- }
-
- await testComp(
- ['npm', 'version'],
- ['major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch', 'prerelease', 'from-git']
- )
- await testComp(['npm', 'version', 'major'], [])
-
- t.end()
-})
-
-t.test('failure reading package.json', async t => {
- const prefix = t.testdir({})
- npm.prefix = prefix
-
- await version.exec([])
-
- t.same(
- result,
- [
- {
- npm: '1.0.0',
- node: '1.0.0',
- },
- ],
- 'should not have package name on returning object'
- )
-})
-
-t.test('--json option', async t => {
- const prefix = t.testdir({})
- config.json = true
- npm.prefix = prefix
- Object.defineProperty(process, 'versions', { value: {} })
-
- await version.exec([])
- t.same(result, ['{\n "npm": "1.0.0"\n}'], 'should return json stringified result')
-})
+t.test('node@1', t => {
+ mockGlobals(t, { 'process.versions': { node: '1.0.0' } }, { replace: true })
-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')
- t.same(
- opts,
- {
- path: '',
- },
- 'should forward expected options'
- )
- return '4.0.0'
- },
- })
- const version = new Version(npm)
-
- await version.exec(['major'])
- t.same(result, ['v4.0.0'], 'outputs the new version prefixed by the tagVersionPrefix')
-})
+ t.test('no args', async t => {
+ const prefix = t.testdir({
+ 'package.json': JSON.stringify({
+ name: 'test-version-no-args',
+ version: '3.2.1',
+ }),
+ })
+ npm.prefix = prefix
-t.test('workspaces', async t => {
- t.teardown(() => {
- npm.localPrefix = ''
- npm.prefix = ''
- })
+ await version.exec([])
- t.test('no args, all workspaces', async t => {
- const testDir = t.testdir({
- 'package.json': JSON.stringify(
- {
- name: 'workspaces-test',
- version: '1.0.0',
- workspaces: ['workspace-a', 'workspace-b'],
- },
- null,
- 2
- ),
- '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',
- }),
- },
- })
- npm.localPrefix = testDir
- npm.prefix = testDir
- const version = new Version(npm)
- await version.execWorkspaces([], [])
t.same(
result,
[
{
- 'workspaces-test': '1.0.0',
- 'workspace-a': '1.0.0',
- 'workspace-b': '1.0.0',
+ 'test-version-no-args': '3.2.1',
+ node: '1.0.0',
npm: '1.0.0',
},
],
- 'outputs includes main package and workspace versions'
+ 'should output expected values for various versions in npm'
)
})
- t.test('no args, single workspaces', async t => {
- const testDir = t.testdir({
- 'package.json': JSON.stringify(
- {
- name: 'workspaces-test',
- version: '1.0.0',
- workspaces: ['workspace-a', 'workspace-b'],
- },
- null,
- 2
- ),
- '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',
- }),
- },
- })
- npm.localPrefix = testDir
- npm.prefix = testDir
- const version = new Version(npm)
- 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('too many args', async t => {
+ await t.rejects(
+ version.exec(['foo', 'bar']),
+ /npm version/,
+ 'should throw usage instructions error'
)
})
- 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',
- version: '1.0.0',
- workspaces: ['workspace-a', 'workspace-b', 'workspace-c'],
- },
- null,
- 2
- ),
- 'workspace-a': {
- 'package.json': JSON.stringify({
- name: 'workspace-a',
- version: '1.0.0',
- }),
- },
- 'workspace-b': {
- 'package.json': JSON.stringify({
- name: 'workspace-b',
- }),
- },
- 'workspace-c': {
- 'package.json': JSON.stringify({
- version: '1.0.0',
- }),
- },
- })
- npm.localPrefix = testDir
- npm.prefix = testDir
- const version = new Version(npm)
- await version.execWorkspaces([], [])
+ t.test('completion', async t => {
+ const testComp = async (argv, expect) => {
+ const res = await version.completion({ conf: { argv: { remain: argv } } })
+ t.strictSame(res, expect, argv.join(' '))
+ }
+
+ await testComp(
+ ['npm', 'version'],
+ ['major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch', 'prerelease', 'from-git']
+ )
+ await testComp(['npm', 'version', 'major'], [])
+
+ t.end()
+ })
+
+ t.test('failure reading package.json', async t => {
+ const prefix = t.testdir({})
+ npm.prefix = prefix
+
+ await version.exec([])
+
t.same(
result,
[
{
- 'workspaces-test': '1.0.0',
- 'workspace-a': '1.0.0',
npm: '1.0.0',
+ node: '1.0.0',
},
],
- 'outputs includes main package and valid workspace versions'
+ 'should not have package name on returning object'
)
})
+ t.end()
+})
- t.test('with one arg, all workspaces', async t => {
- const libNpmVersionArgs = []
- const testDir = t.testdir({
- 'package.json': JSON.stringify(
- {
- name: 'workspaces-test',
- version: '1.0.0',
- workspaces: ['workspace-a', 'workspace-b'],
- },
- null,
- 2
- ),
- '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',
- }),
- },
- })
+t.test('empty versions', t => {
+ mockGlobals(t, { 'process.versions': {} }, { replace: true })
+
+ t.test('--json option', async t => {
+ const prefix = t.testdir({})
+ config.json = true
+ npm.prefix = prefix
+
+ await version.exec([])
+ t.same(result, ['{\n "npm": "1.0.0"\n}'], 'should return json stringified result')
+ })
+
+ t.test('with one arg', async t => {
const Version = t.mock('../../../lib/commands/version.js', {
...mocks,
libnpmversion: (arg, opts) => {
- libNpmVersionArgs.push([arg, opts])
- return '2.0.0'
+ t.equal(arg, 'major', 'should forward expected value')
+ t.same(
+ opts,
+ {
+ path: '',
+ },
+ 'should forward expected options'
+ )
+ return '4.0.0'
},
})
- npm.localPrefix = testDir
- npm.prefix = testDir
const version = new Version(npm)
- 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'
- )
+ await version.exec(['major'])
+ t.same(result, ['v4.0.0'], 'outputs the new version prefixed by the tagVersionPrefix')
})
- t.test('too many args', async t => {
- await t.rejects(
- version.execWorkspaces(['foo', 'bar'], []),
- /npm version/,
- 'should throw usage instructions error'
- )
+ t.test('workspaces', async t => {
+ t.teardown(() => {
+ npm.localPrefix = ''
+ npm.prefix = ''
+ })
+
+ t.test('no args, all workspaces', async t => {
+ const testDir = t.testdir({
+ 'package.json': JSON.stringify(
+ {
+ name: 'workspaces-test',
+ version: '1.0.0',
+ workspaces: ['workspace-a', 'workspace-b'],
+ },
+ null,
+ 2
+ ),
+ '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',
+ }),
+ },
+ })
+ npm.localPrefix = testDir
+ npm.prefix = testDir
+ const version = new Version(npm)
+ 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', async t => {
+ const testDir = t.testdir({
+ 'package.json': JSON.stringify(
+ {
+ name: 'workspaces-test',
+ version: '1.0.0',
+ workspaces: ['workspace-a', 'workspace-b'],
+ },
+ null,
+ 2
+ ),
+ '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',
+ }),
+ },
+ })
+ npm.localPrefix = testDir
+ npm.prefix = testDir
+ const version = new Version(npm)
+ 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', async t => {
+ const testDir = t.testdir({
+ 'package.json': JSON.stringify(
+ {
+ name: 'workspaces-test',
+ version: '1.0.0',
+ workspaces: ['workspace-a', 'workspace-b', 'workspace-c'],
+ },
+ null,
+ 2
+ ),
+ 'workspace-a': {
+ 'package.json': JSON.stringify({
+ name: 'workspace-a',
+ version: '1.0.0',
+ }),
+ },
+ 'workspace-b': {
+ 'package.json': JSON.stringify({
+ name: 'workspace-b',
+ }),
+ },
+ 'workspace-c': {
+ 'package.json': JSON.stringify({
+ version: '1.0.0',
+ }),
+ },
+ })
+ npm.localPrefix = testDir
+ npm.prefix = testDir
+ const version = new Version(npm)
+ 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', async t => {
+ const libNpmVersionArgs = []
+ const testDir = t.testdir({
+ 'package.json': JSON.stringify(
+ {
+ name: 'workspaces-test',
+ version: '1.0.0',
+ workspaces: ['workspace-a', 'workspace-b'],
+ },
+ null,
+ 2
+ ),
+ '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',
+ }),
+ },
+ })
+ const Version = t.mock('../../../lib/commands/version.js', {
+ ...mocks,
+ libnpmversion: (arg, opts) => {
+ libNpmVersionArgs.push([arg, opts])
+ return '2.0.0'
+ },
+ })
+ npm.localPrefix = testDir
+ npm.prefix = testDir
+ const version = new Version(npm)
+
+ 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', async t => {
+ await t.rejects(
+ version.execWorkspaces(['foo', 'bar'], []),
+ /npm version/,
+ 'should throw usage instructions error'
+ )
+ })
})
+
+ t.end()
})
diff --git a/test/lib/commands/view.js b/test/lib/commands/view.js
index 728787ec4..035490a79 100644
--- a/test/lib/commands/view.js
+++ b/test/lib/commands/view.js
@@ -1,6 +1,7 @@
const t = require('tap')
-t.cleanSnapshot = str => str.replace(/published .*? ago/g, 'published {TIME} ago')
+t.cleanSnapshot = str => str
+ .replace(/(published ).*?( ago)/g, '$1{TIME}$2')
// run the same as tap does when running directly with node
process.stdout.columns = undefined
@@ -17,8 +18,8 @@ const cleanLogs = () => {
console.log = fn
}
-// 25 hours ago
-const yesterday = new Date(Date.now() - 1000 * 60 * 60 * 25)
+// 3 days. its never yesterday and never a week ago
+const yesterday = new Date(Date.now() - 1000 * 60 * 60 * 24 * 3)
const packument = (nv, opts) => {
if (!opts.fullMetadata) {
@@ -564,6 +565,12 @@ t.test('workspaces', async t => {
pacote: {
packument,
},
+ 'proc-log': {
+ warn: (msg) => {
+ warnMsg = msg
+ },
+ silly: () => {},
+ },
})
const config = {
unicode: false,
@@ -571,11 +578,6 @@ t.test('workspaces', async t => {
}
let warnMsg
const npm = mockNpm({
- log: {
- warn: (msg) => {
- warnMsg = msg
- },
- },
config,
localPrefix: testDir,
})
diff --git a/test/lib/commands/whoami.js b/test/lib/commands/whoami.js
index dc6144ec1..66c3f0c6b 100644
--- a/test/lib/commands/whoami.js
+++ b/test/lib/commands/whoami.js
@@ -1,26 +1,24 @@
const t = require('tap')
-const { real: mockNpm } = require('../../fixtures/mock-npm')
+const { load: _loadMockNpm } = require('../../fixtures/mock-npm')
const username = 'foo'
-const { joinedOutput, Npm } = mockNpm(t, {
- '../../lib/utils/get-identity.js': () => Promise.resolve(username),
-})
-const npm = new Npm()
-
-t.before(async () => {
- await npm.load()
+const loadMockNpm = (t, options) => _loadMockNpm(t, {
+ mocks: {
+ '../../lib/utils/get-identity.js': () => Promise.resolve(username),
+ },
+ ...options,
})
t.test('npm whoami', async (t) => {
+ const { npm, joinedOutput } = await loadMockNpm(t)
await npm.exec('whoami', [])
t.equal(joinedOutput(), username, 'should print username')
})
t.test('npm whoami --json', async (t) => {
- t.teardown(() => {
- npm.config.set('json', false)
+ const { npm, joinedOutput } = await loadMockNpm(t, {
+ config: { json: true },
})
- npm.config.set('json', true)
await npm.exec('whoami', [])
t.equal(JSON.parse(joinedOutput()), username, 'should print username')
})
diff --git a/test/lib/fixtures/mock-globals.js b/test/lib/fixtures/mock-globals.js
new file mode 100644
index 000000000..02566e575
--- /dev/null
+++ b/test/lib/fixtures/mock-globals.js
@@ -0,0 +1,321 @@
+const t = require('tap')
+const mockGlobals = require('../../fixtures/mock-globals')
+
+const originals = {
+ platform: process.platform,
+ error: console.error,
+ stderrOn: process.stderr.on,
+ stderrWrite: process.stderr.write,
+ shell: process.env.SHELL,
+ home: process.env.HOME,
+ argv: process.argv,
+ env: process.env,
+ setInterval,
+}
+
+t.test('console', async t => {
+ await t.test('mocks', async (t) => {
+ const errors = []
+ mockGlobals(t, {
+ 'console.error': (...args) => errors.push(...args),
+ })
+
+ console.error(1)
+ console.error(2)
+ console.error(3)
+ t.strictSame(errors, [1, 2, 3], 'i got my errors')
+ })
+
+ t.equal(console.error, originals.error)
+})
+
+t.test('platform', async (t) => {
+ t.equal(process.platform, originals.platform)
+
+ await t.test('posix', async (t) => {
+ mockGlobals(t, { 'process.platform': 'posix' })
+ t.equal(process.platform, 'posix')
+
+ await t.test('win32 --> woo', async (t) => {
+ mockGlobals(t, { 'process.platform': 'win32' })
+ t.equal(process.platform, 'win32')
+
+ mockGlobals(t, { 'process.platform': 'woo' })
+ t.equal(process.platform, 'woo')
+ })
+
+ t.equal(process.platform, 'posix')
+ })
+
+ t.equal(process.platform, originals.platform)
+})
+
+t.test('manual reset', async t => {
+ let errorHandler, data
+
+ const { reset } = mockGlobals(t, {
+ 'process.stderr.on': (__, handler) => {
+ errorHandler = handler
+ reset['process.stderr.on']()
+ },
+ 'process.stderr.write': (chunk, callback) => {
+ data = chunk
+ process.nextTick(() => {
+ errorHandler({ errno: 'EPIPE' })
+ callback()
+ })
+ reset['process.stderr.write']()
+ },
+ })
+
+ await new Promise((res, rej) => {
+ process.stderr.on('error', er => er.errno === 'EPIPE' ? res() : rej(er))
+ process.stderr.write('hey', res)
+ })
+
+ t.equal(process.stderr.on, originals.stderrOn)
+ t.equal(process.stderr.write, originals.stderrWrite)
+ t.equal(data, 'hey', 'handles EPIPE errors')
+ t.ok(errorHandler)
+})
+
+t.test('reset called multiple times', async (t) => {
+ await t.test('single reset', async t => {
+ const { reset } = mockGlobals(t, { 'process.platform': 'z' })
+ t.equal(process.platform, 'z')
+
+ reset['process.platform']()
+ t.equal(process.platform, originals.platform)
+
+ reset['process.platform']()
+ reset['process.platform']()
+ reset['process.platform']()
+ t.equal(process.platform, originals.platform)
+ })
+
+ t.equal(process.platform, originals.platform)
+})
+
+t.test('object mode', async t => {
+ await t.test('mocks', async t => {
+ const home = t.testdir()
+
+ mockGlobals(t, {
+ process: {
+ stderr: {
+ on: '1',
+ },
+ env: {
+ HOME: home,
+ },
+ },
+ })
+
+ t.equal(process.stderr.on, '1')
+ t.equal(process.env.HOME, home)
+ })
+
+ t.equal(process.env.HOME, originals.home)
+ t.equal(process.stderr.write, originals.stderrWrite)
+})
+
+t.test('mixed object/string mode', async t => {
+ await t.test('mocks', async t => {
+ const home = t.testdir()
+
+ mockGlobals(t, {
+ 'process.env': {
+ HOME: home,
+ TEST: '1',
+ },
+ })
+
+ t.equal(process.env.HOME, home)
+ t.equal(process.env.TEST, '1')
+ })
+
+ t.equal(process.env.HOME, originals.home)
+ t.equal(process.env.TEST, undefined)
+})
+
+t.test('conflicting mixed object/string mode', async t => {
+ await t.test('same key', async t => {
+ t.throws(
+ () => mockGlobals(t, {
+ process: {
+ env: {
+ HOME: '1',
+ TEST: '1',
+ NODE_ENV: '1',
+ },
+ stderr: {
+ write: '1',
+ },
+ },
+ 'process.env.HOME': '1',
+ 'process.stderr.write': '1',
+ }),
+ /process.env.HOME,process.stderr.write/
+ )
+ })
+
+ await t.test('partial overwrite with replace', async t => {
+ t.throws(
+ () => mockGlobals(t, {
+ process: {
+ env: {
+ HOME: '1',
+ TEST: '1',
+ NODE_ENV: '1',
+ },
+ stderr: {
+ write: '1',
+ },
+ },
+ 'process.env.HOME': '1',
+ 'process.stderr.write': '1',
+ }, { replace: true }),
+ /process -> process.env.HOME,process.stderr.write/
+ )
+ })
+})
+
+t.test('falsy values', async t => {
+ await t.test('undefined deletes', async t => {
+ mockGlobals(t, { 'process.platform': undefined })
+ t.notOk(Object.prototype.hasOwnProperty.call(process, 'platform'))
+ t.equal(process.platform, undefined)
+ })
+
+ await t.test('null', async t => {
+ mockGlobals(t, { 'process.platform': null })
+ t.ok(Object.prototype.hasOwnProperty.call(process, 'platform'))
+ t.equal(process.platform, null)
+ })
+
+ t.equal(process.platform, originals.platform)
+})
+
+t.test('date', async t => {
+ await t.test('mocks', async t => {
+ mockGlobals(t, {
+ 'Date.now': () => 100,
+ 'Date.prototype.toISOString': () => 'DDD',
+ })
+ t.equal(Date.now(), 100)
+ t.equal(new Date().toISOString(), 'DDD')
+ })
+
+ t.ok(Date.now() > 100)
+ t.ok(new Date().toISOString().includes('T'))
+})
+
+t.test('argv', async t => {
+ await t.test('argv', async t => {
+ mockGlobals(t, { 'process.argv': ['node', 'woo'] })
+ t.strictSame(process.argv, ['node', 'woo'])
+ })
+
+ t.strictSame(process.argv, originals.argv)
+})
+
+t.test('replace', async (t) => {
+ await t.test('env', async t => {
+ mockGlobals(t, { 'process.env': { HOME: '1' } }, { replace: true })
+ t.strictSame(process.env, { HOME: '1' })
+ t.equal(Object.keys(process.env).length, 1)
+ })
+
+ await t.test('setInterval', async t => {
+ mockGlobals(t, { setInterval: 0 }, { replace: true })
+ t.strictSame(setInterval, 0)
+ })
+
+ t.strictSame(setInterval, originals.setInterval)
+ t.strictSame(process.env, originals.env)
+})
+
+t.test('multiple mocks and resets', async (t) => {
+ const initial = 'a'
+ const platforms = ['b', 'c', 'd', 'e', 'f', 'g']
+
+ await t.test('first in, first out', async t => {
+ mockGlobals(t, { 'process.platform': initial })
+ t.equal(process.platform, initial)
+
+ await t.test('platforms', async (t) => {
+ const resets = platforms.map((platform) => {
+ const { reset } = mockGlobals(t, { 'process.platform': platform })
+ t.equal(process.platform, platform)
+ return reset['process.platform']
+ }).reverse()
+
+ ;[...platforms.reverse()].forEach((platform, index) => {
+ const reset = resets[index]
+ const nextPlatform = index === platforms.length - 1 ? initial : platforms[index + 1]
+ t.equal(process.platform, platform)
+ reset()
+ t.equal(process.platform, nextPlatform, 'first reset')
+ reset()
+ reset()
+ t.equal(process.platform, nextPlatform, 'multiple resets are indempotent')
+ })
+ })
+
+ t.equal(process.platform, initial)
+ })
+
+ await t.test('last in,first out', async t => {
+ mockGlobals(t, { 'process.platform': initial })
+ t.equal(process.platform, initial)
+
+ await t.test('platforms', async (t) => {
+ const resets = platforms.map((platform) => {
+ const { reset } = mockGlobals(t, { 'process.platform': platform })
+ t.equal(process.platform, platform)
+ return reset['process.platform']
+ })
+
+ resets.forEach((reset, index) => {
+ // Calling a reset out of order removes it from the stack
+ // but does not change the descriptor so it should still be the
+ // last in descriptor until there are none left
+ const lastPlatform = platforms[platforms.length - 1]
+ const nextPlatform = index === platforms.length - 1 ? initial : lastPlatform
+ t.equal(process.platform, lastPlatform)
+ reset()
+ t.equal(process.platform, nextPlatform, 'multiple resets are indempotent')
+ reset()
+ reset()
+ t.equal(process.platform, nextPlatform, 'multiple resets are indempotent')
+ })
+ })
+
+ t.equal(process.platform, initial)
+ })
+
+ t.test('reset all', async (t) => {
+ const { teardown } = mockGlobals(t, { 'process.platform': initial })
+
+ await t.test('platforms', async (t) => {
+ const resets = platforms.map((p) => {
+ const { teardown, reset } = mockGlobals(t, { 'process.platform': p })
+ t.equal(process.platform, p)
+ return [
+ reset['process.platform'],
+ teardown,
+ ]
+ })
+
+ resets.forEach(r => r[1]())
+ t.equal(process.platform, initial, 'teardown goes to initial value')
+
+ resets.forEach((r) => r[0]())
+ t.equal(process.platform, initial, 'calling resets after teardown does nothing')
+ })
+
+ t.equal(process.platform, initial)
+ teardown()
+ t.equal(process.platform, originals.platform)
+ })
+})
diff --git a/test/lib/load-all-commands.js b/test/lib/load-all-commands.js
index f813e50b2..248c81a30 100644
--- a/test/lib/load-all-commands.js
+++ b/test/lib/load-all-commands.js
@@ -4,21 +4,16 @@
// 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 { load: loadMockNpm } = require('../fixtures/mock-npm.js')
const { cmdList } = require('../../lib/utils/cmd-list.js')
-const { Npm, outputs } = mockNpm(t)
-const npm = new Npm()
-
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 { npm, outputs } = await loadMockNpm(t, {
+ config: { usage: true },
+ })
const impl = await npm.cmd(cmd)
if (impl.completion) {
t.type(impl.completion, 'function', 'completion, if present, is a function')
diff --git a/test/lib/load-all.js b/test/lib/load-all.js
index fb45331ba..e5d7b558c 100644
--- a/test/lib/load-all.js
+++ b/test/lib/load-all.js
@@ -1,34 +1,31 @@
const t = require('tap')
const glob = require('glob')
const { resolve } = require('path')
-const { real: mockNpm } = require('../fixtures/mock-npm')
+const { load: loadMockNpm } = require('../fixtures/mock-npm')
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 = new Npm()
+ t.test('load all', async (t) => {
+ const { npm } = await loadMockNpm(t, { })
- t.teardown(() => {
- const exitHandler = require('../../lib/utils/exit-handler.js')
- exitHandler.setNpm(npm)
- exitHandler()
- })
-
- t.before(async t => {
- await npm.load()
- })
+ t.teardown(() => {
+ const exitHandler = require('../../lib/utils/exit-handler.js')
+ exitHandler.setNpm(npm)
+ exitHandler()
+ })
- t.test('load all the files', t => {
- // just load all the files so we measure coverage for the missing tests
- const dir = resolve(__dirname, '../../lib')
- for (const f of glob.sync(`${dir}/**/*.js`)) {
- require(f)
- t.pass('loaded ' + f)
- }
- t.pass('loaded all files')
- t.end()
+ t.test('load all the files', t => {
+ // just load all the files so we measure coverage for the missing tests
+ const dir = resolve(__dirname, '../../lib')
+ for (const f of glob.sync(`${dir}/**/*.js`)) {
+ require(f)
+ t.pass('loaded ' + f)
+ }
+ t.pass('loaded all files')
+ t.end()
+ })
})
}
diff --git a/test/lib/npm.js b/test/lib/npm.js
index 1ccd26e37..2a0c5a89d 100644
--- a/test/lib/npm.js
+++ b/test/lib/npm.js
@@ -1,7 +1,8 @@
const t = require('tap')
+const { resolve, dirname } = require('path')
-const npmlog = require('npmlog')
-const { real: mockNpm } = require('../fixtures/mock-npm.js')
+const { load: loadMockNpm } = require('../fixtures/mock-npm.js')
+const mockGlobals = require('../fixtures/mock-globals')
// delete this so that we don't have configs from the fact that it
// is being run by 'npm test'
@@ -15,7 +16,7 @@ for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e))) {
// if this test is just run directly, which is also acceptable.
if (event === 'test') {
t.ok(
- ['test', 'run-script'].some(i => i === event),
+ ['test', 'run-script'].some(i => i === process.env[env]),
'should match "npm test" or "npm run test"'
)
} else {
@@ -25,41 +26,14 @@ for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e))) {
delete process.env[env]
}
-const { resolve, dirname } = require('path')
-
-const actualPlatform = process.platform
-const beWindows = () => {
- Object.defineProperty(process, 'platform', {
- value: 'win32',
- configurable: true,
- })
-}
-const bePosix = () => {
- Object.defineProperty(process, 'platform', {
- value: 'posix',
- configurable: true,
- })
-}
-const argv = [...process.argv]
-
-t.afterEach(() => {
+t.afterEach(async (t) => {
for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e))) {
delete process.env[env]
}
- process.env.npm_config_cache = CACHE
- process.argv = argv
- Object.defineProperty(process, 'platform', {
- value: actualPlatform,
- configurable: true,
- })
})
-const CACHE = t.testdir()
-process.env.npm_config_cache = CACHE
-
t.test('not yet loaded', async t => {
- const { Npm, logs } = mockNpm(t)
- const npm = new Npm()
+ const { npm, logs } = await loadMockNpm(t, { load: false })
t.match(npm, {
started: Number,
command: null,
@@ -79,8 +53,7 @@ t.test('not yet loaded', async t => {
t.test('npm.load', async t => {
t.test('load error', async t => {
- const { Npm } = mockNpm(t)
- const npm = new Npm()
+ const { npm } = await loadMockNpm(t, { load: false })
const loadError = new Error('load error')
npm.config.load = async () => {
throw loadError
@@ -103,32 +76,28 @@ t.test('npm.load', async t => {
})
t.test('basic loading', async t => {
- const { Npm, logs } = mockNpm(t)
- const npm = new Npm()
- const dir = t.testdir({
- node_modules: {},
+ const { npm, logs, prefix: dir, cache } = await loadMockNpm(t, {
+ testdir: { node_modules: {} },
})
- await npm.load()
+
t.equal(npm.loaded, true)
t.equal(npm.config.loaded, true)
t.equal(npm.config.get('force'), false)
t.ok(npm.usage, 'has usage')
- npm.config.set('prefix', dir)
t.match(npm, {
flatOptions: {},
})
- t.match(logs, [
- ['timing', 'npm:load', /Completed in [0-9.]+ms/],
+ t.match(logs.timing.filter(([p]) => p === 'npm:load'), [
+ ['npm:load', /Completed in [0-9.]+ms/],
])
- bePosix()
- t.equal(resolve(npm.cache), resolve(CACHE), 'cache is cache')
+ mockGlobals(t, { process: { platform: 'posix' } })
+ t.equal(resolve(npm.cache), resolve(cache), 'cache is cache')
const newCache = t.testdir()
npm.cache = newCache
t.equal(npm.config.get('cache'), newCache, 'cache setter sets config')
t.equal(npm.cache, newCache, 'cache getter gets new config')
- t.equal(npm.log, npmlog, 'npmlog getter')
t.equal(npm.lockfileVersion, 2, 'lockfileVersion getter')
t.equal(npm.prefix, npm.localPrefix, 'prefix is local prefix')
t.not(npm.prefix, npm.globalPrefix, 'prefix is not global prefix')
@@ -160,10 +129,9 @@ t.test('npm.load', async t => {
t.equal(npm.bin, npm.globalBin, 'bin is global bin after prefix setter')
t.not(npm.bin, npm.localBin, 'bin is not local bin after prefix setter')
- beWindows()
+ mockGlobals(t, { process: { platform: 'win32' } })
t.equal(npm.bin, npm.globalBin, 'bin is global bin in windows mode')
t.equal(npm.dir, npm.globalDir, 'dir is global dir in windows mode')
- bePosix()
const tmp = npm.tmp
t.match(tmp, String, 'npm.tmp is a string')
@@ -171,13 +139,12 @@ t.test('npm.load', async t => {
})
t.test('forceful loading', async t => {
- process.argv = [...process.argv, '--force', '--color', 'always']
- const { Npm, logs } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- t.match(logs.filter(l => l[0] !== 'timing'), [
+ mockGlobals(t, {
+ 'process.argv': [...process.argv, '--force', '--color', 'always'],
+ })
+ const { logs } = await loadMockNpm(t)
+ t.match(logs.warn, [
[
- 'warn',
'using --force',
'Recommended protections disabled.',
],
@@ -185,54 +152,42 @@ t.test('npm.load', async t => {
})
t.test('node is a symlink', async t => {
- const node = actualPlatform === 'win32' ? 'node.exe' : 'node'
- const dir = t.testdir({
- '.npmrc': 'foo = bar',
- bin: t.fixture('symlink', dirname(process.execPath)),
+ const node = process.platform === 'win32' ? 'node.exe' : 'node'
+ mockGlobals(t, {
+ 'process.argv': [
+ node,
+ process.argv[1],
+ '--usage',
+ '--scope=foo',
+ 'token',
+ 'revoke',
+ 'blergggg',
+ ],
})
-
- const PATH = process.env.PATH || process.env.Path
- process.env.PATH = resolve(dir, 'bin')
- process.argv = [
- node,
- process.argv[1],
- '--prefix', dir,
- '--userconfig', `${dir}/.npmrc`,
- '--usage',
- '--scope=foo',
- 'token',
- 'revoke',
- 'blergggg',
- ]
-
- t.teardown(() => {
- process.env.PATH = PATH
+ const { npm, logs, outputs, prefix } = await loadMockNpm(t, {
+ testdir: {
+ bin: t.fixture('symlink', dirname(process.execPath)),
+ },
+ globals: ({ prefix }) => ({
+ 'process.env.PATH': resolve(prefix, 'bin'),
+ }),
})
- 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])), [
- [
- 'timing',
- 'npm:load:whichnode',
- /Completed in [0-9.]+ms/,
- ],
- [
- 'verbose',
- 'node symlink',
- resolve(dir, 'bin', node),
- ],
- [
- 'timing',
- 'npm:load',
- /Completed in [0-9.]+ms/,
- ],
+ t.match([
+ ...logs.timing.filter(([p]) => p === 'npm:load:whichnode'),
+ ...logs.verbose,
+ ...logs.timing.filter(([p]) => p === 'npm:load'),
+ ], [
+ ['npm:load:whichnode', /Completed in [0-9.]+ms/],
+ ['node symlink', resolve(prefix, 'bin', node)],
+ ['logfile', /.*-debug-0.log/],
+ ['npm:load', /Completed in [0-9.]+ms/],
])
- t.equal(process.execPath, resolve(dir, 'bin', node))
+ t.equal(process.execPath, resolve(prefix, 'bin', node))
outputs.length = 0
+ logs.length = 0
await npm.exec('ll', [])
t.equal(npm.command, 'll', 'command set to first npm command')
@@ -271,33 +226,34 @@ t.test('npm.load', async t => {
})
t.test('--no-workspaces with --workspace', async t => {
- const dir = t.testdir({
- packages: {
- a: {
- 'package.json': JSON.stringify({
- name: 'a',
- version: '1.0.0',
- scripts: { test: 'echo test a' },
- }),
+ mockGlobals(t, {
+ 'process.argv': [
+ process.execPath,
+ process.argv[1],
+ '--color', 'false',
+ '--workspaces', 'false',
+ '--workspace', 'a',
+ ],
+ })
+ const { npm } = await loadMockNpm(t, {
+ load: false,
+ testdir: {
+ packages: {
+ a: {
+ 'package.json': JSON.stringify({
+ name: 'a',
+ version: '1.0.0',
+ scripts: { test: 'echo test a' },
+ }),
+ },
},
+ 'package.json': JSON.stringify({
+ name: 'root',
+ version: '1.0.0',
+ workspaces: ['./packages/*'],
+ }),
},
- 'package.json': JSON.stringify({
- name: 'root',
- version: '1.0.0',
- workspaces: ['./packages/*'],
- }),
})
- process.argv = [
- process.execPath,
- process.argv[1],
- '--userconfig', resolve(dir, '.npmrc'),
- '--color', 'false',
- '--workspaces', 'false',
- '--workspace', 'a',
- ]
- const { Npm } = mockNpm(t)
- const npm = new Npm()
- npm.localPrefix = dir
await t.rejects(
npm.exec('run', []),
/Can not use --no-workspaces and --workspace at the same time/
@@ -305,47 +261,40 @@ t.test('npm.load', async t => {
})
t.test('workspace-aware configs and commands', async t => {
- const dir = t.testdir({
- packages: {
- a: {
- 'package.json': JSON.stringify({
- name: 'a',
- version: '1.0.0',
- scripts: { test: 'echo test a' },
- }),
- },
- b: {
- 'package.json': JSON.stringify({
- name: 'b',
- version: '1.0.0',
- scripts: { test: 'echo test b' },
- }),
+ mockGlobals(t, {
+ 'process.argv': [
+ process.execPath,
+ process.argv[1],
+ '--color', 'false',
+ '--workspaces', 'true',
+ ],
+ })
+ const { npm, outputs } = await loadMockNpm(t, {
+ testdir: {
+ packages: {
+ a: {
+ 'package.json': JSON.stringify({
+ name: 'a',
+ version: '1.0.0',
+ scripts: { test: 'echo test a' },
+ }),
+ },
+ b: {
+ 'package.json': JSON.stringify({
+ name: 'b',
+ version: '1.0.0',
+ scripts: { test: 'echo test b' },
+ }),
+ },
},
+ 'package.json': JSON.stringify({
+ name: 'root',
+ version: '1.0.0',
+ workspaces: ['./packages/*'],
+ }),
},
- 'package.json': JSON.stringify({
- name: 'root',
- version: '1.0.0',
- workspaces: ['./packages/*'],
- }),
- '.npmrc': '',
})
- process.argv = [
- process.execPath,
- process.argv[1],
- '--userconfig',
- resolve(dir, '.npmrc'),
- '--color',
- 'false',
- '--workspaces',
- 'true',
- ]
-
- const { Npm, outputs } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.localPrefix = dir
-
// 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
@@ -368,44 +317,42 @@ t.test('npm.load', async t => {
})
t.test('workspaces in global mode', async t => {
- const dir = t.testdir({
- packages: {
- a: {
- 'package.json': JSON.stringify({
- name: 'a',
- version: '1.0.0',
- scripts: { test: 'echo test a' },
- }),
- },
- b: {
- 'package.json': JSON.stringify({
- name: 'b',
- version: '1.0.0',
- scripts: { test: 'echo test b' },
- }),
+ mockGlobals(t, {
+ 'process.argv': [
+ process.execPath,
+ process.argv[1],
+ '--color',
+ 'false',
+ '--workspaces',
+ '--global',
+ 'true',
+ ],
+ })
+ const { npm } = await loadMockNpm(t, {
+ testdir: {
+ packages: {
+ a: {
+ 'package.json': JSON.stringify({
+ name: 'a',
+ version: '1.0.0',
+ scripts: { test: 'echo test a' },
+ }),
+ },
+ b: {
+ 'package.json': JSON.stringify({
+ name: 'b',
+ version: '1.0.0',
+ scripts: { test: 'echo test b' },
+ }),
+ },
},
+ 'package.json': JSON.stringify({
+ name: 'root',
+ version: '1.0.0',
+ workspaces: ['./packages/*'],
+ }),
},
- 'package.json': JSON.stringify({
- name: 'root',
- version: '1.0.0',
- workspaces: ['./packages/*'],
- }),
})
- process.argv = [
- process.execPath,
- process.argv[1],
- '--userconfig',
- resolve(dir, '.npmrc'),
- '--color',
- 'false',
- '--workspaces',
- '--global',
- 'true',
- ]
- const { Npm } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
- npm.localPrefix = dir
// 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
@@ -418,109 +365,156 @@ t.test('npm.load', async t => {
t.test('set process.title', async t => {
t.test('basic title setting', async t => {
- process.argv = [
- process.execPath,
- process.argv[1],
- '--usage',
- '--scope=foo',
- 'ls',
- ]
- const { Npm } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
+ mockGlobals(t, {
+ 'process.argv': [
+ process.execPath,
+ process.argv[1],
+ '--usage',
+ '--scope=foo',
+ 'ls',
+ ],
+ })
+ const { npm } = await loadMockNpm(t)
t.equal(npm.title, 'npm ls')
t.equal(process.title, 'npm ls')
})
t.test('do not expose token being revoked', async t => {
- process.argv = [
- process.execPath,
- process.argv[1],
- '--usage',
- '--scope=foo',
- 'token',
- 'revoke',
- 'deadbeefcafebad',
- ]
- const { Npm } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
+ mockGlobals(t, {
+ 'process.argv': [
+ process.execPath,
+ process.argv[1],
+ '--usage',
+ '--scope=foo',
+ 'token',
+ 'revoke',
+ 'deadbeefcafebad',
+ ],
+ })
+ const { npm } = await loadMockNpm(t)
t.equal(npm.title, 'npm token revoke ***')
t.equal(process.title, 'npm token revoke ***')
})
t.test('do show *** unless a token is actually being revoked', async t => {
- process.argv = [
- process.execPath,
- process.argv[1],
- '--usage',
- '--scope=foo',
- 'token',
- 'revoke',
- ]
- const { Npm } = mockNpm(t)
- const npm = new Npm()
- await npm.load()
+ mockGlobals(t, {
+ 'process.argv': [
+ process.execPath,
+ process.argv[1],
+ '--usage',
+ '--scope=foo',
+ 'token',
+ 'revoke',
+ ],
+ })
+ const { npm } = await loadMockNpm(t)
t.equal(npm.title, 'npm token revoke')
t.equal(process.title, 'npm token revoke')
})
})
-t.test('timings', 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')
- t.match(npm.timers.get('bar'), Number, 'foo timer is a number')
- process.emit('timeEnd', 'foo')
- process.emit('timeEnd', 'bar')
- process.emit('timeEnd', 'baz')
- t.match(logs, [
- ['timing', 'foo', /Completed in [0-9]+ms/],
- ['timing', 'bar', /Completed in [0-9]+ms/],
- [
- 'silly',
+t.test('debug-log', async t => {
+ const { npm, debugFile } = await loadMockNpm(t, { load: false })
+
+ const log1 = ['silly', 'test', 'before load']
+ const log2 = ['silly', 'test', 'after load']
+
+ process.emit('log', ...log1)
+ await npm.load()
+ process.emit('log', ...log2)
+
+ const debug = await debugFile()
+ t.equal(npm.logFiles.length, 1, 'one debug file')
+ t.match(debug, log1.join(' '), 'before load appears')
+ t.match(debug, log2.join(' '), 'after load log appears')
+})
+
+t.test('timings', async t => {
+ t.test('gets/sets timers', async t => {
+ const { npm, logs } = await loadMockNpm(t, { load: false })
+ process.emit('time', 'foo')
+ process.emit('time', 'bar')
+ t.match(npm.unfinishedTimers.get('foo'), Number, 'foo timer is a number')
+ t.match(npm.unfinishedTimers.get('bar'), Number, 'foo timer is a number')
+ process.emit('timeEnd', 'foo')
+ process.emit('timeEnd', 'bar')
+ process.emit('timeEnd', 'baz')
+ // npm timer is started by default
+ process.emit('timeEnd', 'npm')
+ t.match(logs.timing, [
+ ['foo', /Completed in [0-9]+ms/],
+ ['bar', /Completed in [0-9]+ms/],
+ ['npm', /Completed in [0-9]+ms/],
+ ])
+ t.match(logs.silly, [[
'timing',
"Tried to end timer that doesn't exist:",
'baz',
- ],
- ])
- t.notOk(npm.timers.has('foo'), 'foo timer is gone')
- t.notOk(npm.timers.has('bar'), 'bar timer is gone')
- t.match(npm.timings, { foo: Number, bar: Number })
- t.end()
+ ]])
+ t.notOk(npm.unfinishedTimers.has('foo'), 'foo timer is gone')
+ t.notOk(npm.unfinishedTimers.has('bar'), 'bar timer is gone')
+ t.match(npm.finishedTimers, { foo: Number, bar: Number, npm: Number })
+ t.end()
+ })
+
+ t.test('writes timings file', async t => {
+ const { npm, timingFile } = await loadMockNpm(t, {
+ config: { timing: true },
+ })
+ process.emit('time', 'foo')
+ process.emit('timeEnd', 'foo')
+ process.emit('time', 'bar')
+ npm.unload()
+ const timings = await timingFile()
+ t.match(timings, {
+ command: [],
+ logfile: String,
+ logfiles: [String],
+ version: String,
+ unfinished: {
+ bar: [Number, Number],
+ npm: [Number, Number],
+ },
+ foo: Number,
+ 'npm:load': Number,
+ })
+ })
+
+ t.test('does not write timings file with timers:false', async t => {
+ const { npm, timingFile } = await loadMockNpm(t, {
+ config: { false: true },
+ })
+ npm.unload()
+ await t.rejects(() => timingFile())
+ })
})
-t.test('output clears progress and console.logs the message', t => {
- const mock = mockNpm(t)
- const { Npm, logs } = mock
- const npm = new Npm()
- npm.output = mock.npmOutput
- const { log } = console
- const { log: { clearProgress, showProgress } } = npm
+t.test('output clears progress and console.logs the message', async t => {
+ t.plan(2)
let showingProgress = true
- npm.log.clearProgress = () => showingProgress = false
- npm.log.showProgress = () => showingProgress = true
- console.log = (...args) => {
- t.equal(showingProgress, false, 'should not be showing progress right now')
- logs.push(args)
- }
- t.teardown(() => {
- console.log = log
- npm.log.showProgress = showProgress
- npm.log.clearProgress = clearProgress
+ const logs = []
+ mockGlobals(t, {
+ 'console.log': (...args) => {
+ t.equal(showingProgress, false, 'should not be showing progress right now')
+ logs.push(args)
+ },
})
-
- npm.output('hello')
- t.strictSame(logs, [['hello']])
+ const { npm } = await loadMockNpm(t, {
+ load: false,
+ mocks: {
+ npmlog: {
+ clearProgress: () => showingProgress = false,
+ showProgress: () => showingProgress = true,
+ },
+ },
+ })
+ npm.originalOutput('hello')
+ t.match(logs, [['hello']])
t.end()
})
t.test('unknown command', async t => {
- const mock = mockNpm(t)
- const { Npm } = mock
- const npm = new Npm()
+ const { npm } = await loadMockNpm(t, { load: false })
await t.rejects(
npm.cmd('thisisnotacommand'),
{ code: 'EUNKNOWNCOMMAND' }
diff --git a/test/lib/utils/audit-error.js b/test/lib/utils/audit-error.js
index c683053cb..bcb7d8c16 100644
--- a/test/lib/utils/audit-error.js
+++ b/test/lib/utils/audit-error.js
@@ -3,14 +3,15 @@ const t = require('tap')
const LOGS = []
const OUTPUT = []
const output = (...msg) => OUTPUT.push(msg)
-const auditError = require('../../../lib/utils/audit-error.js')
+const auditError = t.mock('../../../lib/utils/audit-error.js', {
+ 'proc-log': {
+ warn: (...msg) => LOGS.push(msg),
+ },
+})
const npm = {
command: null,
flatOptions: {},
- log: {
- warn: (...msg) => LOGS.push(msg),
- },
output,
}
t.afterEach(() => {
diff --git a/test/lib/utils/cleanup-log-files.js b/test/lib/utils/cleanup-log-files.js
deleted file mode 100644
index e97cf36b5..000000000
--- a/test/lib/utils/cleanup-log-files.js
+++ /dev/null
@@ -1,79 +0,0 @@
-const t = require('tap')
-
-const glob = require('glob')
-const rimraf = require('rimraf')
-const mocks = { glob, rimraf }
-const cleanup = t.mock('../../../lib/utils/cleanup-log-files.js', {
- glob: (...args) => mocks.glob(...args),
- rimraf: (...args) => mocks.rimraf(...args),
-})
-const { basename } = require('path')
-
-const fs = require('fs')
-
-t.test('clean up those files', t => {
- const cache = t.testdir({
- _logs: {
- '1-debug.log': 'hello',
- '2-debug.log': 'hello',
- '3-debug.log': 'hello',
- '4-debug.log': 'hello',
- '5-debug.log': 'hello',
- },
- })
- const warn = (...warning) => t.fail('failed cleanup', { warning })
- return cleanup(cache, 3, warn).then(() => {
- t.strictSame(fs.readdirSync(cache + '/_logs').sort(), [
- '3-debug.log',
- '4-debug.log',
- '5-debug.log',
- ])
- })
-})
-
-t.test('nothing to clean up', t => {
- const cache = t.testdir({
- _logs: {
- '4-debug.log': 'hello',
- '5-debug.log': 'hello',
- },
- })
- const warn = (...warning) => t.fail('failed cleanup', { warning })
- return cleanup(cache, 3, warn).then(() => {
- t.strictSame(fs.readdirSync(cache + '/_logs').sort(), [
- '4-debug.log',
- '5-debug.log',
- ])
- })
-})
-
-t.test('glob fail', t => {
- mocks.glob = (pattern, cb) => cb(new Error('no globbity'))
- t.teardown(() => mocks.glob = glob)
- const cache = t.testdir({})
- const warn = (...warning) => t.fail('failed cleanup', { warning })
- return cleanup(cache, 3, warn)
-})
-
-t.test('rimraf fail', t => {
- mocks.rimraf = (file, cb) => cb(new Error('youll never rimraf me!'))
- t.teardown(() => mocks.rimraf = rimraf)
-
- const cache = t.testdir({
- _logs: {
- '1-debug.log': 'hello',
- '2-debug.log': 'hello',
- '3-debug.log': 'hello',
- '4-debug.log': 'hello',
- '5-debug.log': 'hello',
- },
- })
- const warnings = []
- const warn = (...warning) => warnings.push(basename(warning[2]))
- return cleanup(cache, 3, warn).then(() => {
- t.strictSame(warnings.sort((a, b) => a.localeCompare(b, 'en')), [
- '1-debug.log',
- '2-debug.log',
- ])
- })
-})
diff --git a/test/lib/utils/config/definitions.js b/test/lib/utils/config/definitions.js
index 7af0b6839..bf4b48709 100644
--- a/test/lib/utils/config/definitions.js
+++ b/test/lib/utils/config/definitions.js
@@ -1,11 +1,9 @@
const t = require('tap')
-
const { resolve } = require('path')
+const mockGlobals = require('../../../fixtures/mock-globals')
// have to fake the node version, or else it'll only pass on this one
-Object.defineProperty(process, 'version', {
- value: 'v14.8.0',
-})
+mockGlobals(t, { 'process.version': 'v14.8.0', 'process.env.NODE_ENV': undefined })
// also fake the npm version, so that it doesn't get reset every time
const pkg = require('../../../../package.json')
@@ -13,8 +11,6 @@ const pkg = require('../../../../package.json')
// this is a pain to keep typing
const defpath = '../../../../lib/utils/config/definitions.js'
-// set this in the test when we need it
-delete process.env.NODE_ENV
const definitions = require(defpath)
// Tie the definitions to a snapshot so that if they change we are forced to
@@ -43,22 +39,19 @@ t.test('basic flattening function camelCases from css-case', t => {
t.test('editor', t => {
t.test('has EDITOR and VISUAL, use EDITOR', t => {
- process.env.EDITOR = 'vim'
- process.env.VISUAL = 'mate'
+ mockGlobals(t, { 'process.env': { EDITOR: 'vim', VISUAL: 'mate' } })
const defs = t.mock(defpath)
t.equal(defs.editor.default, 'vim')
t.end()
})
t.test('has VISUAL but no EDITOR, use VISUAL', t => {
- delete process.env.EDITOR
- process.env.VISUAL = 'mate'
+ mockGlobals(t, { 'process.env': { EDITOR: undefined, VISUAL: 'mate' } })
const defs = t.mock(defpath)
t.equal(defs.editor.default, 'mate')
t.end()
})
t.test('has neither EDITOR nor VISUAL, system specific', t => {
- delete process.env.EDITOR
- delete process.env.VISUAL
+ mockGlobals(t, { 'process.env': { EDITOR: undefined, VISUAL: undefined } })
const defsWin = t.mock(defpath, {
[isWin]: true,
})
@@ -74,12 +67,12 @@ t.test('editor', t => {
t.test('shell', t => {
t.test('windows, env.ComSpec then cmd.exe', t => {
- process.env.ComSpec = 'command.com'
+ mockGlobals(t, { 'process.env.ComSpec': 'command.com' })
const defsComSpec = t.mock(defpath, {
[isWin]: true,
})
t.equal(defsComSpec.shell.default, 'command.com')
- delete process.env.ComSpec
+ mockGlobals(t, { 'process.env.ComSpec': undefined })
const defsNoComSpec = t.mock(defpath, {
[isWin]: true,
})
@@ -88,12 +81,12 @@ t.test('shell', t => {
})
t.test('nix, SHELL then sh', t => {
- process.env.SHELL = '/usr/local/bin/bash'
+ mockGlobals(t, { 'process.env.SHELL': '/usr/local/bin/bash' })
const defsShell = t.mock(defpath, {
[isWin]: false,
})
t.equal(defsShell.shell.default, '/usr/local/bin/bash')
- delete process.env.SHELL
+ mockGlobals(t, { 'process.env.SHELL': undefined })
const defsNoShell = t.mock(defpath, {
[isWin]: false,
})
@@ -136,43 +129,40 @@ t.test('local-address allowed types', t => {
})
t.test('unicode allowed?', t => {
- const { LC_ALL, LC_CTYPE, LANG } = process.env
- t.teardown(() => Object.assign(process.env, { LC_ALL, LC_CTYPE, LANG }))
+ const setGlobal = (obj = {}) => mockGlobals(t, { 'process.env': obj })
- process.env.LC_ALL = 'utf8'
- process.env.LC_CTYPE = 'UTF-8'
- process.env.LANG = 'Unicode utf-8'
+ setGlobal({ LC_ALL: 'utf8', LC_CTYPE: 'UTF-8', LANG: 'Unicode utf-8' })
const lcAll = t.mock(defpath)
t.equal(lcAll.unicode.default, true)
- process.env.LC_ALL = 'no unicode for youUUUU!'
+ setGlobal({ LC_ALL: 'no unicode for youUUUU!' })
const noLcAll = t.mock(defpath)
t.equal(noLcAll.unicode.default, false)
- delete process.env.LC_ALL
+ setGlobal({ LC_ALL: undefined })
const lcCtype = t.mock(defpath)
t.equal(lcCtype.unicode.default, true)
- process.env.LC_CTYPE = 'something other than unicode version 8'
+ setGlobal({ LC_CTYPE: 'something other than unicode version 8' })
const noLcCtype = t.mock(defpath)
t.equal(noLcCtype.unicode.default, false)
- delete process.env.LC_CTYPE
+ setGlobal({ LC_CTYPE: undefined })
const lang = t.mock(defpath)
t.equal(lang.unicode.default, true)
- process.env.LANG = 'ISO-8859-1'
+ setGlobal({ LANG: 'ISO-8859-1' })
const noLang = t.mock(defpath)
t.equal(noLang.unicode.default, false)
t.end()
})
t.test('cache', t => {
- process.env.LOCALAPPDATA = 'app/data/local'
+ mockGlobals(t, { 'process.env.LOCALAPPDATA': 'app/data/local' })
const defsWinLocalAppData = t.mock(defpath, {
[isWin]: true,
})
t.equal(defsWinLocalAppData.cache.default, 'app/data/local/npm-cache')
- delete process.env.LOCALAPPDATA
+ mockGlobals(t, { 'process.env.LOCALAPPDATA': undefined })
const defsWinNoLocalAppData = t.mock(defpath, {
[isWin]: true,
})
@@ -241,7 +231,7 @@ t.test('flatteners that populate flat.omit array', t => {
definitions.omit.flatten('omit', obj, flat)
t.strictSame(flat, { omit: ['optional'] }, 'do not omit what is included')
- process.env.NODE_ENV = 'production'
+ mockGlobals(t, { 'process.env.NODE_ENV': 'production' })
const defProdEnv = t.mock(defpath)
t.strictSame(defProdEnv.omit.default, ['dev'], 'omit dev in production')
t.end()
@@ -372,42 +362,79 @@ t.test('cache-min', t => {
})
t.test('color', t => {
- const { isTTY } = process.stdout
- t.teardown(() => process.stdout.isTTY = isTTY)
+ const setTTY = (stream, value) => mockGlobals(t, { [`process.${stream}.isTTY`]: value })
const flat = {}
const obj = { color: 'always' }
definitions.color.flatten('color', obj, flat)
- t.strictSame(flat, { color: true }, 'true when --color=always')
+ t.strictSame(flat, { color: true, logColor: true }, 'true when --color=always')
obj.color = false
definitions.color.flatten('color', obj, flat)
- t.strictSame(flat, { color: false }, 'true when --no-color')
+ t.strictSame(flat, { color: false, logColor: false }, 'true when --no-color')
- process.stdout.isTTY = false
+ setTTY('stdout', false)
obj.color = true
definitions.color.flatten('color', obj, flat)
- t.strictSame(flat, { color: false }, 'no color when stdout not tty')
- process.stdout.isTTY = true
+ t.strictSame(flat, { color: false, logColor: false }, 'no color when stdout not tty')
+ setTTY('stdout', true)
definitions.color.flatten('color', obj, flat)
- t.strictSame(flat, { color: true }, '--color turns on color when stdout is tty')
+ t.strictSame(flat, { color: true, logColor: false }, '--color turns on color when stdout is tty')
+ setTTY('stdout', false)
- delete process.env.NO_COLOR
+ setTTY('stderr', false)
+ obj.color = true
+ definitions.color.flatten('color', obj, flat)
+ t.strictSame(flat, { color: false, logColor: false }, 'no color when stderr not tty')
+ setTTY('stderr', true)
+ definitions.color.flatten('color', obj, flat)
+ t.strictSame(flat, { color: false, logColor: true }, '--color turns on color when stderr is tty')
+ setTTY('stderr', false)
+
+ const setColor = (value) => mockGlobals(t, { 'process.env.NO_COLOR': value })
+
+ setColor(undefined)
const defsAllowColor = t.mock(defpath)
t.equal(defsAllowColor.color.default, true, 'default true when no NO_COLOR env')
- process.env.NO_COLOR = '0'
+ setColor('0')
const defsNoColor0 = t.mock(defpath)
t.equal(defsNoColor0.color.default, true, 'default true when no NO_COLOR=0')
- process.env.NO_COLOR = '1'
+ setColor('1')
const defsNoColor1 = t.mock(defpath)
t.equal(defsNoColor1.color.default, false, 'default false when no NO_COLOR=1')
t.end()
})
+t.test('progress', t => {
+ const setEnv = ({ tty, term } = {}) => mockGlobals(t, {
+ 'process.stderr.isTTY': tty,
+ 'process.env.TERM': term,
+ })
+
+ const flat = {}
+
+ definitions.progress.flatten('progress', {}, flat)
+ t.strictSame(flat, { progress: false })
+
+ setEnv({ tty: true, term: 'notdumb' })
+ definitions.progress.flatten('progress', { progress: true }, flat)
+ t.strictSame(flat, { progress: true })
+
+ setEnv({ tty: false, term: 'notdumb' })
+ definitions.progress.flatten('progress', { progress: true }, flat)
+ t.strictSame(flat, { progress: false })
+
+ setEnv({ tty: true, term: 'dumb' })
+ definitions.progress.flatten('progress', { progress: true }, flat)
+ t.strictSame(flat, { progress: false })
+
+ t.end()
+})
+
t.test('retry options', t => {
const obj = {}
// <config>: flat.retry[<option>]
diff --git a/test/lib/utils/did-you-mean.js b/test/lib/utils/did-you-mean.js
index 185368d61..d3cb3a24f 100644
--- a/test/lib/utils/did-you-mean.js
+++ b/test/lib/utils/did-you-mean.js
@@ -1,11 +1,9 @@
const t = require('tap')
-const { real: mockNpm } = require('../../fixtures/mock-npm.js')
-const { Npm } = mockNpm(t)
-const npm = new Npm()
+const { load: loadMockNpm } = require('../../fixtures/mock-npm.js')
const dym = require('../../../lib/utils/did-you-mean.js')
t.test('did-you-mean', async t => {
- await npm.load()
+ const { npm } = await loadMockNpm(t)
t.test('with package.json', async t => {
const testdir = t.testdir({
'package.json': JSON.stringify({
diff --git a/test/lib/utils/display.js b/test/lib/utils/display.js
new file mode 100644
index 000000000..30cd2cc27
--- /dev/null
+++ b/test/lib/utils/display.js
@@ -0,0 +1,85 @@
+const t = require('tap')
+const log = require('../../../lib/utils/log-shim')
+const mockLogs = require('../../fixtures/mock-logs')
+const mockGlobals = require('../../fixtures/mock-globals')
+
+const mockDisplay = (t, mocks) => {
+ const { logs, logMocks } = mockLogs(mocks)
+ const Display = t.mock('../../../lib/utils/display', {
+ ...mocks,
+ ...logMocks,
+ })
+ const display = new Display()
+ t.teardown(() => display.off())
+ return { display, logs }
+}
+
+t.test('setup', async (t) => {
+ const { display } = mockDisplay(t)
+
+ display.load({ timing: true, loglevel: 'notice' })
+ t.equal(log.level, 'timing')
+
+ display.load({ timing: false, loglevel: 'notice' })
+ t.equal(log.level, 'notice')
+
+ display.load({ color: true })
+ t.equal(log.useColor(), true)
+
+ display.load({ unicode: true })
+ t.equal(log.gauge._theme.hasUnicode, true)
+
+ display.load({ unicode: false })
+ t.equal(log.gauge._theme.hasUnicode, false)
+
+ mockGlobals(t, { 'process.stderr.isTTY': true })
+ display.load({ progress: true })
+ t.equal(log.progressEnabled, true)
+})
+
+t.test('can log', async (t) => {
+ const explains = []
+ const { display, logs } = mockDisplay(t, {
+ npmlog: {
+ error: (...args) => logs.push(['error', ...args]),
+ warn: (...args) => logs.push(['warn', ...args]),
+ },
+ '../../../lib/utils/explain-eresolve.js': {
+ explain: (...args) => {
+ explains.push(args)
+ return 'explanation'
+ },
+ },
+ })
+
+ display.log('error', 'test')
+ t.match(logs.error, [['test']])
+
+ display.log('warn', 'ERESOLVE', 'hello', { some: 'object' })
+ t.match(logs.warn, [['ERESOLVE', 'hello']])
+ t.match(explains, [[{ some: 'object' }, false, 2]])
+})
+
+t.test('handles log throwing', async (t) => {
+ const errors = []
+ mockGlobals(t, {
+ 'console.error': (...args) => errors.push(args),
+ })
+ const { display } = mockDisplay(t, {
+ npmlog: {
+ verbose: () => {
+ throw new Error('verbose')
+ },
+ },
+ '../../../lib/utils/explain-eresolve.js': {
+ explain: () => {
+ throw new Error('explain')
+ },
+ },
+ })
+
+ display.log('warn', 'ERESOLVE', 'hello', { some: 'object' })
+ t.match(errors, [
+ [/attempt to log .* crashed/, Error('explain'), Error('verbose')],
+ ])
+})
diff --git a/test/lib/utils/error-message.js b/test/lib/utils/error-message.js
index 1959b9217..ddc88c1d9 100644
--- a/test/lib/utils/error-message.js
+++ b/test/lib/utils/error-message.js
@@ -1,87 +1,51 @@
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 { load: _loadMockNpm } = require('../../fixtures/mock-npm.js')
+const mockGlobals = require('../../fixtures/mock-globals.js')
+const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot.js')
+
+t.cleanSnapshot = p => cleanDate(cleanCwd(p))
+
+mockGlobals(t, {
+ process: {
+ getuid: () => 867,
+ getgid: () => 5309,
+ arch: 'x64',
+ version: '123.456.789-node',
+ platform: 'posix',
},
})
-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 = () => 867
-process.getgid = () => 5309
-
-Object.defineProperty(process, 'arch', {
- value: 'x64',
- configurable: true,
-})
-
-Object.defineProperty(process, 'version', {
- 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) => {
- verboseLogs.push(message)
-}
-
-const EXPLAIN_CALLED = []
-const mocks = {
- '../../../lib/utils/explain-eresolve.js': {
- report: (...args) => {
- EXPLAIN_CALLED.push(args)
- return 'explanation'
+const loadMockNpm = async (t, { load, command, testdir, config } = {}) => {
+ const { npm, ...rest } = await _loadMockNpm(t, {
+ load,
+ testdir,
+ config,
+ mocks: {
+ '../../package.json': {
+ version: '123.456.789-npm',
+ },
},
- },
- // XXX ???
- get '../../../lib/utils/is-windows.js' () {
- return process.platform === 'win32'
- },
-}
-let errorMessage = t.mock('../../../lib/utils/error-message.js', { ...mocks })
-
-const beWindows = () => {
- Object.defineProperty(process, 'platform', {
- value: 'win32',
- configurable: true,
})
- errorMessage = t.mock('../../../lib/utils/error-message.js', { ...mocks })
+ if (command !== undefined) {
+ npm.command = command
+ }
+ return {
+ npm,
+ ...rest,
+ }
}
-const bePosix = () => {
- Object.defineProperty(process, 'platform', {
- value: 'posix',
- configurable: true,
- })
- errorMessage = t.mock('../../../lib/utils/error-message.js', { ...mocks })
-}
+const errorMessage = (er, { mocks, logMocks, npm } = {}) =>
+ t.mock('../../../lib/utils/error-message.js', { ...mocks, ...logMocks })(er, npm)
-t.test('just simple messages', t => {
- npm.command = 'audit'
+t.test('just simple messages', async t => {
+ const npm = await loadMockNpm(t, {
+ command: 'audit',
+ config: {
+ 'node-version': '99.99.99',
+ },
+ })
const codes = [
'ENOAUDIT',
'ENOLOCK',
@@ -108,7 +72,7 @@ t.test('just simple messages', t => {
'ERR_SOCKET_TIMEOUT',
]
t.plan(codes.length)
- codes.forEach(code => {
+ codes.forEach(async code => {
const path = '/some/path'
const pkgid = 'some@package'
const file = '/some/file'
@@ -124,8 +88,8 @@ t.test('just simple messages', t => {
})
})
-t.test('replace message/stack sensistive info', t => {
- npm.command = 'audit'
+t.test('replace message/stack sensistive info', async t => {
+ const npm = await loadMockNpm(t, { command: 'audit' })
const path = '/some/path'
const pkgid = 'some@package'
const file = '/some/file'
@@ -139,10 +103,10 @@ t.test('replace message/stack sensistive info', t => {
stack,
})
t.matchSnapshot(errorMessage(er, npm))
- t.end()
})
-t.test('bad engine without config loaded', t => {
+t.test('bad engine without config loaded', async t => {
+ const npm = await loadMockNpm(t, { load: false })
const path = '/some/path'
const pkgid = 'some@package'
const file = '/some/file'
@@ -154,11 +118,11 @@ t.test('bad engine without config loaded', t => {
file,
stack,
})
- t.matchSnapshot(errorMessage(er, unloadedNpm))
- t.end()
+ t.matchSnapshot(errorMessage(er, npm))
})
-t.test('enoent without a file', t => {
+t.test('enoent without a file', async t => {
+ const npm = await loadMockNpm(t)
const path = '/some/path'
const pkgid = 'some@package'
const stack = 'dummy stack trace'
@@ -169,11 +133,10 @@ t.test('enoent without a file', t => {
stack,
})
t.matchSnapshot(errorMessage(er, npm))
- t.end()
})
-t.test('enolock without a command', t => {
- npm.command = null
+t.test('enolock without a command', async t => {
+ const npm = await loadMockNpm(t, { command: null })
const path = '/some/path'
const pkgid = 'some@package'
const file = '/some/file'
@@ -186,12 +149,12 @@ t.test('enolock without a command', t => {
stack,
})
t.matchSnapshot(errorMessage(er, npm))
- t.end()
})
-t.test('default message', t => {
+t.test('default message', async t => {
+ const npm = await loadMockNpm(t)
t.matchSnapshot(errorMessage(new Error('error object'), npm))
- t.matchSnapshot(errorMessage('error string'), npm)
+ t.matchSnapshot(errorMessage('error string', npm))
t.matchSnapshot(errorMessage(Object.assign(new Error('cmd err'), {
cmd: 'some command',
signal: 'SIGYOLO',
@@ -199,10 +162,10 @@ t.test('default message', t => {
stdout: 'stdout',
stderr: 'stderr',
}), npm))
- t.end()
})
-t.test('args are cleaned', t => {
+t.test('args are cleaned', async t => {
+ const npm = await loadMockNpm(t)
t.matchSnapshot(errorMessage(Object.assign(new Error('cmd err'), {
cmd: 'some command',
signal: 'SIGYOLO',
@@ -210,35 +173,25 @@ t.test('args are cleaned', t => {
stdout: 'stdout',
stderr: 'stderr',
}), npm))
- t.end()
})
-t.test('eacces/eperm', t => {
- const runTest = (windows, loaded, cachePath, cacheDest) => t => {
+t.test('eacces/eperm', async t => {
+ const runTest = (windows, loaded, cachePath, cacheDest) => async t => {
if (windows) {
- beWindows()
- } else {
- bePosix()
+ mockGlobals(t, { 'process.platform': 'win32' })
}
-
- const path = `${cachePath ? CACHE : '/not/cache/dir'}/path`
- const dest = `${cacheDest ? CACHE : '/not/cache/dir'}/dest`
+ const npm = await loadMockNpm(t, { windows, load: loaded })
+ const path = `${cachePath ? npm.cache : '/not/cache/dir'}/path`
+ const dest = `${cacheDest ? npm.cache : '/not/cache/dir'}/dest`
const er = Object.assign(new Error('whoopsie'), {
code: 'EACCES',
path,
dest,
stack: 'dummy stack trace',
})
- verboseLogs.length = 0
- if (loaded) {
- t.matchSnapshot(errorMessage(er, npm))
- } else {
- t.matchSnapshot(errorMessage(er, unloadedNpm))
- }
- t.matchSnapshot(verboseLogs)
- t.end()
- verboseLogs.length = 0
+ t.matchSnapshot(errorMessage(er, npm))
+ t.matchSnapshot(npm.logs.verbose)
}
for (const windows of [true, false]) {
@@ -251,12 +204,13 @@ t.test('eacces/eperm', t => {
}
}
}
- t.end()
})
t.test('json parse', t => {
- t.test('merge conflict in package.json', t => {
- const dir = t.testdir({
+ mockGlobals(t, { 'process.argv': ['arg', 'v'] })
+
+ t.test('merge conflict in package.json', async t => {
+ const testdir = {
'package.json': `
{
"array": [
@@ -295,59 +249,35 @@ t.test('json parse', t => {
}
}
`,
- })
- const { prefix } = npm
- const { argv } = process
- t.teardown(() => {
- Object.defineProperty(npm, 'prefix', {
- value: prefix,
- configurable: true,
- })
- process.argv = argv
- })
- Object.defineProperty(npm, 'prefix', { value: dir, configurable: true })
- process.argv = ['arg', 'v']
+ }
+ const npm = await loadMockNpm(t, { testdir })
t.matchSnapshot(errorMessage(Object.assign(new Error('conflicted'), {
code: 'EJSONPARSE',
- path: resolve(dir, 'package.json'),
+ path: path.resolve(npm.prefix, 'package.json'),
}), npm))
t.end()
})
- t.test('just regular bad json in package.json', t => {
- const dir = t.testdir({
+ t.test('just regular bad json in package.json', async t => {
+ const testdir = {
'package.json': 'not even slightly json',
- })
- const { prefix } = npm
- const { argv } = process
- t.teardown(() => {
- Object.defineProperty(npm, 'prefix', {
- value: prefix,
- configurable: true,
- })
- process.argv = argv
- })
- Object.defineProperty(npm, 'prefix', { value: dir, configurable: true })
- process.argv = ['arg', 'v']
+ }
+ const npm = await loadMockNpm(t, { testdir })
t.matchSnapshot(errorMessage(Object.assign(new Error('not json'), {
code: 'EJSONPARSE',
- path: resolve(dir, 'package.json'),
+ path: path.resolve(npm.prefix, 'package.json'),
}), npm))
t.end()
})
- t.test('json somewhere else', t => {
- const dir = t.testdir({
+ t.test('json somewhere else', async t => {
+ const testdir = {
'blerg.json': 'not even slightly json',
- })
- const { argv } = process
- t.teardown(() => {
- process.argv = argv
- })
- process.argv = ['arg', 'v']
+ }
+ const npm = await loadMockNpm(t, { testdir })
t.matchSnapshot(errorMessage(Object.assign(new Error('not json'), {
code: 'EJSONPARSE',
- path: `${dir}/blerg.json`,
+ path: path.resolve(npm.prefix, 'blerg.json'),
}), npm))
t.end()
})
@@ -355,7 +285,9 @@ t.test('json parse', t => {
t.end()
})
-t.test('eotp/e401', t => {
+t.test('eotp/e401', async t => {
+ const npm = await loadMockNpm(t)
+
t.test('401, no auth headers', t => {
t.matchSnapshot(errorMessage(Object.assign(new Error('nope'), {
code: 'E401',
@@ -406,11 +338,11 @@ t.test('eotp/e401', t => {
})
}
})
-
- t.end()
})
-t.test('404', t => {
+t.test('404', async t => {
+ const npm = await loadMockNpm(t)
+
t.test('no package id', t => {
const er = Object.assign(new Error('404 not found'), { code: 'E404' })
t.matchSnapshot(errorMessage(er, npm))
@@ -448,10 +380,11 @@ t.test('404', t => {
t.matchSnapshot(errorMessage(er, npm))
t.end()
})
- t.end()
})
-t.test('bad platform', t => {
+t.test('bad platform', async t => {
+ const npm = await loadMockNpm(t)
+
t.test('string os/arch', t => {
const er = Object.assign(new Error('a bad plat'), {
pkgid: 'lodash@1.0.0',
@@ -484,19 +417,30 @@ t.test('bad platform', t => {
t.matchSnapshot(errorMessage(er, npm))
t.end()
})
-
- t.end()
})
-t.test('explain ERESOLVE errors', t => {
+t.test('explain ERESOLVE errors', async t => {
+ const npm = await loadMockNpm(t)
+ const EXPLAIN_CALLED = []
+
const er = Object.assign(new Error('could not resolve'), {
code: 'ERESOLVE',
})
- t.matchSnapshot(errorMessage(er, npm))
+
+ t.matchSnapshot(errorMessage(er, {
+ ...npm,
+ mocks: {
+ '../../../lib/utils/explain-eresolve.js': {
+ report: (...args) => {
+ EXPLAIN_CALLED.push(args)
+ return 'explanation'
+ },
+ },
+ },
+ }))
t.match(EXPLAIN_CALLED, [[
er,
- undefined,
+ false,
path.resolve(npm.cache, 'eresolve-report.txt'),
]])
- t.end()
})
diff --git a/test/lib/utils/exit-handler.js b/test/lib/utils/exit-handler.js
index adc7c3f4e..54bf48f89 100644
--- a/test/lib/utils/exit-handler.js
+++ b/test/lib/utils/exit-handler.js
@@ -1,177 +1,213 @@
-/* eslint-disable no-extend-native */
-/* eslint-disable no-global-assign */
const t = require('tap')
-const EventEmitter = require('events')
const os = require('os')
-const fs = require('fs')
-const path = require('path')
-
-const { real: mockNpm } = require('../../fixtures/mock-npm')
-
-// generic error to be used in tests
-const err = Object.assign(new Error('ERROR'), { code: 'ERROR' })
-err.stack = 'Error: ERROR'
-
-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}')
+const EventEmitter = require('events')
+const { format } = require('../../../lib/utils/log-file')
+const { load: loadMockNpm } = require('../../fixtures/mock-npm')
+const mockGlobals = require('../../fixtures/mock-globals')
+const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot')
+
+const pick = (obj, ...keys) => keys.reduce((acc, key) => {
+ acc[key] = obj[key]
+ return acc
+}, {})
+
+t.formatSnapshot = (obj) => {
+ if (Array.isArray(obj)) {
+ return obj
+ .map((i) => Array.isArray(i) ? i.join(' ') : i)
+ .join('\n')
+ }
+ return obj
}
-t.cleanSnapshot = (str) => redactCwd(str)
-
-const cacheFolder = t.testdir({})
-const logFile = path.resolve(cacheFolder, '_logs', 'expecteddate-debug.log')
-const timingFile = path.resolve(cacheFolder, '_timing.json')
-
-const { Npm } = mockNpm(t, {
- '../../package.json': {
- version: '1.0.0',
- },
-})
-const npm = new Npm()
-
-t.before(async () => {
- await npm.load()
- npm.config.set('cache', cacheFolder)
-})
+t.cleanSnapshot = (path) => cleanDate(cleanCwd(path))
+// Config loading is dependent on env so strip those from snapshots
+ .replace(/.*timing config:load:.*\n/gm, '')
+ .replace(/(Completed in )\d+(ms)/g, '$1{TIME}$2')
// cut off process from script so that it won't quit the test runner
// while trying to run through the myriad of cases. need to make it
// have all the functions signal-exit relies on so that it doesn't
// nerf itself, thinking global.process is broken or gone.
-const _process = process
-process = Object.assign(
- new EventEmitter(),
- {
- argv: ['/node', ..._process.argv.slice(1)],
- cwd: _process.cwd,
- env: _process.env,
+mockGlobals(t, {
+ process: Object.assign(new EventEmitter(), {
+ ...pick(process, 'execPath', 'stdout', 'stderr', 'cwd', 'env'),
+ argv: ['/node', ...process.argv.slice(1)],
version: 'v1.0.0',
+ kill: () => {},
+ reallyExit: (code) => process.exit(code),
+ pid: 123456,
exit: (code) => {
process.exitCode = code || process.exitCode || 0
process.emit('exit', process.exitCode)
},
- stdout: { write (_, cb) {
- cb()
- } },
- stderr: { write () {} },
- hrtime: _process.hrtime,
- kill: () => {},
- reallyExit: (code) => process.exit(code),
- pid: 123456,
+ }),
+}, { replace: true })
+
+const mockExitHandler = async (t, { init, load, testdir, config } = {}) => {
+ const errors = []
+ mockGlobals(t, { 'console.error': (err) => errors.push(err) })
+
+ const { npm, logMocks, ...rest } = await loadMockNpm(t, {
+ init,
+ load,
+ testdir,
+ mocks: {
+ '../../package.json': {
+ version: '1.0.0',
+ },
+ },
+ config: {
+ loglevel: 'notice',
+ ...config,
+ },
+ })
+
+ const exitHandler = t.mock('../../../lib/utils/exit-handler.js', {
+ '../../../lib/utils/error-message.js': (err) => ({
+ ...err,
+ summary: [['ERR SUMMARY', err.message]],
+ detail: [['ERR DETAIL', err.message]],
+ }),
+ os: {
+ type: () => 'Foo',
+ release: () => '1.0.0',
+ },
+ ...logMocks,
+ })
+
+ if (npm) {
+ exitHandler.setNpm(npm)
}
-)
-
-const osType = os.type
-const osRelease = os.release
-// overrides OS type/release for cross platform snapshots
-os.type = () => 'Foo'
-os.release = () => '1.0.0'
-
-// generates logfile name with mocked date
-const _toISOString = Date.prototype.toISOString
-Date.prototype.toISOString = () => 'expecteddate'
-
-const consoleError = console.error
-const errors = []
-console.error = (err) => {
- errors.push(err)
-}
-t.teardown(() => {
- os.type = osType
- os.release = osRelease
- // needs to put process back in its place in order for tap to exit properly
- process = _process
- Date.prototype.toISOString = _toISOString
- console.error = consoleError
-})
-t.afterEach(() => {
- errors.length = 0
- npm.log.level = 'silent'
- // clear out the 'A complete log' message
- npm.log.record.length = 0
- delete process.exitCode
-})
+ t.teardown(() => {
+ delete process.exitCode
+ process.removeAllListeners('exit')
+ })
-const mocks = {
- '../../../lib/utils/error-message.js': (err) => ({
- ...err,
- summary: [['ERR', err.message]],
- detail: [['ERR', err.message]],
- }),
+ return {
+ ...rest,
+ errors,
+ npm,
+ // // Make it async to make testing ergonomics a little
+ // // easier so we dont need to t.plan() every test to
+ // // make sure we get process.exit called
+ exitHandler: (...args) => new Promise(resolve => {
+ process.once('exit', resolve)
+ exitHandler(...args)
+ }),
+ }
}
-const exitHandler = t.mock('../../../lib/utils/exit-handler.js', mocks)
-exitHandler.setNpm(npm)
-
-t.test('exit handler never called - loglevel silent', (t) => {
- npm.log.level = 'silent'
- process.emit('exit', 1)
- const logData = fs.readFileSync(logFile, 'utf8')
- t.match(logData, 'Exit handler never called!')
- t.match(errors, [''], 'logs one empty string to console.error')
- t.end()
-})
+// Create errors with properties to be used in tests
+const err = (message = '', options = {}, noStack = false) => {
+ const e = Object.assign(
+ new Error(message),
+ typeof options !== 'object' ? { code: options } : options
+ )
+ e.stack = options.stack || `Error: ${message}`
+ if (noStack) {
+ delete e.stack
+ }
+ return e
+}
-t.test('exit handler never called - loglevel notice', (t) => {
- npm.log.level = 'notice'
- process.emit('exit', 1)
- const logData = fs.readFileSync(logFile, 'utf8')
- t.match(logData, 'Exit handler never called!')
- t.match(errors, ['', ''], 'logs two empty strings to console.error')
- t.end()
-})
+t.test('handles unknown error with logs and debug file', async (t) => {
+ const { exitHandler, debugFile, logs } = await mockExitHandler(t)
-t.test('handles unknown error', (t) => {
- t.plan(2)
+ await exitHandler(err('Unknown error', 'ECODE'))
- npm.log.level = 'notice'
+ const debugContent = await debugFile()
- process.once('timeEnd', (msg) => {
- t.equal(msg, 'npm', 'should trigger timeEnd for npm')
+ t.equal(process.exitCode, 1)
+ logs.forEach((logItem, i) => {
+ const logLines = format(i, ...logItem).trim().split(os.EOL)
+ logLines.forEach((line) => {
+ t.match(debugContent.trim(), line, 'log appears in debug file')
+ })
})
- exitHandler(err)
- const logData = fs.readFileSync(logFile, 'utf8')
- t.matchSnapshot(
- logData,
- 'should have expected log contents for unknown error'
- )
- t.end()
+ const lastLog = debugContent
+ .split('\n')
+ .reduce((__, l) => parseInt(l.match(/^(\d+)\s/)[1]))
+ t.equal(logs.length, lastLog + 1)
+ t.match(logs.error, [
+ ['code', 'ECODE'],
+ ['ERR SUMMARY', 'Unknown error'],
+ ['ERR DETAIL', 'Unknown error'],
+ ])
+ t.match(debugContent, /\d+ error code ECODE/)
+ t.match(debugContent, /\d+ error ERR SUMMARY Unknown error/)
+ t.match(debugContent, /\d+ error ERR DETAIL Unknown error/)
+ t.matchSnapshot(logs, 'logs')
+ t.matchSnapshot(debugContent, 'debug file contents')
})
-t.test('fail to write logfile', (t) => {
- t.plan(1)
-
- t.teardown(() => {
- npm.config.set('cache', cacheFolder)
+t.test('exit handler never called - loglevel silent', async (t) => {
+ const { logs, errors } = await mockExitHandler(t, {
+ config: { loglevel: 'silent' },
})
+ process.emit('exit', 1)
+ t.match(logs.error, [
+ ['', /Exit handler never called/],
+ ['', /error with npm itself/],
+ ])
+ t.strictSame(errors, [''], 'logs one empty string to console.error')
+})
- const badDir = t.testdir({
- _logs: 'is a file',
- })
+t.test('exit handler never called - loglevel notice', async (t) => {
+ const { logs, errors } = await mockExitHandler(t)
+ process.emit('exit', 1)
+ t.equal(process.exitCode, 1)
+ t.match(logs.error, [
+ ['', /Exit handler never called/],
+ ['', /error with npm itself/],
+ ])
+ t.strictSame(errors, ['', ''], 'logs two empty strings to console.error')
+})
+
+t.test('exit handler never called - no npm', async (t) => {
+ const { logs, errors } = await mockExitHandler(t, { init: false })
+ process.emit('exit', 1)
+ t.equal(process.exitCode, 1)
+ t.match(logs.error, [
+ ['', /Exit handler never called/],
+ ['', /error with npm itself/],
+ ])
+ t.strictSame(errors, [''], 'logs one empty string to console.error')
+})
- npm.config.set('cache', badDir)
+t.test('exit handler called - no npm', async (t) => {
+ const { exitHandler, errors } = await mockExitHandler(t, { init: false })
+ await exitHandler()
+ t.equal(process.exitCode, 1)
+ t.match(errors, [/Error: Exit prior to setting npm in exit handler/])
+})
- t.doesNotThrow(
- () => exitHandler(err),
- 'should not throw on cache write failure'
- )
+t.test('exit handler called - no npm with error', async (t) => {
+ const { exitHandler, errors } = await mockExitHandler(t, { init: false })
+ await exitHandler(err('something happened'))
+ t.equal(process.exitCode, 1)
+ t.match(errors, [/Error: something happened/])
})
-t.test('console.log output using --json', (t) => {
- t.plan(1)
+t.test('exit handler called - no npm with error without stack', async (t) => {
+ const { exitHandler, errors } = await mockExitHandler(t, { init: false })
+ await exitHandler(err('something happened', {}, true))
+ t.equal(process.exitCode, 1)
+ t.match(errors, [/something happened/])
+})
- npm.config.set('json', true)
- t.teardown(() => {
- npm.config.set('json', false)
+t.test('console.log output using --json', async (t) => {
+ const { exitHandler, errors } = await mockExitHandler(t, {
+ config: {
+ json: true,
+ },
})
- exitHandler(new Error('Error: EBADTHING Something happened'))
+ await exitHandler(err('Error: EBADTHING Something happened'))
+
+ t.equal(process.exitCode, 1)
t.same(
JSON.parse(errors[0]),
{
@@ -185,213 +221,223 @@ t.test('console.log output using --json', (t) => {
)
})
-t.test('throw a non-error obj', (t) => {
- t.plan(2)
+t.test('throw a non-error obj', async (t) => {
+ const { exitHandler, logs } = await mockExitHandler(t)
- const weirdError = {
+ await exitHandler({
code: 'ESOMETHING',
message: 'foo bar',
- }
-
- process.once('exit', code => {
- t.equal(code, 1, 'exits with exitCode 1')
})
- exitHandler(weirdError)
- t.match(
- npm.log.record.find(r => r.level === 'error'),
- { message: 'foo bar' }
- )
+
+ t.equal(process.exitCode, 1)
+ t.match(logs.error, [
+ ['weird error', { code: 'ESOMETHING', message: 'foo bar' }],
+ ])
})
-t.test('throw a string error', (t) => {
- t.plan(2)
- const error = 'foo bar'
+t.test('throw a string error', async (t) => {
+ const { exitHandler, logs } = await mockExitHandler(t)
- process.once('exit', code => {
- t.equal(code, 1, 'exits with exitCode 1')
- })
- exitHandler(error)
- t.match(
- npm.log.record.find(r => r.level === 'error'),
- { message: 'foo bar' }
- )
+ await exitHandler('foo bar')
+
+ t.equal(process.exitCode, 1)
+ t.match(logs.error, [
+ ['', 'foo bar'],
+ ])
})
-t.test('update notification', (t) => {
- const updateMsg = 'you should update npm!'
- npm.updateNotification = updateMsg
- npm.log.level = 'silent'
+t.test('update notification', async (t) => {
+ const { exitHandler, logs, npm } = await mockExitHandler(t)
+ npm.updateNotification = 'you should update npm!'
- t.teardown(() => {
- delete npm.updateNotification
- })
+ await exitHandler()
- exitHandler()
- t.match(
- npm.log.record.find(r => r.level === 'notice'),
- { message: 'you should update npm!' }
- )
- t.end()
+ t.match(logs.notice, [
+ ['', 'you should update npm!'],
+ ])
})
-t.test('npm.config not ready', (t) => {
- t.plan(1)
+t.test('npm.config not ready', async (t) => {
+ const { exitHandler, logs, errors } = await mockExitHandler(t, {
+ load: false,
+ })
- const { Npm: Unloaded } = mockNpm(t)
- const unloaded = new Unloaded()
+ await exitHandler()
- t.teardown(() => {
- exitHandler.setNpm(npm)
+ t.equal(process.exitCode, 1)
+ t.match(errors, [
+ /Error: Exit prior to config file resolving./,
+ ], 'should exit with config error msg')
+ t.match(logs.verbose, [
+ ['stack', /Error: Exit prior to config file resolving./],
+ ], 'should exit with config error msg')
+})
+
+t.test('timing with no error', async (t) => {
+ const { exitHandler, timingFile, npm, logs } = await mockExitHandler(t, {
+ config: {
+ timing: true,
+ },
})
- exitHandler.setNpm(unloaded)
+ await exitHandler()
+ const timingFileData = await timingFile()
+
+ t.equal(process.exitCode, 0)
+
+ t.match(logs.error, [
+ ['', /A complete log of this run can be found in:[\s\S]*-debug-\d\.log/],
+ ])
- exitHandler()
t.match(
- errors[0],
- /Error: Exit prior to config file resolving./,
- 'should exit with config error msg'
+ timingFileData,
+ Object.keys(npm.finishedTimers).reduce((acc, k) => {
+ acc[k] = Number
+ return acc
+ }, {})
)
- t.end()
+ t.strictSame(npm.unfinishedTimers, new Map())
+ t.match(timingFileData, {
+ command: [],
+ version: '1.0.0',
+ npm: Number,
+ logfile: String,
+ logfiles: [String],
+ })
})
-t.test('timing', (t) => {
- npm.config.set('timing', true)
-
- t.teardown(() => {
- fs.unlinkSync(timingFile)
- npm.config.set('timing', false)
+t.test('unfinished timers', async (t) => {
+ const { exitHandler, timingFile, npm } = await mockExitHandler(t, {
+ config: {
+ timing: true,
+ },
})
- exitHandler()
- const timingData = JSON.parse(fs.readFileSync(timingFile, 'utf8'))
- t.match(timingData, { version: '1.0.0', 'config:load:defaults': Number })
- t.end()
-})
+ process.emit('time', 'foo')
+ process.emit('time', 'bar')
-t.test('timing - with error', (t) => {
- npm.config.set('timing', true)
+ await exitHandler()
+ const timingFileData = await timingFile()
- t.teardown(() => {
- fs.unlinkSync(timingFile)
- npm.config.set('timing', false)
+ t.equal(process.exitCode, 0)
+ t.match(npm.unfinishedTimers, new Map([['foo', Number], ['bar', Number]]))
+ t.match(timingFileData, {
+ command: [],
+ version: '1.0.0',
+ npm: Number,
+ logfile: String,
+ logfiles: [String],
+ unfinished: {
+ foo: [Number, Number],
+ bar: [Number, Number],
+ },
})
-
- exitHandler(err)
- const timingData = JSON.parse(fs.readFileSync(timingFile, 'utf8'))
- t.match(timingData, { version: '1.0.0', 'config:load:defaults': Number })
- t.end()
})
-t.test('uses code from errno', (t) => {
- t.plan(1)
+t.test('uses code from errno', async (t) => {
+ const { exitHandler, logs } = await mockExitHandler(t)
- process.once('exit', code => {
- t.equal(code, 127, 'should set exitCode from errno')
- })
- exitHandler(Object.assign(
- new Error('Error with errno'),
- {
- errno: 127,
- }
- ))
+ await exitHandler(err('Error with errno', { errno: 127 }))
+ t.equal(process.exitCode, 127)
+ t.match(logs.error, [['errno', 127]])
})
-t.test('uses code from number', (t) => {
- t.plan(1)
+t.test('uses code from number', async (t) => {
+ const { exitHandler, logs } = await mockExitHandler(t)
- process.once('exit', code => {
- t.equal(code, 404, 'should set exitCode from a number')
- })
- exitHandler(Object.assign(
- new Error('Error with code type number'),
- {
- code: 404,
- }
- ))
+ await exitHandler(err('Error with code type number', 404))
+ t.equal(process.exitCode, 404)
+ t.match(logs.error, [['code', 404]])
})
-t.test('call exitHandler with no error', (t) => {
- t.plan(1)
- process.once('exit', code => {
- t.equal(code, 0, 'should end up with exitCode 0 (default)')
- })
- exitHandler()
+t.test('uses all err special properties', async t => {
+ const { exitHandler, logs } = await mockExitHandler(t)
+
+ const keys = ['code', 'syscall', 'file', 'path', 'dest', 'errno']
+ const properties = keys.reduce((acc, k) => {
+ acc[k] = `${k}-hey`
+ return acc
+ }, {})
+
+ await exitHandler(err('Error with code type number', properties))
+ t.equal(process.exitCode, 1)
+ t.match(logs.error, keys.map((k) => [k, `${k}-hey`]), 'all special keys get logged')
})
-t.test('defaults to log error msg if stack is missing', (t) => {
- const { Npm: Unloaded } = mockNpm(t)
- const unloaded = new Unloaded()
+t.test('verbose logs replace info on err props', async t => {
+ const { exitHandler, logs } = await mockExitHandler(t)
- t.teardown(() => {
- exitHandler.setNpm(npm)
- })
+ const keys = ['type', 'stack', 'statusCode', 'pkgid']
+ const properties = keys.reduce((acc, k) => {
+ acc[k] = `${k}-https://user:pass@registry.npmjs.org/`
+ return acc
+ }, {})
- exitHandler.setNpm(unloaded)
- const noStackErr = Object.assign(
- new Error('Error with no stack'),
- {
- code: 'ENOSTACK',
- errno: 127,
- }
+ await exitHandler(err('Error with code type number', properties))
+ t.equal(process.exitCode, 1)
+ t.match(
+ logs.verbose.filter(([p]) => p !== 'logfile'),
+ keys.map((k) => [k, `${k}-https://user:***@registry.npmjs.org/`]),
+ 'all special keys get replaced'
)
- delete noStackErr.stack
+})
- exitHandler(noStackErr)
- t.equal(errors[0], 'Error with no stack', 'should use error msg')
- t.end()
+t.test('call exitHandler with no error', async (t) => {
+ const { exitHandler, logs } = await mockExitHandler(t)
+
+ await exitHandler()
+
+ t.equal(process.exitCode, 0)
+ t.match(logs.error, [])
+})
+
+t.test('defaults to log error msg if stack is missing when unloaded', async (t) => {
+ const { exitHandler, logs, errors } = await mockExitHandler(t, { load: false })
+
+ await exitHandler(err('Error with no stack', { code: 'ENOSTACK', errno: 127 }, true))
+ t.equal(process.exitCode, 127)
+ t.same(errors, ['Error with no stack'], 'should use error msg')
+ t.match(logs.error, [
+ ['code', 'ENOSTACK'],
+ ['errno', 127],
+ ])
})
-t.test('exits uncleanly when only emitting exit event', (t) => {
- t.plan(2)
+t.test('exits uncleanly when only emitting exit event', async (t) => {
+ const { logs } = await mockExitHandler(t)
- npm.log.level = 'silent'
process.emit('exit')
- const logData = fs.readFileSync(logFile, 'utf8')
- t.match(logData, 'Exit handler never called!')
- t.match(process.exitCode, 1, 'exitCode coerced to 1')
+
+ t.match(logs.error, [['', 'Exit handler never called!']])
+ t.equal(process.exitCode, 1, 'exitCode coerced to 1')
t.end()
})
-t.test('do no fancy handling for shellouts', t => {
- const { command } = npm
- const LOG_RECORD = []
- npm.command = 'exec'
+t.test('do no fancy handling for shellouts', async t => {
+ const { exitHandler, npm, logs } = await mockExitHandler(t)
- t.teardown(() => {
- npm.command = command
- })
- t.beforeEach(() => LOG_RECORD.length = 0)
+ npm.command = 'exec'
- const loudNoises = () => npm.log.record
- .filter(({ level }) => ['warn', 'error'].includes(level))
+ const loudNoises = () =>
+ logs.filter(([level]) => ['warn', 'error'].includes(level))
- t.test('shellout with a numeric error code', t => {
- t.plan(2)
- process.once('exit', code => {
- t.equal(code, 5, 'got expected exit code')
- })
- exitHandler(Object.assign(new Error(), { code: 5 }))
+ t.test('shellout with a numeric error code', async t => {
+ await exitHandler(err('', 5))
+ t.equal(process.exitCode, 5, 'got expected exit code')
t.strictSame(loudNoises(), [], 'no noisy warnings')
})
- t.test('shellout without a numeric error code (something in npm)', t => {
- t.plan(2)
- process.once('exit', code => {
- t.equal(code, 1, 'got expected exit code')
- })
- exitHandler(Object.assign(new Error(), { code: 'banana stand' }))
+ t.test('shellout without a numeric error code (something in npm)', async t => {
+ await exitHandler(err('', 'banana stand'))
+ t.equal(process.exitCode, 1, 'got expected exit code')
// should log some warnings and errors, because something weird happened
t.strictNotSame(loudNoises(), [], 'bring the noise')
t.end()
})
- t.test('shellout with code=0 (extra weird?)', t => {
- t.plan(2)
- process.once('exit', code => {
- t.equal(code, 1, 'got expected exit code')
- })
- exitHandler(Object.assign(new Error(), { code: 0 }))
+ t.test('shellout with code=0 (extra weird?)', async t => {
+ await exitHandler(Object.assign(new Error(), { code: 0 }))
+ t.equal(process.exitCode, 1, 'got expected exit code')
t.strictNotSame(loudNoises(), [], 'bring the noise')
})
diff --git a/test/lib/utils/is-windows-bash.js b/test/lib/utils/is-windows-bash.js
index 94fde0ace..0fbebdf8e 100644
--- a/test/lib/utils/is-windows-bash.js
+++ b/test/lib/utils/is-windows-bash.js
@@ -1,4 +1,5 @@
const t = require('tap')
+const mockGlobal = require('../../fixtures/mock-globals.js')
const isWindowsBash = () => {
delete require.cache[require.resolve('../../../lib/utils/is-windows-bash.js')]
@@ -6,23 +7,24 @@ const isWindowsBash = () => {
return require('../../../lib/utils/is-windows-bash.js')
}
-Object.defineProperty(process, 'platform', {
- value: 'posix',
- configurable: true,
-})
-t.equal(isWindowsBash(), false, 'false when not windows')
+t.test('posix', (t) => {
+ mockGlobal(t, { 'process.platform': 'posix' })
+ t.equal(isWindowsBash(), false, 'false when not windows')
-Object.defineProperty(process, 'platform', {
- value: 'win32',
- configurable: true,
+ t.end()
})
-process.env.MSYSTEM = 'not ming'
-process.env.TERM = 'dumb'
-t.equal(isWindowsBash(), false, 'false when not mingw or cygwin')
-process.env.TERM = 'cygwin'
-t.equal(isWindowsBash(), true, 'true when cygwin')
+t.test('win32', (t) => {
+ mockGlobal(t, { 'process.platform': 'win32' })
+
+ mockGlobal(t, { 'process.env': { TERM: 'dumb', MSYSTEM: undefined } })
+ t.equal(isWindowsBash(), false, 'false when not mingw or cygwin')
+
+ mockGlobal(t, { 'process.env.TERM': 'cygwin' })
+ t.equal(isWindowsBash(), true, 'true when cygwin')
-process.env.MSYSTEM = 'MINGW64'
-process.env.TERM = 'dumb'
-t.equal(isWindowsBash(), true, 'true when mingw')
+ mockGlobal(t, { 'process.env': { TERM: 'dumb', MSYSTEM: 'MINGW64' } })
+ t.equal(isWindowsBash(), true, 'true when mingw')
+
+ t.end()
+})
diff --git a/test/lib/utils/log-file.js b/test/lib/utils/log-file.js
new file mode 100644
index 000000000..adc1a2e03
--- /dev/null
+++ b/test/lib/utils/log-file.js
@@ -0,0 +1,333 @@
+const t = require('tap')
+const _fs = require('fs')
+const fs = _fs.promises
+const path = require('path')
+const os = require('os')
+const fsMiniPass = require('fs-minipass')
+const rimraf = require('rimraf')
+const LogFile = require('../../../lib/utils/log-file.js')
+const { cleanCwd } = require('../../fixtures/clean-snapshot')
+
+t.cleanSnapshot = (path) => cleanCwd(path)
+
+const last = arr => arr[arr.length - 1]
+const range = (n) => Array.from(Array(n).keys())
+const makeOldLogs = (count) => {
+ const d = new Date()
+ d.setHours(-1)
+ d.setSeconds(0)
+ return range(count / 2).reduce((acc, i) => {
+ const cloneDate = new Date(d.getTime())
+ cloneDate.setSeconds(i)
+ acc[LogFile.fileName(LogFile.logId(cloneDate), 0)] = 'hello'
+ acc[LogFile.fileName(LogFile.logId(cloneDate), 1)] = 'hello'
+ return acc
+ }, {})
+}
+
+const cleanErr = (message) => {
+ const err = new Error(message)
+ const stack = err.stack.split('\n')
+ err.stack = stack[0] + '\n' + range(10)
+ .map((__, i) => stack[1].replace(/^(\s+at\s).*/, `$1stack trace line ${i}`))
+ .join('\n')
+ return err
+}
+
+const loadLogFile = async (t, { buffer = [], mocks, testdir = {}, ...options } = {}) => {
+ const root = t.testdir(testdir)
+ const MockLogFile = t.mock('../../../lib/utils/log-file.js', mocks)
+ const logFile = new MockLogFile(Object.keys(options).length ? options : undefined)
+ buffer.forEach((b) => logFile.log(...b))
+ await logFile.load({ dir: root, ...options })
+ t.teardown(() => logFile.off())
+ return {
+ root,
+ logFile,
+ LogFile,
+ readLogs: async () => {
+ const logDir = await fs.readdir(root)
+ const logFiles = logDir.map((f) => path.join(root, f))
+ .filter((f) => _fs.existsSync(f))
+ return Promise.all(logFiles.map(async (f) => {
+ const content = await fs.readFile(f, 'utf8')
+ const rawLogs = content.split(os.EOL)
+ return {
+ filename: f,
+ content,
+ rawLogs,
+ logs: rawLogs.filter(Boolean),
+ }
+ }))
+ },
+ }
+}
+
+t.test('init', async t => {
+ const maxLogsPerFile = 10
+ const { root, logFile, readLogs } = await loadLogFile(t, {
+ maxLogsPerFile,
+ maxFilesPerProcess: 20,
+ buffer: [['error', 'buffered']],
+ })
+
+ for (const i of range(50)) {
+ logFile.log('error', `log ${i}`)
+ }
+
+ // Ignored
+ logFile.log('pause')
+ logFile.log('resume')
+ logFile.log('pause')
+
+ for (const i of range(50)) {
+ logFile.log('verb', `log ${i}`)
+ }
+
+ logFile.off()
+ logFile.log('error', 'ignored')
+
+ const logs = await readLogs()
+ t.equal(logs.length, 11, 'total log files')
+ t.ok(logs.slice(0, 10).every(f => f.logs.length === maxLogsPerFile), 'max logs per file')
+ t.ok(last(logs).logs.length, 1, 'last file has remaining logs')
+ t.ok(logs.every(f => last(f.rawLogs) === ''), 'all logs end with newline')
+ t.strictSame(
+ logFile.files,
+ logs.map((l) => path.resolve(root, l.filename))
+ )
+})
+
+t.test('max files per process', async t => {
+ const maxLogsPerFile = 10
+ const maxFilesPerProcess = 5
+ const { logFile, readLogs } = await loadLogFile(t, {
+ maxLogsPerFile,
+ maxFilesPerProcess,
+ })
+
+ for (const i of range(maxLogsPerFile * maxFilesPerProcess)) {
+ logFile.log('error', `log ${i}`)
+ }
+
+ for (const i of range(5)) {
+ logFile.log('verbose', `log ${i}`)
+ }
+
+ const logs = await readLogs()
+ t.equal(logs.length, maxFilesPerProcess, 'total log files')
+ t.equal(last(last(logs).logs), '49 error log 49')
+})
+
+t.test('stream error', async t => {
+ let times = 0
+ const { logFile, readLogs } = await loadLogFile(t, {
+ maxLogsPerFile: 1,
+ maxFilesPerProcess: 99,
+ mocks: {
+ 'fs-minipass': {
+ WriteStreamSync: class {
+ constructor (...args) {
+ if (times >= 5) {
+ throw new Error('bad stream')
+ }
+ times++
+ return new fsMiniPass.WriteStreamSync(...args)
+ }
+ },
+ },
+ },
+ })
+
+ for (const i of range(10)) {
+ logFile.log('verbose', `log ${i}`)
+ }
+
+ const logs = await readLogs()
+ t.equal(logs.length, 5, 'total log files')
+})
+
+t.test('initial stream error', async t => {
+ const { logFile, readLogs } = await loadLogFile(t, {
+ mocks: {
+ 'fs-minipass': {
+ WriteStreamSync: class {
+ constructor (...args) {
+ throw new Error('no stream')
+ }
+ },
+ },
+ },
+ })
+
+ for (const i of range(10)) {
+ logFile.log('verbose', `log ${i}`)
+ }
+
+ const logs = await readLogs()
+ t.equal(logs.length, 0, 'total log files')
+})
+
+t.test('turns off', async t => {
+ const { logFile, readLogs } = await loadLogFile(t)
+
+ logFile.log('error', 'test')
+ logFile.off()
+ logFile.log('error', 'test2')
+ logFile.load()
+
+ const logs = await readLogs()
+ t.equal(logs.length, 1)
+ t.equal(logs[0].logs[0], '0 error test')
+})
+
+t.test('cleans logs', async t => {
+ const logsMax = 5
+ const { readLogs } = await loadLogFile(t, {
+ logsMax,
+ testdir: makeOldLogs(10),
+ })
+
+ const logs = await readLogs()
+ t.equal(logs.length, logsMax + 1)
+})
+
+t.test('doesnt clean current log by default', async t => {
+ const logsMax = 0
+ const { readLogs, logFile } = await loadLogFile(t, {
+ logsMax,
+ testdir: makeOldLogs(10),
+ })
+
+ logFile.log('error', 'test')
+
+ const logs = await readLogs()
+ t.equal(logs.length, 1)
+ t.match(last(logs).content, /\d+ error test/)
+})
+
+t.test('negative logs max', async t => {
+ const logsMax = -10
+ const { readLogs, logFile } = await loadLogFile(t, {
+ logsMax,
+ testdir: makeOldLogs(10),
+ })
+
+ logFile.log('error', 'test')
+
+ const logs = await readLogs()
+ t.equal(logs.length, 1)
+ t.match(last(logs).content, /\d+ error test/)
+})
+
+t.test('doesnt need to clean', async t => {
+ const logsMax = 20
+ const oldLogs = 10
+ const { readLogs } = await loadLogFile(t, {
+ logsMax,
+ testdir: makeOldLogs(oldLogs),
+ })
+
+ const logs = await readLogs()
+ t.equal(logs.length, oldLogs + 1)
+})
+
+t.test('glob error', async t => {
+ const { readLogs } = await loadLogFile(t, {
+ logsMax: 5,
+ mocks: {
+ glob: () => {
+ throw new Error('bad glob')
+ },
+ },
+ })
+
+ const logs = await readLogs()
+ t.equal(logs.length, 1)
+ t.match(last(logs).content, /error cleaning log files .* bad glob/)
+})
+
+t.test('rimraf error', async t => {
+ const logsMax = 5
+ const oldLogs = 10
+ let count = 0
+ const { readLogs } = await loadLogFile(t, {
+ logsMax,
+ testdir: makeOldLogs(oldLogs),
+ mocks: {
+ rimraf: (...args) => {
+ if (count >= 3) {
+ throw new Error('bad rimraf')
+ }
+ count++
+ return rimraf(...args)
+ },
+ },
+ })
+
+ const logs = await readLogs()
+ t.equal(logs.length, oldLogs - 3 + 1)
+ t.match(last(logs).content, /error removing log file .* bad rimraf/)
+})
+
+t.test('delete log file while open', async t => {
+ const { logFile, root, readLogs } = await loadLogFile(t)
+
+ logFile.log('error', '', 'log 1')
+ const [log] = await readLogs(true)
+ t.match(log.content, /\d+ error log 1/)
+
+ await fs.unlink(path.resolve(root, log.filename))
+
+ logFile.log('error', '', 'log 2')
+ const logs = await readLogs()
+
+ // XXX: do some retry logic after error?
+ t.strictSame(logs, [], 'logs arent written after error')
+})
+
+t.test('snapshot', async t => {
+ const { logFile, readLogs } = await loadLogFile(t)
+
+ logFile.log('error', '', 'no prefix')
+ logFile.log('error', 'prefix', 'with prefix')
+ logFile.log('error', 'prefix', 1, 2, 3)
+
+ const nestedObj = { obj: { with: { many: { props: 1 } } } }
+ logFile.log('verbose', '', nestedObj)
+ logFile.log('verbose', '', JSON.stringify(nestedObj))
+ logFile.log('verbose', '', JSON.stringify(nestedObj, null, 2))
+
+ const arr = ['test', 'with', 'an', 'array']
+ logFile.log('verbose', '', arr)
+ logFile.log('verbose', '', JSON.stringify(arr))
+ logFile.log('verbose', '', JSON.stringify(arr, null, 2))
+
+ const nestedArr = ['test', ['with', ['an', ['array']]]]
+ logFile.log('verbose', '', nestedArr)
+ logFile.log('verbose', '', JSON.stringify(nestedArr))
+ logFile.log('verbose', '', JSON.stringify(nestedArr, null, 2))
+
+ // XXX: multiple errors are hard to parse visually
+ // the second error should start on a newline
+ logFile.log(...[
+ 'error',
+ 'pre',
+ 'has',
+ 'many',
+ 'errors',
+ cleanErr('message'),
+ cleanErr('message2'),
+ ])
+
+ const err = new Error('message')
+ delete err.stack
+ logFile.log(...[
+ 'error',
+ 'nostack',
+ err,
+ ])
+
+ const logs = await readLogs()
+ t.matchSnapshot(logs.map(l => l.content).join('\n'))
+})
diff --git a/test/lib/utils/log-shim.js b/test/lib/utils/log-shim.js
new file mode 100644
index 000000000..dee4efbaa
--- /dev/null
+++ b/test/lib/utils/log-shim.js
@@ -0,0 +1,100 @@
+const t = require('tap')
+
+const makeShim = (mocks) => t.mock('../../../lib/utils/log-shim.js', mocks)
+
+const loggers = [
+ 'notice',
+ 'error',
+ 'warn',
+ 'info',
+ 'verbose',
+ 'http',
+ 'silly',
+ 'pause',
+ 'resume',
+]
+
+t.test('has properties', (t) => {
+ const shim = makeShim()
+
+ t.match(shim, {
+ level: String,
+ levels: {},
+ gauge: {},
+ stream: {},
+ heading: undefined,
+ enableColor: Function,
+ disableColor: Function,
+ enableUnicode: Function,
+ disableUnicode: Function,
+ enableProgress: Function,
+ disableProgress: Function,
+ ...loggers.reduce((acc, l) => {
+ acc[l] = Function
+ return acc
+ }, {}),
+ })
+
+ t.match(Object.keys(shim).sort(), [
+ 'level',
+ 'heading',
+ 'levels',
+ 'gauge',
+ 'stream',
+ 'tracker',
+ 'useColor',
+ 'enableColor',
+ 'disableColor',
+ 'enableUnicode',
+ 'disableUnicode',
+ 'enableProgress',
+ 'disableProgress',
+ 'progressEnabled',
+ 'clearProgress',
+ 'showProgress',
+ 'newItem',
+ 'newGroup',
+ ...loggers,
+ ].sort())
+
+ t.end()
+})
+
+t.test('works with npmlog/proclog proxy', t => {
+ const procLog = { silly: () => 'SILLY' }
+ const npmlog = { level: 'woo', enableColor: () => true }
+ const shim = makeShim({ npmlog, 'proc-log': procLog })
+
+ t.equal(shim.level, 'woo', 'can get a property')
+
+ npmlog.level = 'hey'
+ t.strictSame(
+ [shim.level, npmlog.level],
+ ['hey', 'hey'],
+ 'can get a property after update on npmlog'
+ )
+
+ shim.level = 'test'
+ t.strictSame(
+ [shim.level, npmlog.level],
+ ['test', 'test'],
+ 'can get a property after update on shim'
+ )
+
+ t.ok(shim.enableColor(), 'can call method on shim to call npmlog')
+ t.equal(shim.silly(), 'SILLY', 'can call method on proclog')
+ t.notOk(shim.LEVELS, 'only includes levels from npmlog')
+ t.throws(() => shim.gauge = 100, 'cant set getters properies')
+
+ t.end()
+})
+
+t.test('works with npmlog/proclog proxy', t => {
+ const shim = makeShim()
+
+ loggers.forEach((k) => {
+ t.doesNotThrow(() => shim[k]('test'))
+ })
+
+ t.end()
+})
diff --git a/test/lib/utils/npm-usage.js b/test/lib/utils/npm-usage.js
index 77254a80d..035d4bbb2 100644
--- a/test/lib/utils/npm-usage.js
+++ b/test/lib/utils/npm-usage.js
@@ -1,10 +1,8 @@
const t = require('tap')
-const { real: mockNpm } = require('../../fixtures/mock-npm.js')
-const { Npm } = mockNpm(t)
-const npm = new Npm()
+const { load: loadMockNpm } = require('../../fixtures/mock-npm.js')
t.test('usage', async t => {
- await npm.load()
+ const { npm } = await loadMockNpm(t)
t.afterEach(() => {
npm.config.set('viewer', null)
npm.config.set('long', false)
diff --git a/test/lib/utils/proc-log-listener.js b/test/lib/utils/proc-log-listener.js
deleted file mode 100644
index d580defa8..000000000
--- a/test/lib/utils/proc-log-listener.js
+++ /dev/null
@@ -1,41 +0,0 @@
-const t = require('tap')
-const { inspect } = require('util')
-
-const logs = []
-const npmlog = {
- warn: (...args) => logs.push(['warn', ...args]),
- verbose: (...args) => logs.push(['verbose', ...args]),
-}
-
-t.mock('../../../lib/utils/proc-log-listener.js', {
- npmlog,
-})()
-
-process.emit('log', 'warn', 'hello', 'i am a warning')
-t.strictSame(logs, [['warn', 'hello', 'i am a warning']])
-logs.length = 0
-
-const nopeError = new Error('nope')
-npmlog.warn = () => {
- throw nopeError
-}
-
-process.emit('log', 'warn', 'fail')
-t.strictSame(logs, [[
- 'verbose',
- `attempt to log ${inspect(['warn', 'fail'])} crashed`,
- nopeError,
-]])
-logs.length = 0
-
-npmlog.verbose = () => {
- throw nopeError
-}
-const consoleErrors = []
-console.error = (...args) => consoleErrors.push(args)
-process.emit('log', 'warn', 'fail2')
-t.strictSame(logs, [])
-t.strictSame(consoleErrors, [[
- `attempt to log ${inspect(['warn', 'fail2'])} crashed`,
- nopeError,
-]])
diff --git a/test/lib/utils/pulse-till-done.js b/test/lib/utils/pulse-till-done.js
index acbf66396..9f7a94614 100644
--- a/test/lib/utils/pulse-till-done.js
+++ b/test/lib/utils/pulse-till-done.js
@@ -1,18 +1,17 @@
const t = require('tap')
let pulseStarted = null
-const npmlog = {
- gauge: {
- pulse: () => {
- if (pulseStarted) {
- pulseStarted()
- }
- },
- },
-}
const pulseTillDone = t.mock('../../../lib/utils/pulse-till-done.js', {
- npmlog,
+ npmlog: {
+ gauge: {
+ pulse: () => {
+ if (pulseStarted) {
+ pulseStarted()
+ }
+ },
+ },
+ },
})
t.test('pulses (with promise)', async (t) => {
diff --git a/test/lib/utils/read-user-info.js b/test/lib/utils/read-user-info.js
index 35101f1d7..be805a2a8 100644
--- a/test/lib/utils/read-user-info.js
+++ b/test/lib/utils/read-user-info.js
@@ -7,11 +7,6 @@ const read = (opts, cb) => {
return cb(null, readResult)
}
-const npmlog = {
- clearProgress: () => {},
- showProgress: () => {},
-}
-
const npmUserValidate = {
username: (username) => {
if (username === 'invalid') {
@@ -29,12 +24,23 @@ const npmUserValidate = {
},
}
+let logMsg = null
const readUserInfo = t.mock('../../../lib/utils/read-user-info.js', {
read,
- npmlog,
+ npmlog: {
+ clearProgress: () => {},
+ showProgress: () => {},
+ },
+ 'proc-log': {
+ warn: (msg) => logMsg = msg,
+ },
'npm-user-validate': npmUserValidate,
})
+t.beforeEach(() => {
+ logMsg = null
+})
+
t.test('otp', async (t) => {
readResult = '1234'
t.teardown(() => {
@@ -75,11 +81,7 @@ t.test('username - invalid warns and retries', async (t) => {
readOpts = null
})
- let logMsg
- const log = {
- warn: (msg) => logMsg = msg,
- }
- const pResult = readUserInfo.username(null, null, { log })
+ const pResult = readUserInfo.username(null, null)
// have to swap it to a valid username after execution starts
// or it will loop forever
readResult = 'valid'
@@ -105,11 +107,7 @@ t.test('email - invalid warns and retries', async (t) => {
readOpts = null
})
- let logMsg
- const log = {
- warn: (msg) => logMsg = msg,
- }
- const pResult = readUserInfo.email(null, null, { log })
+ const pResult = readUserInfo.email(null, null)
readResult = 'foo@bar.baz'
const result = await pResult
t.equal(result, 'foo@bar.baz', 'received the email')
diff --git a/test/lib/utils/reify-output.js b/test/lib/utils/reify-output.js
index 9a1bffb40..4e9ed7133 100644
--- a/test/lib/utils/reify-output.js
+++ b/test/lib/utils/reify-output.js
@@ -1,7 +1,9 @@
const t = require('tap')
+const log = require('../../../lib/utils/log-shim')
-const log = require('npmlog')
-log.level = 'warn'
+const _level = log.level
+t.beforeEach(() => log.level = 'warn')
+t.teardown(() => log.level = _level)
t.cleanSnapshot = str => str.replace(/in [0-9]+m?s/g, 'in {TIME}')
@@ -237,7 +239,6 @@ t.test('showing and not showing audit report', async t => {
npm.output = out => {
t.fail('should not get output when silent', { actual: out })
}
- t.teardown(() => log.level = 'warn')
log.level = 'silent'
reifyOutput(npm, {
actualTree: { inventory: { size: 999 }, children: [] },
diff --git a/test/lib/utils/setup-log.js b/test/lib/utils/setup-log.js
deleted file mode 100644
index 7f907bc7e..000000000
--- a/test/lib/utils/setup-log.js
+++ /dev/null
@@ -1,296 +0,0 @@
-const t = require('tap')
-
-const settings = {
- level: 'warn',
-}
-t.afterEach(() => {
- Object.keys(settings).forEach(k => {
- delete settings[k]
- })
-})
-
-const WARN_CALLED = []
-const npmlog = {
- warn: (...args) => {
- WARN_CALLED.push(args)
- },
- levels: {
- silly: -Infinity,
- verbose: 1000,
- info: 2000,
- timing: 2500,
- http: 3000,
- notice: 3500,
- warn: 4000,
- error: 5000,
- silent: Infinity,
- },
- settings,
- enableColor: () => {
- settings.color = true
- },
- disableColor: () => {
- settings.color = false
- },
- enableUnicode: () => {
- settings.unicode = true
- },
- disableUnicode: () => {
- settings.unicode = false
- },
- enableProgress: () => {
- settings.progress = true
- },
- disableProgress: () => {
- settings.progress = false
- },
- get heading () {
- return settings.heading
- },
- set heading (h) {
- settings.heading = h
- },
- get level () {
- return settings.level
- },
- set level (l) {
- settings.level = l
- },
-}
-
-const EXPLAIN_CALLED = []
-const setupLog = t.mock('../../../lib/utils/setup-log.js', {
- '../../../lib/utils/explain-eresolve.js': {
- explain: (...args) => {
- EXPLAIN_CALLED.push(args)
- return 'explanation'
- },
- },
- npmlog,
-})
-
-const config = obj => ({
- get (k) {
- return obj[k]
- },
- set (k, v) {
- obj[k] = v
- },
-})
-
-t.test('setup with color=always and unicode', t => {
- npmlog.warn('ERESOLVE', 'hello', { some: 'object' })
- t.strictSame(EXPLAIN_CALLED, [], 'log.warn() not patched yet')
- t.strictSame(WARN_CALLED, [['ERESOLVE', 'hello', { some: 'object' }]])
- WARN_CALLED.length = 0
-
- setupLog(config({
- loglevel: 'warn',
- color: 'always',
- unicode: true,
- progress: false,
- }))
-
- npmlog.warn('ERESOLVE', 'hello', { some: { other: 'object' } })
- t.strictSame(EXPLAIN_CALLED, [[{ some: { other: 'object' } }, true, 2]],
- 'log.warn(ERESOLVE) patched to call explainEresolve()')
- t.strictSame(WARN_CALLED, [
- ['ERESOLVE', 'hello'],
- ['', 'explanation'],
- ], 'warn the explanation')
- EXPLAIN_CALLED.length = 0
- WARN_CALLED.length = 0
- npmlog.warn('some', 'other', 'thing')
- t.strictSame(EXPLAIN_CALLED, [], 'do not try to explain other things')
- t.strictSame(WARN_CALLED, [['some', 'other', 'thing']], 'warnings passed through')
-
- t.strictSame(settings, {
- level: 'warn',
- color: true,
- unicode: true,
- progress: false,
- heading: 'npm',
- })
-
- t.end()
-})
-
-t.test('setup with color=true, no unicode, and non-TTY terminal', t => {
- const { isTTY: stderrIsTTY } = process.stderr
- const { isTTY: stdoutIsTTY } = process.stdout
- t.teardown(() => {
- process.stderr.isTTY = stderrIsTTY
- process.stdout.isTTY = stdoutIsTTY
- })
- process.stderr.isTTY = false
- process.stdout.isTTY = false
-
- setupLog(config({
- loglevel: 'warn',
- color: false,
- progress: false,
- heading: 'asdf',
- }))
-
- t.strictSame(settings, {
- level: 'warn',
- color: false,
- unicode: false,
- progress: false,
- heading: 'asdf',
- })
-
- t.end()
-})
-
-t.test('setup with color=true, no unicode, and dumb TTY terminal', t => {
- const { isTTY: stderrIsTTY } = process.stderr
- const { isTTY: stdoutIsTTY } = process.stdout
- const { TERM } = process.env
- t.teardown(() => {
- process.stderr.isTTY = stderrIsTTY
- process.stdout.isTTY = stdoutIsTTY
- process.env.TERM = TERM
- })
- process.stderr.isTTY = true
- process.stdout.isTTY = true
- process.env.TERM = 'dumb'
-
- setupLog(config({
- loglevel: 'warn',
- color: true,
- progress: false,
- heading: 'asdf',
- }))
-
- t.strictSame(settings, {
- level: 'warn',
- color: true,
- unicode: false,
- progress: false,
- heading: 'asdf',
- })
-
- t.end()
-})
-
-t.test('setup with color=true, no unicode, and non-dumb TTY terminal', t => {
- const { isTTY: stderrIsTTY } = process.stderr
- const { isTTY: stdoutIsTTY } = process.stdout
- const { TERM } = process.env
- t.teardown(() => {
- process.stderr.isTTY = stderrIsTTY
- process.stdout.isTTY = stdoutIsTTY
- process.env.TERM = TERM
- })
- process.stderr.isTTY = true
- process.stdout.isTTY = true
- process.env.TERM = 'totes not dum'
-
- setupLog(config({
- loglevel: 'warn',
- color: true,
- progress: true,
- heading: 'asdf',
- }))
-
- t.strictSame(settings, {
- level: 'warn',
- color: true,
- unicode: false,
- progress: true,
- heading: 'asdf',
- })
-
- t.end()
-})
-
-t.test('setup with non-TTY stdout, TTY stderr', t => {
- const { isTTY: stderrIsTTY } = process.stderr
- const { isTTY: stdoutIsTTY } = process.stdout
- const { TERM } = process.env
- t.teardown(() => {
- process.stderr.isTTY = stderrIsTTY
- process.stdout.isTTY = stdoutIsTTY
- process.env.TERM = TERM
- })
- process.stderr.isTTY = true
- process.stdout.isTTY = false
- process.env.TERM = 'definitely not a dummy'
-
- setupLog(config({
- loglevel: 'warn',
- color: true,
- progress: true,
- heading: 'asdf',
- }))
-
- t.strictSame(settings, {
- level: 'warn',
- color: true,
- unicode: false,
- progress: true,
- heading: 'asdf',
- })
-
- t.end()
-})
-
-t.test('setup with TTY stdout, non-TTY stderr', t => {
- const { isTTY: stderrIsTTY } = process.stderr
- const { isTTY: stdoutIsTTY } = process.stdout
- const { TERM } = process.env
- t.teardown(() => {
- process.stderr.isTTY = stderrIsTTY
- process.stdout.isTTY = stdoutIsTTY
- process.env.TERM = TERM
- })
- process.stderr.isTTY = false
- process.stdout.isTTY = true
-
- setupLog(config({
- loglevel: 'warn',
- color: true,
- progress: true,
- heading: 'asdf',
- }))
-
- t.strictSame(settings, {
- level: 'warn',
- color: false,
- unicode: false,
- progress: false,
- heading: 'asdf',
- })
-
- t.end()
-})
-
-t.test('set loglevel to timing', t => {
- setupLog(config({
- timing: true,
- loglevel: 'notice',
- }))
- t.equal(settings.level, 'timing')
- t.end()
-})
-
-t.test('silent has no logging', t => {
- const { isTTY: stderrIsTTY } = process.stderr
- const { isTTY: stdoutIsTTY } = process.stdout
- const { TERM } = process.env
- t.teardown(() => {
- process.stderr.isTTY = stderrIsTTY
- process.stdout.isTTY = stdoutIsTTY
- process.env.TERM = TERM
- })
- process.stderr.isTTY = true
- process.stdout.isTTY = true
- process.env.TERM = 'totes not dum'
-
- setupLog(config({
- loglevel: 'silent',
- }))
- t.equal(settings.progress, false, 'progress disabled when silent')
- t.end()
-})
diff --git a/test/lib/utils/tar.js b/test/lib/utils/tar.js
index 19d949169..adc5cb364 100644
--- a/test/lib/utils/tar.js
+++ b/test/lib/utils/tar.js
@@ -2,18 +2,20 @@ const t = require('tap')
const pack = require('libnpmpack')
const ssri = require('ssri')
-const { logTar, getContents } = require('../../../lib/utils/tar.js')
+const { getContents } = require('../../../lib/utils/tar.js')
-const printLogs = (tarball, unicode) => {
+const mockTar = ({ notice }) => t.mock('../../../lib/utils/tar.js', {
+ 'proc-log': {
+ notice,
+ },
+})
+
+const printLogs = (tarball, options) => {
const logs = []
- logTar(tarball, {
- log: {
- notice: (...args) => {
- args.map(el => logs.push(el))
- },
- },
- unicode,
+ const { logTar } = mockTar({
+ notice: (...args) => args.map(el => logs.push(el)),
})
+ logTar(tarball, options)
return logs.join('\n')
}
@@ -41,16 +43,14 @@ t.test('should log tarball contents', async (t) => {
version: '1.0.0',
}, tarball)
- t.matchSnapshot(printLogs(tarballContents, false))
+ t.matchSnapshot(printLogs(tarballContents))
})
t.test('should log tarball contents with unicode', async (t) => {
- const { logTar } = t.mock('../../../lib/utils/tar.js', {
- npmlog: {
- notice: (str) => {
- t.ok(true, 'defaults to npmlog')
- return str
- },
+ const { logTar } = mockTar({
+ notice: (str) => {
+ t.ok(true, 'defaults to proc-log')
+ return str
},
})
@@ -64,26 +64,6 @@ t.test('should log tarball contents with unicode', async (t) => {
t.end()
})
-t.test('should default to npmlog', async (t) => {
- const { logTar } = t.mock('../../../lib/utils/tar.js', {
- npmlog: {
- notice: (str) => {
- t.ok(true, 'defaults to npmlog')
- return str
- },
- },
- })
-
- logTar({
- files: [],
- bundled: [],
- size: 0,
- unpackedSize: 0,
- integrity: '',
- })
- t.end()
-})
-
t.test('should getContents of a tarball', async (t) => {
const testDir = t.testdir({
'package.json': JSON.stringify({
diff --git a/test/lib/utils/timers.js b/test/lib/utils/timers.js
new file mode 100644
index 000000000..6127f346b
--- /dev/null
+++ b/test/lib/utils/timers.js
@@ -0,0 +1,82 @@
+const t = require('tap')
+const { resolve } = require('path')
+const fs = require('graceful-fs')
+const mockLogs = require('../../fixtures/mock-logs')
+
+const mockTimers = (t, options) => {
+ const { logs, logMocks } = mockLogs()
+ const Timers = t.mock('../../../lib/utils/timers', {
+ ...logMocks,
+ })
+ const timers = new Timers(options)
+ t.teardown(() => timers.off())
+ return { timers, logs }
+}
+
+t.test('getters', async (t) => {
+ const { timers } = mockTimers(t)
+ t.match(timers.unfinished, new Map())
+ t.match(timers.finished, {})
+})
+
+t.test('listens/stops on process', async (t) => {
+ const { timers } = mockTimers(t)
+ process.emit('time', 'foo')
+ process.emit('time', 'bar')
+ process.emit('timeEnd', 'bar')
+ t.match(timers.unfinished, new Map([['foo', Number]]))
+ t.match(timers.finished, { bar: Number })
+ timers.off()
+ process.emit('time', 'baz')
+ t.notOk(timers.unfinished.get('baz'))
+})
+
+t.test('initial timer', async (t) => {
+ const { timers } = mockTimers(t, { start: 'foo' })
+ process.emit('timeEnd', 'foo')
+ t.match(timers.finished, { foo: Number })
+})
+
+t.test('initial listener', async (t) => {
+ const events = []
+ const listener = (...args) => events.push(args)
+ const { timers } = mockTimers(t, { listener })
+ process.emit('time', 'foo')
+ process.emit('time', 'bar')
+ process.emit('timeEnd', 'bar')
+ timers.off(listener)
+ process.emit('timeEnd', 'foo')
+ t.equal(events.length, 1)
+ t.match(events, [['bar', Number]])
+})
+
+t.test('finish unstarted timer', async (t) => {
+ const { logs } = mockTimers(t)
+ process.emit('timeEnd', 'foo')
+ t.match(logs.silly, [['timing', /^Tried to end timer/, 'foo']])
+})
+
+t.test('writes file', async (t) => {
+ const { timers } = mockTimers(t)
+ const dir = t.testdir()
+ process.emit('time', 'foo')
+ process.emit('timeEnd', 'foo')
+ timers.load({ dir })
+ timers.writeFile({ some: 'data' })
+ const data = JSON.parse(fs.readFileSync(resolve(dir, '_timing.json')))
+ t.match(data, {
+ some: 'data',
+ foo: Number,
+ unfinished: {
+ npm: [Number, Number],
+ },
+ })
+})
+
+t.test('fails to write file', async (t) => {
+ const { logs, timers } = mockTimers(t)
+ timers.writeFile()
+ t.match(logs.warn, [
+ ['timing', 'could not write timing file', Error],
+ ])
+})
diff --git a/test/lib/utils/unsupported.js b/test/lib/utils/unsupported.js
index 4d806cefc..2703044a2 100644
--- a/test/lib/utils/unsupported.js
+++ b/test/lib/utils/unsupported.js
@@ -1,5 +1,6 @@
const t = require('tap')
const unsupported = require('../../../lib/utils/unsupported.js')
+const mockGlobals = require('../../fixtures/mock-globals.js')
const versions = [
// broken unsupported
@@ -55,42 +56,30 @@ t.test('checkForBrokenNode', t => {
// run it once to not fail
unsupported.checkForBrokenNode()
- const { exit } = process
- const { error } = console
- const versionPropDesc = Object.getOwnPropertyDescriptor(process, 'version')
-
- t.teardown(() => {
- process.exit = exit
- Object.defineProperty(process, 'version', versionPropDesc)
- console.error = error
- })
-
- // then make it a thing that fails
- process.exit = code => {
- t.equal(code, 1)
- t.strictSame(logs, expectLogs)
- t.end()
- }
- Object.defineProperty(process, 'version', { value: '1.2.3', configurable: true })
const logs = []
const expectLogs = [
'ERROR: npm is known not to run on Node.js 1.2.3',
"You'll need to upgrade to a newer Node.js version in order to use this",
'version of npm. You can find the latest version at https://nodejs.org/',
]
- console.error = msg => logs.push(msg)
+
+ // then make it a thing that fails
+ mockGlobals(t, {
+ 'console.error': msg => logs.push(msg),
+ 'process.version': '1.2.3',
+ 'process.exit': (code) => {
+ t.equal(code, 1)
+ t.strictSame(logs, expectLogs)
+ t.end()
+ },
+ })
+
unsupported.checkForBrokenNode()
})
t.test('checkForUnsupportedNode', t => {
- const npmlog = require('npmlog')
- const { warn } = npmlog
- const versionPropDesc = Object.getOwnPropertyDescriptor(process, 'version')
-
- t.teardown(() => {
- Object.defineProperty(process, 'version', versionPropDesc)
- npmlog.warn = warn
- })
+ // run it once to not fail or warn
+ unsupported.checkForUnsupportedNode()
const logs = []
const expectLogs = [
@@ -99,14 +88,15 @@ t.test('checkForUnsupportedNode', t => {
"can't make any promises that npm will work with this version.",
'You can find the latest version at https://nodejs.org/',
]
- npmlog.warn = (section, msg) => logs.push(msg)
-
- // run it once to not fail or warn
- unsupported.checkForUnsupportedNode()
// then make it a thing that fails
- Object.defineProperty(process, 'version', { value: '8.0.0' })
+ mockGlobals(t, {
+ 'console.error': msg => logs.push(msg),
+ 'process.version': '8.0.0',
+ })
+
unsupported.checkForUnsupportedNode()
+
t.strictSame(logs, expectLogs)
t.end()
})
diff --git a/test/lib/utils/update-notifier.js b/test/lib/utils/update-notifier.js
index 78ff93825..a7a800c60 100644
--- a/test/lib/utils/update-notifier.js
+++ b/test/lib/utils/update-notifier.js
@@ -36,18 +36,13 @@ const pacote = {
},
}
-const npm = {
+const defaultNpm = {
flatOptions,
- log: { useColor: () => true },
version: CURRENT_VERSION,
config: { get: k => k !== 'global' },
command: 'view',
argv: ['npm'],
}
-const npmNoColor = {
- ...npm,
- log: { useColor: () => false },
-}
const { basename } = require('path')
@@ -80,12 +75,6 @@ const fs = {
},
}
-const updateNotifier = t.mock('../../../lib/utils/update-notifier.js', {
- '@npmcli/ci-detect': () => ciMock,
- pacote,
- fs,
-})
-
t.afterEach(() => {
MANIFEST_REQUEST.length = 0
STAT_ERROR = null
@@ -94,16 +83,21 @@ t.afterEach(() => {
WRITE_ERROR = null
})
-const runUpdateNotifier = async npm => {
- await updateNotifier(npm)
- return npm.updateNotification
+const runUpdateNotifier = async ({ color = true, ...npmOptions } = {}) => {
+ const _npm = { ...defaultNpm, ...npmOptions }
+ await t.mock('../../../lib/utils/update-notifier.js', {
+ '@npmcli/ci-detect': () => ciMock,
+ pacote,
+ fs,
+ npmlog: { useColor: () => color },
+ })(_npm)
+ return _npm.updateNotification
}
t.test('situations in which we do not notify', t => {
t.test('nothing to do if notifier disabled', async t => {
t.equal(
await runUpdateNotifier({
- ...npm,
config: { get: k => k !== 'update-notifier' },
}),
null
@@ -114,7 +108,6 @@ t.test('situations in which we do not notify', t => {
t.test('do not suggest update if already updating', async t => {
t.equal(
await runUpdateNotifier({
- ...npm,
flatOptions: { ...flatOptions, global: true },
command: 'install',
argv: ['npm'],
@@ -127,7 +120,6 @@ t.test('situations in which we do not notify', t => {
t.test('do not suggest update if already updating with spec', async t => {
t.equal(
await runUpdateNotifier({
- ...npm,
flatOptions: { ...flatOptions, global: true },
command: 'install',
argv: ['npm@latest'],
@@ -138,31 +130,31 @@ t.test('situations in which we do not notify', t => {
})
t.test('do not update if same as latest', async t => {
- t.equal(await runUpdateNotifier(npm), null)
+ t.equal(await runUpdateNotifier(), null)
t.strictSame(MANIFEST_REQUEST, ['npm@latest'], 'requested latest version')
})
t.test('check if stat errors (here for coverage)', async t => {
STAT_ERROR = new Error('blorg')
- t.equal(await runUpdateNotifier(npm), null)
+ t.equal(await runUpdateNotifier(), null)
t.strictSame(MANIFEST_REQUEST, ['npm@latest'], 'requested latest version')
})
t.test('ok if write errors (here for coverage)', async t => {
WRITE_ERROR = new Error('grolb')
- t.equal(await runUpdateNotifier(npm), null)
+ t.equal(await runUpdateNotifier(), null)
t.strictSame(MANIFEST_REQUEST, ['npm@latest'], 'requested latest version')
})
t.test('ignore pacote failures (here for coverage)', async t => {
PACOTE_ERROR = new Error('pah-KO-tchay')
- t.equal(await runUpdateNotifier(npm), null)
+ t.equal(await runUpdateNotifier(), null)
t.strictSame(MANIFEST_REQUEST, ['npm@latest'], 'requested latest version')
})
t.test('do not update if newer than latest, but same as next', async t => {
- t.equal(await runUpdateNotifier({ ...npm, version: NEXT_VERSION }), null)
+ t.equal(await runUpdateNotifier({ version: NEXT_VERSION }), null)
const reqs = ['npm@latest', `npm@^${NEXT_VERSION}`]
t.strictSame(MANIFEST_REQUEST, reqs, 'requested latest and next versions')
})
t.test('do not update if on the latest beta', async t => {
- t.equal(await runUpdateNotifier({ ...npm, version: CURRENT_BETA }), null)
+ t.equal(await runUpdateNotifier({ version: CURRENT_BETA }), null)
const reqs = [`npm@^${CURRENT_BETA}`]
t.strictSame(MANIFEST_REQUEST, reqs, 'requested latest and next versions')
})
@@ -172,21 +164,21 @@ t.test('situations in which we do not notify', t => {
ciMock = null
})
ciMock = 'something'
- t.equal(await runUpdateNotifier(npm), null)
+ t.equal(await runUpdateNotifier(), null)
t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
})
t.test('only check weekly for GA releases', async t => {
// One week (plus five minutes to account for test environment fuzziness)
STAT_MTIME = Date.now() - 1000 * 60 * 60 * 24 * 7 + 1000 * 60 * 5
- t.equal(await runUpdateNotifier(npm), null)
+ t.equal(await runUpdateNotifier(), null)
t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
})
t.test('only check daily for betas', async t => {
// One day (plus five minutes to account for test environment fuzziness)
STAT_MTIME = Date.now() - 1000 * 60 * 60 * 24 + 1000 * 60 * 5
- t.equal(await runUpdateNotifier({ ...npm, version: HAVE_BETA }), null)
+ t.equal(await runUpdateNotifier({ version: HAVE_BETA }), null)
t.strictSame(MANIFEST_REQUEST, [], 'no requests for manifests')
})
@@ -196,9 +188,9 @@ t.test('situations in which we do not notify', t => {
t.test('notification situations', t => {
t.test('new beta available', async t => {
const version = HAVE_BETA
- t.matchSnapshot(await runUpdateNotifier({ ...npm, version }), 'color')
+ t.matchSnapshot(await runUpdateNotifier({ version }), 'color')
t.matchSnapshot(
- await runUpdateNotifier({ ...npmNoColor, version }),
+ await runUpdateNotifier({ version, color: false }),
'no color'
)
t.strictSame(MANIFEST_REQUEST, [`npm@^${version}`, `npm@^${version}`])
@@ -206,9 +198,9 @@ t.test('notification situations', t => {
t.test('patch to next version', async t => {
const version = NEXT_PATCH
- t.matchSnapshot(await runUpdateNotifier({ ...npm, version }), 'color')
+ t.matchSnapshot(await runUpdateNotifier({ version }), 'color')
t.matchSnapshot(
- await runUpdateNotifier({ ...npmNoColor, version }),
+ await runUpdateNotifier({ version, color: false }),
'no color'
)
t.strictSame(MANIFEST_REQUEST, [
@@ -221,9 +213,9 @@ t.test('notification situations', t => {
t.test('minor to next version', async t => {
const version = NEXT_MINOR
- t.matchSnapshot(await runUpdateNotifier({ ...npm, version }), 'color')
+ t.matchSnapshot(await runUpdateNotifier({ version }), 'color')
t.matchSnapshot(
- await runUpdateNotifier({ ...npmNoColor, version }),
+ await runUpdateNotifier({ version, color: false }),
'no color'
)
t.strictSame(MANIFEST_REQUEST, [
@@ -236,9 +228,9 @@ t.test('notification situations', t => {
t.test('patch to current', async t => {
const version = CURRENT_PATCH
- t.matchSnapshot(await runUpdateNotifier({ ...npm, version }), 'color')
+ t.matchSnapshot(await runUpdateNotifier({ version }), 'color')
t.matchSnapshot(
- await runUpdateNotifier({ ...npmNoColor, version }),
+ await runUpdateNotifier({ version, color: false }),
'no color'
)
t.strictSame(MANIFEST_REQUEST, ['npm@latest', 'npm@latest'])
@@ -246,9 +238,9 @@ t.test('notification situations', t => {
t.test('minor to current', async t => {
const version = CURRENT_MINOR
- t.matchSnapshot(await runUpdateNotifier({ ...npm, version }), 'color')
+ t.matchSnapshot(await runUpdateNotifier({ version }), 'color')
t.matchSnapshot(
- await runUpdateNotifier({ ...npmNoColor, version }),
+ await runUpdateNotifier({ version, color: false }),
'no color'
)
t.strictSame(MANIFEST_REQUEST, ['npm@latest', 'npm@latest'])
@@ -256,9 +248,9 @@ t.test('notification situations', t => {
t.test('major to current', async t => {
const version = CURRENT_MAJOR
- t.matchSnapshot(await runUpdateNotifier({ ...npm, version }), 'color')
+ t.matchSnapshot(await runUpdateNotifier({ version }), 'color')
t.matchSnapshot(
- await runUpdateNotifier({ ...npmNoColor, version }),
+ await runUpdateNotifier({ version, color: false }),
'no color'
)
t.strictSame(MANIFEST_REQUEST, ['npm@latest', 'npm@latest'])