• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1const t = require('tap')
2const { load: loadMockNpm } = require('../fixtures/mock-npm.js')
3const tmock = require('../fixtures/tmock.js')
4const validateEngines = require('../../lib/es6/validate-engines.js')
5
6const cliMock = async (t, opts) => {
7  let exitHandlerArgs = null
8  let npm = null
9  const exitHandlerMock = (...args) => {
10    exitHandlerArgs = args
11    npm.unload()
12  }
13  exitHandlerMock.setNpm = _npm => npm = _npm
14
15  const { Npm, outputs, logMocks, logs } = await loadMockNpm(t, { ...opts, init: false })
16  const cli = tmock(t, '{LIB}/cli-entry.js', {
17    '{LIB}/npm.js': Npm,
18    '{LIB}/utils/exit-handler.js': exitHandlerMock,
19    ...logMocks,
20  })
21
22  return {
23    Npm,
24    cli: (p) => validateEngines(p, () => cli),
25    outputs,
26    exitHandlerCalled: () => exitHandlerArgs,
27    exitHandlerNpm: () => npm,
28    logs,
29    logsBy: (title) => logs.verbose.filter(([p]) => p === title).map(([p, ...rest]) => rest),
30  }
31}
32
33t.test('print the version, and treat npm_g as npm -g', async t => {
34  const { logsBy, logs, cli, Npm, outputs, exitHandlerCalled } = await cliMock(t, {
35    globals: { 'process.argv': ['node', 'npm_g', '-v'] },
36  })
37  await cli(process)
38
39  t.strictSame(process.argv, ['node', 'npm', '-g', '-v'], 'system process.argv was rewritten')
40  t.strictSame(logsBy('cli'), [['node npm']])
41  t.strictSame(logsBy('title'), [['npm']])
42  t.match(logsBy('argv'), [['"--global" "--version"']])
43  t.strictSame(logs.info, [
44    ['using', 'npm@%s', Npm.version],
45    ['using', 'node@%s', process.version],
46  ])
47  t.equal(outputs.length, 1)
48  t.strictSame(outputs, [[Npm.version]])
49  t.strictSame(exitHandlerCalled(), [])
50})
51
52t.test('calling with --versions calls npm version with no args', async t => {
53  const { logsBy, cli, outputs, exitHandlerCalled } = await cliMock(t, {
54    globals: {
55      'process.argv': ['node', 'npm', 'install', 'or', 'whatever', '--versions'],
56    },
57  })
58  await cli(process)
59
60  t.equal(process.title, 'npm install or whatever')
61  t.strictSame(logsBy('cli'), [['node npm']])
62  t.strictSame(logsBy('title'), [['npm install or whatever']])
63  t.match(logsBy('argv'), [['"install" "or" "whatever" "--versions"']])
64  t.equal(outputs.length, 1)
65  t.match(outputs[0][0], { npm: String, node: String, v8: String })
66  t.strictSame(exitHandlerCalled(), [])
67})
68
69t.test('logged argv is sanitized', async t => {
70  const { logsBy, cli } = await cliMock(t, {
71    globals: {
72      'process.argv': [
73        'node',
74        'npm',
75        'version',
76        '--registry',
77        'https://u:password@npmjs.org/password',
78      ],
79    },
80  })
81
82  await cli(process)
83  t.equal(process.title, 'npm version')
84  t.strictSame(logsBy('cli'), [['node npm']])
85  t.strictSame(logsBy('title'), [['npm version']])
86  t.match(logsBy('argv'), [['"version" "--registry" "https://u:***@npmjs.org/password"']])
87})
88
89t.test('logged argv is sanitized with equals', async t => {
90  const { logsBy, cli } = await cliMock(t, {
91    globals: {
92      'process.argv': [
93        'node',
94        'npm',
95        'version',
96        '--registry=https://u:password@npmjs.org',
97      ],
98    },
99  })
100  await cli(process)
101
102  t.match(logsBy('argv'), [['"version" "--registry" "https://u:***@npmjs.org/"']])
103})
104
105t.test('print usage if no params provided', async t => {
106  const { cli, outputs, exitHandlerCalled, exitHandlerNpm } = await cliMock(t, {
107    globals: {
108      'process.argv': ['node', 'npm'],
109    },
110  })
111  await cli(process)
112
113  t.match(outputs[0][0], 'Usage:', 'outputs npm usage')
114  t.match(exitHandlerCalled(), [], 'should call exitHandler with no args')
115  t.ok(exitHandlerNpm(), 'exitHandler npm is set')
116  t.match(process.exitCode, 1)
117})
118
119t.test('print usage if non-command param provided', async t => {
120  const { cli, outputs, exitHandlerCalled, exitHandlerNpm } = await cliMock(t, {
121    globals: {
122      'process.argv': ['node', 'npm', 'tset'],
123    },
124  })
125  await cli(process)
126
127  t.match(outputs[0][0], 'Unknown command: "tset"')
128  t.match(outputs[0][0], 'Did you mean this?')
129  t.match(exitHandlerCalled(), [], 'should call exitHandler with no args')
130  t.ok(exitHandlerNpm(), 'exitHandler npm is set')
131  t.match(process.exitCode, 1)
132})
133
134t.test('load error calls error handler', async t => {
135  const err = new Error('test load error')
136  const { cli, exitHandlerCalled } = await cliMock(t, {
137    mocks: {
138      '@npmcli/config': class BadConfig {
139        async load () {
140          throw err
141        }
142      },
143    },
144    globals: {
145      'process.argv': ['node', 'npm', 'asdf'],
146    },
147  })
148  await cli(process)
149  t.strictSame(exitHandlerCalled(), [err])
150})
151
152t.test('unsupported node version', async t => {
153  const { cli, logs } = await cliMock(t, {
154    globals: {
155      'process.version': '12.6.0',
156    },
157  })
158  await cli(process)
159  t.match(
160    logs.warn[0][1],
161    /npm v.* does not support Node\.js 12\.6\.0\./
162  )
163})
164