Skip to content

Commit

Permalink
refactor and test for main cli script
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacs committed Jul 17, 2020
1 parent 1b00d17 commit d71db29
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 69 deletions.
69 changes: 1 addition & 68 deletions bin/npm-cli.js
Original file line number Diff line number Diff line change
@@ -1,69 +1,2 @@
#!/usr/bin/env node

process.title = 'npm'

const {
checkForBrokenNode,
checkForUnsupportedNode
} = require('../lib/utils/unsupported.js')

checkForBrokenNode()

const log = require('npmlog')
// pause it here so it can unpause when we've loaded the configs
// and know what loglevel we should be printing.
log.pause()

checkForUnsupportedNode()

const npm = require('../lib/npm.js')
const { defs: { shorthands, types } } = require('../lib/config/core.js')
const errorHandler = require('../lib/utils/error-handler.js')
const nopt = require('nopt')

// if npm is called as "npmg" or "npm_g", then
// run in global mode.
if (process.argv[1][process.argv[1].length - 1] === 'g') {
process.argv.splice(1, 1, 'npm', '-g')
}

log.verbose('cli', process.argv)

const conf = nopt(types, shorthands)
npm.argv = conf.argv.remain

if (conf.version) {
console.log(npm.version)
return errorHandler.exit(0)
}

if (conf.versions) {
npm.argv = ['version']
conf.usage = false
}

log.info('using', 'npm@%s', npm.version)
log.info('using', 'node@%s', process.version)

process.on('uncaughtException', errorHandler)
process.on('unhandledRejection', errorHandler)

// now actually fire up npm and run the command.
// this is how to use npm programmatically:
conf._exit = true
const updateNotifier = require('../lib/utils/update-notifier.js')
npm.load(conf, function (er) {
if (er) return errorHandler(er)

updateNotifier(npm)

const cmd = npm.argv.shift()
const impl = npm.commands[cmd]
if (impl) {
impl(npm.argv, errorHandler)
} else {
npm.config.set('usage', false)
npm.argv.unshift(cmd)
npm.commands.help(npm.argv, errorHandler)
}
})
require('../lib/cli.js')(process)
2 changes: 1 addition & 1 deletion lib/npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,5 +287,5 @@ const cleanUpLogFiles = require('./utils/cleanup-log-files.js')
const getProjectScope = require('./utils/get-project-scope.js')

if (require.main === module) {
require('./npm-cli.js')(process)
require('./cli.js')(process)
}
166 changes: 166 additions & 0 deletions test/lib/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
const t = require('tap')

let LOAD_ERROR = null
const npmock = {
version: '99.99.99',
load: (config, cb) => cb(LOAD_ERROR),
argv: [],
config: {
settings: {},
get: (k) => npmock.config.settings[k],
set: (k, v) => { npmock.config.settings[k] = v },
},
commands: {}
}

const unsupportedMock = {
checkForBrokenNode: () => {},
checkForUnsupportedNode: () => {}
}

let errorHandlerCalled = null
const errorHandlerMock = (...args) => {
errorHandlerCalled = args
}
let errorHandlerExitCalled = null
errorHandlerMock.exit = code => {
errorHandlerExitCalled = code
}

const logs = []
const npmlogMock = {
pause: () => logs.push('pause'),
verbose: (...msg) => logs.push(['verbose', ...msg]),
info: (...msg) => logs.push(['info', ...msg])
}

const requireInject = require('require-inject')
const cli = requireInject.installGlobally('../../lib/cli.js', {
'../../lib/npm.js': npmock,
'../../lib/utils/unsupported.js': unsupportedMock,
'../../lib/utils/error-handler.js': errorHandlerMock,
npmlog: npmlogMock
})

t.test('print the version, and treat npm_g to npm -g', t => {
const { log } = console
const consoleLogs = []
console.log = (...msg) => consoleLogs.push(msg)
const proc = {
argv: ['node', 'npm_g', '-v'],
on: () => {}
}

cli(proc)

t.strictSame(npmock.argv, [])
t.strictSame(proc.argv, [ 'node', 'npm', '-g', '-v' ])
t.strictSame(logs, [
'pause',
[ 'verbose', 'cli', [ 'node', 'npm', '-g', '-v' ] ]
])
t.strictSame(consoleLogs, [ [ '99.99.99' ] ])
t.strictSame(errorHandlerExitCalled, 0)

console.log = log
npmock.argv = 0
proc.argv.length = 0
logs.length = 0
consoleLogs.length = 0
errorHandlerExitCalled = null

t.end()
})

t.test('calling with --versions calls npm version with no args', t => {
const { log } = console
const consoleLogs = []
console.log = (...msg) => consoleLogs.push(msg)
const proc = {
argv: ['node', 'npm', 'install', 'or', 'whatever', '--versions'],
on: () => {}
}

t.teardown(() => {
console.log = log
npmock.argv = 0
proc.argv.length = 0
logs.length = 0
consoleLogs.length = 0
errorHandlerExitCalled = null
delete npmock.commands.version
})

npmock.commands.version = (args, cb) => {
t.equal(proc.title, 'npm')
t.strictSame(npmock.argv, [])
t.strictSame(proc.argv, [ 'node', 'npm', 'install', 'or', 'whatever', '--versions' ])
t.strictSame(logs, [
'pause',
[ 'verbose', 'cli', [ 'node', 'npm', 'install', 'or', 'whatever', '--versions' ] ],
[ 'info', 'using', 'npm@%s', '99.99.99' ],
[ 'info', 'using', 'node@%s', undefined ]
])

t.strictSame(consoleLogs, [])
t.strictSame(errorHandlerExitCalled, null)

t.strictSame(args, [])
t.end()
}

cli(proc)
})

t.test('print usage if -h provided', t => {
const { log } = console
const consoleLogs = []
console.log = (...msg) => consoleLogs.push(msg)
const proc = {
argv: ['node', 'npm', 'asdf'],
on: () => {}
}

t.teardown(() => {
console.log = log
npmock.argv = 0
proc.argv.length = 0
logs.length = 0
consoleLogs.length = 0
errorHandlerExitCalled = null
delete npmock.commands.help
})

npmock.commands.help = (args, cb) => {
delete npmock.commands.help
t.equal(proc.title, 'npm')
t.strictSame(args, ['asdf'])
t.strictSame(npmock.argv, ['asdf'])
t.strictSame(proc.argv, [ 'node', 'npm', 'asdf' ])
t.strictSame(logs, [
'pause',
[ 'verbose', 'cli', [ 'node', 'npm', 'asdf' ] ],
[ 'info', 'using', 'npm@%s', '99.99.99' ],
[ 'info', 'using', 'node@%s', undefined ]
])
t.strictSame(consoleLogs, [])
t.strictSame(errorHandlerExitCalled, null)
t.end()
}

cli(proc)
})

t.test('load error calls error handler', t => {
const er = new Error('poop')
LOAD_ERROR = er
const proc = {
argv: ['node', 'npm', 'asdf'],
on: () => {}
}
cli(proc)
t.strictSame(errorHandlerCalled, [er])
LOAD_ERROR = null
t.end()
})

0 comments on commit d71db29

Please sign in to comment.