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