xref: /third_party/node/deps/npm/test/lib/commands/org.js (revision 1cb0ef41)
1const t = require('tap')
2const mockNpm = require('../../fixtures/mock-npm')
3const { stripVTControlCharacters } = require('node:util')
4
5const mockOrg = async (t, { orgSize = 1, orgList = {}, ...npmOpts } = {}) => {
6  let setArgs = null
7  let rmArgs = null
8  let lsArgs = null
9
10  const libnpmorg = {
11    set: async (org, user, role, opts) => {
12      setArgs = { org, user, role, opts }
13      return {
14        org: {
15          name: org,
16          size: orgSize,
17        },
18        user,
19        role,
20      }
21    },
22    rm: async (org, user, opts) => {
23      rmArgs = { org, user, opts }
24    },
25    ls: async (org, opts) => {
26      lsArgs = { org, opts }
27      return orgList
28    },
29  }
30
31  const mock = await mockNpm(t, {
32    ...npmOpts,
33    command: 'org',
34    mocks: {
35      libnpmorg,
36      ...npmOpts.mocks,
37    },
38  })
39
40  return {
41    ...mock,
42    setArgs: () => setArgs,
43    rmArgs: () => rmArgs,
44    lsArgs: () => lsArgs,
45  }
46}
47
48t.test('completion', async t => {
49  const { org } = await mockOrg(t)
50  const completion = argv => org.completion({ conf: { argv: { remain: argv } } })
51
52  const assertions = [
53    [
54      ['npm', 'org'],
55      ['set', 'rm', 'ls'],
56    ],
57    [['npm', 'org', 'ls'], []],
58    [['npm', 'org', 'add'], []],
59    [['npm', 'org', 'rm'], []],
60    [['npm', 'org', 'set'], []],
61  ]
62
63  for (const [argv, expected] of assertions) {
64    t.resolveMatch(completion(argv), expected, `completion for: ${argv.join(', ')}`)
65  }
66
67  t.rejects(
68    completion(['npm', 'org', 'flurb']),
69    /flurb not recognized/,
70    'errors for unknown subcommand'
71  )
72})
73
74t.test('npm org - invalid subcommand', async t => {
75  const { org } = await mockOrg(t)
76  await t.rejects(org.exec(['foo']), org.usage)
77})
78
79t.test('npm org add', async t => {
80  const { npm, org, setArgs, outputs } = await mockOrg(t)
81
82  await org.exec(['add', 'orgname', 'username'])
83
84  t.match(
85    setArgs(),
86    {
87      org: 'orgname',
88      user: 'username',
89      role: 'developer',
90      opts: npm.flatOptions,
91    },
92    'received the correct arguments'
93  )
94  t.equal(
95    outputs[0][0],
96    'Added username as developer to orgname. You now have 1 member in this org.',
97    'printed the correct output'
98  )
99})
100
101t.test('npm org add - no org', async t => {
102  const { org } = await mockOrg(t)
103
104  await t.rejects(
105    org.exec(['add', '', 'username']),
106    /`orgname` is required/,
107    'returns the correct error'
108  )
109})
110
111t.test('npm org add - no user', async t => {
112  const { org } = await mockOrg(t)
113  await t.rejects(
114    org.exec(['add', 'orgname', '']),
115    /`username` is required/,
116    'returns the correct error'
117  )
118})
119
120t.test('npm org add - invalid role', async t => {
121  const { org } = await mockOrg(t)
122  await t.rejects(
123    org.exec(['add', 'orgname', 'username', 'person']),
124    /`role` must be one of/,
125    'returns the correct error'
126  )
127})
128
129t.test('npm org add - more users', async t => {
130  const orgSize = 5
131  const { npm, org, outputs, setArgs } = await mockOrg(t, { orgSize })
132
133  await org.exec(['add', 'orgname', 'username'])
134  t.match(
135    setArgs(),
136    {
137      org: 'orgname',
138      user: 'username',
139      role: 'developer',
140      opts: npm.flatOptions,
141    },
142    'received the correct arguments'
143  )
144  t.equal(
145    outputs[0][0],
146    'Added username as developer to orgname. You now have 5 members in this org.',
147    'printed the correct output'
148  )
149})
150
151t.test('npm org add - json output', async t => {
152  const { npm, org, outputs, setArgs } = await mockOrg(t, {
153    config: { json: true },
154  })
155
156  await org.exec(['add', 'orgname', 'username'])
157
158  t.match(
159    setArgs(),
160    {
161      org: 'orgname',
162      user: 'username',
163      role: 'developer',
164      opts: npm.flatOptions,
165    },
166    'received the correct arguments'
167  )
168  t.strictSame(
169    JSON.parse(outputs[0]),
170    {
171      org: {
172        name: 'orgname',
173        size: 1,
174      },
175      user: 'username',
176      role: 'developer',
177    },
178    'printed the correct output'
179  )
180})
181
182t.test('npm org add - parseable output', async t => {
183  const config = { parseable: true }
184  const { npm, org, outputs, setArgs } = await mockOrg(t, {
185    config,
186  })
187
188  await org.exec(['add', 'orgname', 'username'])
189
190  t.match(
191    setArgs(),
192    {
193      org: 'orgname',
194      user: 'username',
195      role: 'developer',
196      opts: npm.flatOptions,
197    },
198    'received the correct arguments'
199  )
200  t.strictSame(
201    outputs.map(line => line[0].split(/\t/)),
202    [
203      ['org', 'orgsize', 'user', 'role'],
204      ['orgname', '1', 'username', 'developer'],
205    ],
206    'printed the correct output'
207  )
208})
209
210t.test('npm org add - silent output', async t => {
211  const config = { loglevel: 'silent' }
212  const { npm, org, outputs, setArgs } = await mockOrg(t, {
213    config,
214  })
215
216  await org.exec(['add', 'orgname', 'username'])
217
218  t.match(
219    setArgs(),
220    {
221      org: 'orgname',
222      user: 'username',
223      role: 'developer',
224      opts: npm.flatOptions,
225    },
226    'received the correct arguments'
227  )
228  t.strictSame(outputs, [], 'prints no output')
229})
230
231t.test('npm org rm', async t => {
232  const { npm, org, outputs, lsArgs, rmArgs } = await mockOrg(t)
233
234  await org.exec(['rm', 'orgname', 'username'])
235
236  t.match(
237    rmArgs(),
238    {
239      org: 'orgname',
240      user: 'username',
241      opts: npm.flatOptions,
242    },
243    'libnpmorg.rm received the correct args'
244  )
245  t.match(
246    lsArgs(),
247    {
248      org: 'orgname',
249      opts: npm.flatOptions,
250    },
251    'libnpmorg.ls received the correct args'
252  )
253  t.equal(
254    outputs[0][0],
255    'Successfully removed username from orgname. You now have 0 members in this org.',
256    'printed the correct output'
257  )
258})
259
260t.test('npm org rm - no org', async t => {
261  const { org } = await mockOrg(t)
262
263  await t.rejects(
264    org.exec(['rm', '', 'username']),
265    /`orgname` is required/,
266    'threw the correct error'
267  )
268})
269
270t.test('npm org rm - no user', async t => {
271  const { org } = await mockOrg(t)
272
273  await t.rejects(org.exec(['rm', 'orgname']), /`username` is required/, 'threw the correct error')
274})
275
276t.test('npm org rm - one user left', async t => {
277  const orgList = {
278    one: 'developer',
279  }
280  const { npm, org, outputs, lsArgs, rmArgs } = await mockOrg(t, {
281    orgList,
282  })
283
284  await org.exec(['rm', 'orgname', 'username'])
285
286  t.match(
287    rmArgs(),
288    {
289      org: 'orgname',
290      user: 'username',
291      opts: npm.flatOptions,
292    },
293    'libnpmorg.rm received the correct args'
294  )
295  t.match(
296    lsArgs(),
297    {
298      org: 'orgname',
299      opts: npm.flatOptions,
300    },
301    'libnpmorg.ls received the correct args'
302  )
303  t.equal(
304    outputs[0][0],
305    'Successfully removed username from orgname. You now have 1 member in this org.',
306    'printed the correct output'
307  )
308})
309
310t.test('npm org rm - json output', async t => {
311  const config = { json: true }
312  const { npm, org, outputs, lsArgs, rmArgs } = await mockOrg(t, {
313    config,
314  })
315
316  await org.exec(['rm', 'orgname', 'username'])
317
318  t.match(
319    rmArgs(),
320    {
321      org: 'orgname',
322      user: 'username',
323      opts: npm.flatOptions,
324    },
325    'libnpmorg.rm received the correct args'
326  )
327  t.match(
328    lsArgs(),
329    {
330      org: 'orgname',
331      opts: npm.flatOptions,
332    },
333    'libnpmorg.ls received the correct args'
334  )
335  t.strictSame(
336    JSON.parse(outputs[0]),
337    {
338      user: 'username',
339      org: 'orgname',
340      userCount: 0,
341      deleted: true,
342    },
343    'printed the correct output'
344  )
345})
346
347t.test('npm org rm - parseable output', async t => {
348  const config = { parseable: true }
349  const { npm, org, outputs, lsArgs, rmArgs } = await mockOrg(t, {
350    config,
351  })
352
353  await org.exec(['rm', 'orgname', 'username'])
354
355  t.match(
356    rmArgs(),
357    {
358      org: 'orgname',
359      user: 'username',
360      opts: npm.flatOptions,
361    },
362    'libnpmorg.rm received the correct args'
363  )
364  t.match(
365    lsArgs(),
366    {
367      org: 'orgname',
368      opts: npm.flatOptions,
369    },
370    'libnpmorg.ls received the correct args'
371  )
372  t.strictSame(
373    outputs.map(line => line[0].split(/\t/)),
374    [
375      ['user', 'org', 'userCount', 'deleted'],
376      ['username', 'orgname', '0', 'true'],
377    ],
378    'printed the correct output'
379  )
380})
381
382t.test('npm org rm - silent output', async t => {
383  const config = { loglevel: 'silent' }
384  const { npm, org, outputs, lsArgs, rmArgs } = await mockOrg(t, {
385    config,
386  })
387
388  await org.exec(['rm', 'orgname', 'username'])
389
390  t.match(
391    rmArgs(),
392    {
393      org: 'orgname',
394      user: 'username',
395      opts: npm.flatOptions,
396    },
397    'libnpmorg.rm received the correct args'
398  )
399  t.match(
400    lsArgs(),
401    {
402      org: 'orgname',
403      opts: npm.flatOptions,
404    },
405    'libnpmorg.ls received the correct args'
406  )
407  t.strictSame(outputs, [], 'printed no output')
408})
409
410t.test('npm org ls', async t => {
411  const orgList = {
412    one: 'developer',
413    two: 'admin',
414    three: 'owner',
415  }
416  const { npm, org, outputs, lsArgs } = await mockOrg(t, {
417    orgList,
418  })
419
420  await org.exec(['ls', 'orgname'])
421
422  t.match(
423    lsArgs(),
424    {
425      org: 'orgname',
426      opts: npm.flatOptions,
427    },
428    'receieved the correct args'
429  )
430  const out = stripVTControlCharacters(outputs[0][0])
431  t.match(out, /one.*developer/, 'contains the developer member')
432  t.match(out, /two.*admin/, 'contains the admin member')
433  t.match(out, /three.*owner/, 'contains the owner member')
434})
435
436t.test('npm org ls - user filter', async t => {
437  const orgList = {
438    username: 'admin',
439    missing: 'admin',
440  }
441  const { npm, org, outputs, lsArgs } = await mockOrg(t, {
442    orgList,
443  })
444
445  await org.exec(['ls', 'orgname', 'username'])
446
447  t.match(
448    lsArgs(),
449    {
450      org: 'orgname',
451      opts: npm.flatOptions,
452    },
453    'receieved the correct args'
454  )
455  const out = stripVTControlCharacters(outputs[0][0])
456  t.match(out, /username.*admin/, 'contains the filtered member')
457  t.notMatch(out, /missing.*admin/, 'does not contain other members')
458})
459
460t.test('npm org ls - user filter, missing user', async t => {
461  const orgList = {
462    missing: 'admin',
463  }
464  const { npm, org, outputs, lsArgs } = await mockOrg(t, {
465    orgList,
466  })
467
468  await org.exec(['ls', 'orgname', 'username'])
469
470  t.match(
471    lsArgs(),
472    {
473      org: 'orgname',
474      opts: npm.flatOptions,
475    },
476    'receieved the correct args'
477  )
478  const out = stripVTControlCharacters(outputs[0][0])
479  t.notMatch(out, /username/, 'does not contain the requested member')
480  t.notMatch(out, /missing.*admin/, 'does not contain other members')
481})
482
483t.test('npm org ls - no org', async t => {
484  const { org } = await mockOrg(t)
485  await t.rejects(org.exec(['ls']), /`orgname` is required/, 'throws the correct error')
486})
487
488t.test('npm org ls - json output', async t => {
489  const config = { json: true }
490  const orgList = {
491    one: 'developer',
492    two: 'admin',
493    three: 'owner',
494  }
495  const { npm, org, outputs, lsArgs } = await mockOrg(t, {
496    orgList,
497    config,
498  })
499
500  await org.exec(['ls', 'orgname'])
501
502  t.match(
503    lsArgs(),
504    {
505      org: 'orgname',
506      opts: npm.flatOptions,
507    },
508    'receieved the correct args'
509  )
510  t.strictSame(JSON.parse(outputs[0]), orgList, 'prints the correct output')
511})
512
513t.test('npm org ls - parseable output', async t => {
514  const config = { parseable: true }
515  const orgList = {
516    one: 'developer',
517    two: 'admin',
518    three: 'owner',
519  }
520  const { npm, org, outputs, lsArgs } = await mockOrg(t, {
521    orgList,
522    config,
523  })
524
525  await org.exec(['ls', 'orgname'])
526
527  t.match(
528    lsArgs(),
529    {
530      org: 'orgname',
531      opts: npm.flatOptions,
532    },
533    'receieved the correct args'
534  )
535  t.strictSame(
536    outputs.map(line => line[0].split(/\t/)),
537    [
538      ['user', 'role'],
539      ['one', 'developer'],
540      ['two', 'admin'],
541      ['three', 'owner'],
542    ],
543    'printed the correct output'
544  )
545})
546
547t.test('npm org ls - silent output', async t => {
548  const config = { loglevel: 'silent' }
549  const orgList = {
550    one: 'developer',
551    two: 'admin',
552    three: 'owner',
553  }
554  const { npm, org, outputs, lsArgs } = await mockOrg(t, {
555    orgList,
556    config,
557  })
558
559  await org.exec(['ls', 'orgname'])
560
561  t.match(
562    lsArgs(),
563    {
564      org: 'orgname',
565      opts: npm.flatOptions,
566    },
567    'receieved the correct args'
568  )
569  t.strictSame(outputs, [], 'printed no output')
570})
571