Skip to content

Commit 6caf19f

Browse files
committed
tests for npm help
PR-URL: #2348 Credit: @nlf Close: #2348 Reviewed-by: @ruyadorno
1 parent 3ba5de4 commit 6caf19f

File tree

2 files changed

+368
-1
lines changed

2 files changed

+368
-1
lines changed

lib/help.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,12 @@ function viewMan (man, cb) {
133133
break
134134

135135
case 'browser':
136-
openUrl(htmlMan(man), 'help available at the following URL', cb)
136+
try {
137+
var url = htmlMan(man)
138+
} catch (err) {
139+
return cb(err)
140+
}
141+
openUrl(url, 'help available at the following URL', cb)
137142
break
138143

139144
default:

test/lib/help.js

Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
1+
const { test } = require('tap')
2+
const requireInject = require('require-inject')
3+
const { EventEmitter } = require('events')
4+
5+
let npmUsageArg = null
6+
const npmUsage = (arg) => {
7+
npmUsageArg = arg
8+
}
9+
10+
const npmConfig = {
11+
usage: false,
12+
viewer: undefined,
13+
loglevel: undefined,
14+
}
15+
16+
let helpSearchArgs = null
17+
const npm = {
18+
config: {
19+
get: (key) => npmConfig[key],
20+
set: (key, value) => {
21+
npmConfig[key] = value
22+
},
23+
parsedArgv: {
24+
cooked: [],
25+
},
26+
},
27+
commands: {
28+
'help-search': (args, cb) => {
29+
helpSearchArgs = args
30+
return cb()
31+
},
32+
help: {
33+
usage: 'npm help <term>',
34+
},
35+
},
36+
deref: (cmd) => {},
37+
}
38+
39+
const OUTPUT = []
40+
const output = (msg) => {
41+
OUTPUT.push(msg)
42+
}
43+
44+
const globDefaults = [
45+
'/root/man/man1/npm-whoami.1',
46+
'/root/man/man5/npmrc.5',
47+
'/root/man/man7/disputes.7',
48+
]
49+
50+
let globErr = null
51+
let globResult = globDefaults
52+
const glob = (p, cb) => {
53+
return cb(globErr, globResult)
54+
}
55+
56+
let spawnBin = null
57+
let spawnArgs = null
58+
const spawn = (bin, args) => {
59+
spawnBin = bin
60+
spawnArgs = args
61+
const spawnEmitter = new EventEmitter()
62+
process.nextTick(() => {
63+
spawnEmitter.emit('close', 0)
64+
})
65+
return spawnEmitter
66+
}
67+
68+
let openUrlArg = null
69+
const openUrl = (url, msg, cb) => {
70+
openUrlArg = url
71+
return cb()
72+
}
73+
74+
const help = requireInject('../../lib/help.js', {
75+
'../../lib/npm.js': npm,
76+
'../../lib/utils/npm-usage.js': npmUsage,
77+
'../../lib/utils/open-url.js': openUrl,
78+
'../../lib/utils/output.js': output,
79+
'../../lib/utils/spawn.js': spawn,
80+
glob,
81+
})
82+
83+
test('npm help', t => {
84+
t.teardown(() => {
85+
npmUsageArg = null
86+
})
87+
88+
return help([], (err) => {
89+
if (err)
90+
throw err
91+
92+
t.equal(npmUsageArg, false, 'called npmUsage')
93+
t.end()
94+
})
95+
})
96+
97+
test('npm help completion', async t => {
98+
t.teardown(() => {
99+
globErr = null
100+
})
101+
const completion = (opts) => new Promise((resolve, reject) => {
102+
help.completion(opts, (err, res) => {
103+
if (err)
104+
return reject(err)
105+
return resolve(res)
106+
})
107+
})
108+
109+
const noArgs = await completion({ conf: { argv: { remain: [] } } })
110+
t.strictSame(noArgs, ['help', 'whoami', 'npmrc', 'disputes'], 'outputs available help pages')
111+
const threeArgs = await completion({ conf: { argv: { remain: ['one', 'two', 'three'] } } })
112+
t.strictSame(threeArgs, [], 'outputs no results when more than 2 args are provided')
113+
globErr = new Error('glob failed')
114+
t.rejects(completion({ conf: { argv: { remain: [] } } }), /glob failed/, 'glob errors propagate')
115+
})
116+
117+
test('npm help -h', t => {
118+
npmConfig.usage = true
119+
t.teardown(() => {
120+
npmConfig.usage = false
121+
OUTPUT.length = 0
122+
})
123+
124+
return help(['help'], (err) => {
125+
if (err)
126+
throw err
127+
128+
t.strictSame(OUTPUT, ['npm help <term>'], 'outputs usage information for command')
129+
t.end()
130+
})
131+
})
132+
133+
test('npm help multiple args calls search', t => {
134+
t.teardown(() => {
135+
helpSearchArgs = null
136+
})
137+
138+
return help(['run', 'script'], (err) => {
139+
if (err)
140+
throw err
141+
142+
t.strictSame(helpSearchArgs, ['run', 'script'], 'passed the args to help-search')
143+
t.end()
144+
})
145+
})
146+
147+
test('npm help no matches calls search', t => {
148+
globResult = []
149+
t.teardown(() => {
150+
helpSearchArgs = null
151+
globResult = globDefaults
152+
})
153+
154+
return help(['asdfasdf'], (err) => {
155+
if (err)
156+
throw err
157+
158+
t.strictSame(helpSearchArgs, ['asdfasdf'], 'passed the args to help-search')
159+
t.end()
160+
})
161+
})
162+
163+
test('npm help glob errors propagate', t => {
164+
globErr = new Error('glob failed')
165+
t.teardown(() => {
166+
globErr = null
167+
spawnBin = null
168+
spawnArgs = null
169+
})
170+
171+
return help(['whoami'], (err) => {
172+
t.match(err, /glob failed/, 'glob error propagates')
173+
t.end()
174+
})
175+
})
176+
177+
test('npm help whoami', t => {
178+
globResult = ['/root/man/man1/npm-whoami.1.xz']
179+
t.teardown(() => {
180+
globResult = globDefaults
181+
spawnBin = null
182+
spawnArgs = null
183+
})
184+
185+
return help(['whoami'], (err) => {
186+
if (err)
187+
throw err
188+
189+
t.equal(spawnBin, 'man', 'calls man by default')
190+
t.strictSame(spawnArgs, ['1', 'npm-whoami'], 'passes the correct arguments')
191+
t.end()
192+
})
193+
})
194+
195+
test('npm help 1 install', t => {
196+
npmConfig.viewer = 'browser'
197+
globResult = [
198+
'/root/man/man5/install.5',
199+
'/root/man/man1/npm-install.1',
200+
]
201+
202+
t.teardown(() => {
203+
npmConfig.viewer = undefined
204+
globResult = globDefaults
205+
spawnBin = null
206+
spawnArgs = null
207+
})
208+
209+
return help(['1', 'install'], (err) => {
210+
if (err)
211+
throw err
212+
213+
t.match(openUrlArg, /commands(\/|\\)npm-install.html$/, 'attempts to open the correct url')
214+
t.end()
215+
})
216+
})
217+
218+
test('npm help 5 install', t => {
219+
npmConfig.viewer = 'browser'
220+
globResult = [
221+
'/root/man/man5/install.5',
222+
'/root/man/man1/npm-install.1',
223+
]
224+
225+
t.teardown(() => {
226+
npmConfig.viewer = undefined
227+
globResult = globDefaults
228+
spawnBin = null
229+
spawnArgs = null
230+
})
231+
232+
return help(['5', 'install'], (err) => {
233+
if (err)
234+
throw err
235+
236+
t.match(openUrlArg, /configuring-npm(\/|\\)install.html$/, 'attempts to open the correct url')
237+
t.end()
238+
})
239+
})
240+
241+
test('npm help 7 config', t => {
242+
npmConfig.viewer = 'browser'
243+
globResult = [
244+
'/root/man/man1/npm-config.1',
245+
'/root/man/man7/config.7',
246+
]
247+
t.teardown(() => {
248+
npmConfig.viewer = undefined
249+
globResult = globDefaults
250+
spawnBin = null
251+
spawnArgs = null
252+
})
253+
254+
return help(['7', 'config'], (err) => {
255+
if (err)
256+
throw err
257+
258+
t.match(openUrlArg, /using-npm(\/|\\)config.html$/, 'attempts to open the correct url')
259+
t.end()
260+
})
261+
})
262+
263+
test('npm help with browser viewer and invalid section throws', t => {
264+
npmConfig.viewer = 'browser'
265+
globResult = [
266+
'/root/man/man1/npm-config.1',
267+
'/root/man/man7/config.7',
268+
'/root/man/man9/config.9',
269+
]
270+
t.teardown(() => {
271+
npmConfig.viewer = undefined
272+
globResult = globDefaults
273+
spawnBin = null
274+
spawnArgs = null
275+
})
276+
277+
return help(['9', 'config'], (err) => {
278+
t.match(err, /invalid man section: 9/, 'throws appropriate error')
279+
t.end()
280+
})
281+
})
282+
283+
test('npm help global redirects to folders', t => {
284+
globResult = ['/root/man/man5/folders.5']
285+
t.teardown(() => {
286+
globResult = globDefaults
287+
spawnBin = null
288+
spawnArgs = null
289+
})
290+
291+
return help(['global'], (err) => {
292+
if (err)
293+
throw err
294+
295+
t.equal(spawnBin, 'man', 'calls man by default')
296+
t.strictSame(spawnArgs, ['5', 'folders'], 'passes the correct arguments')
297+
t.end()
298+
})
299+
})
300+
301+
test('npm help package.json redirects to package-json', t => {
302+
globResult = ['/root/man/man5/package-json.5']
303+
t.teardown(() => {
304+
globResult = globDefaults
305+
spawnBin = null
306+
spawnArgs = null
307+
})
308+
309+
return help(['package.json'], (err) => {
310+
if (err)
311+
throw err
312+
313+
t.equal(spawnBin, 'man', 'calls man by default')
314+
t.strictSame(spawnArgs, ['5', 'package-json'], 'passes the correct arguments')
315+
t.end()
316+
})
317+
})
318+
319+
test('npm help ?(un)star', t => {
320+
npmConfig.viewer = 'woman'
321+
globResult = [
322+
'/root/man/man1/npm-star.1',
323+
'/root/man/man1/npm-unstar.1',
324+
]
325+
t.teardown(() => {
326+
npmConfig.viewer = undefined
327+
globResult = globDefaults
328+
spawnBin = null
329+
spawnArgs = null
330+
})
331+
332+
return help(['?(un)star'], (err) => {
333+
if (err)
334+
throw err
335+
336+
t.equal(spawnBin, 'emacsclient', 'maps woman to emacs correctly')
337+
t.strictSame(spawnArgs, ['-e', `(woman-find-file '/root/man/man1/npm-unstar.1')`], 'passes the correct arguments')
338+
t.end()
339+
})
340+
})
341+
342+
test('npm help un*', t => {
343+
globResult = [
344+
'/root/man/man1/npm-unstar.1',
345+
'/root/man/man1/npm-uninstall.1',
346+
'/root/man/man1/npm-unpublish.1',
347+
]
348+
t.teardown(() => {
349+
globResult = globDefaults
350+
spawnBin = null
351+
spawnArgs = null
352+
})
353+
354+
return help(['un*'], (err) => {
355+
if (err)
356+
throw err
357+
358+
t.equal(spawnBin, 'man', 'calls man by default')
359+
t.strictSame(spawnArgs, ['1', 'npm-unstar'], 'passes the correct arguments')
360+
t.end()
361+
})
362+
})

0 commit comments

Comments
 (0)