1// TODO(isaacs): This test has a lot of very large objects pasted inline. 2// Consider using t.matchSnapshot on these instead, especially since many 3// of them contain the tap testdir folders, which are auto-generated and 4// may change when node-tap is updated. 5 6const t = require('tap') 7const { utimesSync } = require('fs') 8const mockNpm = require('../../fixtures/mock-npm.js') 9const { cleanCwd } = require('../../fixtures/clean-snapshot') 10 11const touchHiddenPackageLock = prefix => { 12 const later = new Date(Date.now() + 10000) 13 utimesSync(`${prefix}/node_modules/.package-lock.json`, later, later) 14} 15 16t.cleanSnapshot = str => cleanCwd(str) 17 18const simpleNmFixture = { 19 node_modules: { 20 foo: { 21 'package.json': JSON.stringify({ 22 name: 'foo', 23 version: '1.0.0', 24 dependencies: { 25 dog: '^1.0.0', 26 }, 27 }), 28 }, 29 dog: { 30 'package.json': JSON.stringify({ 31 name: 'dog', 32 version: '1.0.0', 33 }), 34 }, 35 chai: { 36 'package.json': JSON.stringify({ 37 name: 'chai', 38 version: '1.0.0', 39 }), 40 }, 41 }, 42} 43 44const diffDepTypesNmFixture = { 45 node_modules: { 46 'dev-dep': { 47 'package.json': JSON.stringify({ 48 name: 'dev-dep', 49 description: 'A DEV dep kind of dep', 50 version: '1.0.0', 51 dependencies: { 52 foo: '^1.0.0', 53 }, 54 }), 55 }, 56 'prod-dep': { 57 'package.json': JSON.stringify({ 58 name: 'prod-dep', 59 description: 'A PROD dep kind of dep', 60 version: '1.0.0', 61 dependencies: { 62 dog: '^2.0.0', 63 }, 64 }), 65 node_modules: { 66 dog: { 67 'package.json': JSON.stringify({ 68 name: 'dog', 69 description: 'A dep that bars', 70 version: '2.0.0', 71 }), 72 }, 73 }, 74 }, 75 'optional-dep': { 76 'package.json': JSON.stringify({ 77 name: 'optional-dep', 78 description: 'Maybe a dep?', 79 version: '1.0.0', 80 }), 81 }, 82 'peer-dep': { 83 'package.json': JSON.stringify({ 84 name: 'peer-dep', 85 description: 'Peer-dep description here', 86 version: '1.0.0', 87 }), 88 }, 89 ...simpleNmFixture.node_modules, 90 }, 91} 92 93const mockLs = async (t, { mocks, config, ...opts } = {}) => { 94 const mock = await mockNpm(t, { 95 ...opts, 96 config: { 97 all: true, 98 ...config, 99 }, 100 command: 'ls', 101 mocks: { 102 path: { 103 ...require('path'), 104 sep: '/', 105 }, 106 ...mocks, 107 }, 108 }) 109 110 return { 111 ...mock, 112 result: () => mock.joinedOutput(), 113 } 114} 115 116const redactCwdObj = obj => { 117 if (Array.isArray(obj)) { 118 return obj.map(o => redactCwdObj(o)) 119 } 120 if (obj && typeof obj === 'object') { 121 return Object.keys(obj).reduce((o, k) => { 122 o[k] = redactCwdObj(obj[k]) 123 return o 124 }, {}) 125 } 126 return typeof obj === 'string' ? cleanCwd(obj) : obj 127} 128 129const jsonParse = res => redactCwdObj(JSON.parse(res)) 130 131t.test('ls', async t => { 132 t.test('no args', async t => { 133 const { result, ls } = await mockLs(t, { 134 // config: {}, 135 prefixDir: { 136 'package.json': JSON.stringify({ 137 name: 'test-npm-ls', 138 version: '1.0.0', 139 dependencies: { 140 foo: '^1.0.0', 141 chai: '^1.0.0', 142 }, 143 }), 144 ...simpleNmFixture, 145 }, 146 }) 147 await ls.exec([]) 148 t.matchSnapshot( 149 cleanCwd(result()), 150 'should output tree representation of dependencies structure' 151 ) 152 }) 153 154 t.test('missing package.json', async t => { 155 const { result, ls } = await mockLs(t, { 156 config: {}, 157 prefixDir: { 158 ...simpleNmFixture, 159 }, 160 }) 161 await ls.exec([]) 162 t.matchSnapshot( 163 cleanCwd(result()), 164 'should output tree missing name/version of top-level package' 165 ) 166 }) 167 168 t.test('workspace and missing optional dep', async t => { 169 const config = { 170 'include-workspace-root': true, 171 workspace: 'baz', 172 } 173 const { result, ls } = await mockLs(t, { 174 config, 175 prefixDir: { 176 'package.json': JSON.stringify({ 177 name: 'root', 178 dependencies: { 179 foo: '^1.0.0', 180 }, 181 optionalDependencies: { 182 bar: '^1.0.0', 183 }, 184 workspaces: ['./baz'], 185 }), 186 baz: { 187 'package.json': JSON.stringify({ 188 name: 'baz', 189 version: '1.0.0', 190 }), 191 }, 192 node_modules: { 193 baz: t.fixture('symlink', '../baz'), 194 foo: { 195 'package.json': JSON.stringify({ 196 name: 'foo', 197 version: '1.0.0', 198 }), 199 }, 200 }, 201 }, 202 }) 203 204 await ls.exec([]) 205 t.matchSnapshot(cleanCwd(result()), 'should omit missing optional dep') 206 }) 207 208 t.test('extraneous deps', async t => { 209 const { result, ls } = await mockLs(t, { 210 config: {}, 211 prefixDir: { 212 'package.json': JSON.stringify({ 213 name: 'test-npm-ls', 214 version: '1.0.0', 215 dependencies: { 216 foo: '^1.0.0', 217 }, 218 }), 219 ...simpleNmFixture, 220 }, 221 }) 222 await ls.exec([]) 223 t.matchSnapshot(cleanCwd(result()), 'should output containing problems info') 224 }) 225 226 t.test('overridden dep', async t => { 227 const config = { 228 } 229 230 const { result, ls } = await mockLs(t, { 231 config, 232 prefixDir: { 233 'package.json': JSON.stringify({ 234 name: 'test-overridden', 235 version: '1.0.0', 236 dependencies: { 237 foo: '^1.0.0', 238 }, 239 overrides: { 240 bar: '1.0.0', 241 }, 242 }), 243 node_modules: { 244 foo: { 245 'package.json': JSON.stringify({ 246 name: 'foo', 247 version: '1.0.0', 248 dependencies: { 249 bar: '^2.0.0', 250 }, 251 }), 252 }, 253 bar: { 254 'package.json': JSON.stringify({ 255 name: 'bar', 256 version: '1.0.0', 257 }), 258 }, 259 }, 260 }, 261 }) 262 263 await 264 265 ls.exec([]) 266 t.matchSnapshot(cleanCwd(result()), 'should contain overridden outout') 267 }) 268 269 t.test('overridden dep w/ color', async t => { 270 const config = { 271 color: 'always', 272 } 273 274 const { result, ls } = await mockLs(t, { 275 config, 276 prefixDir: { 277 'package.json': JSON.stringify({ 278 name: 'test-overridden', 279 version: '1.0.0', 280 dependencies: { 281 foo: '^1.0.0', 282 }, 283 overrides: { 284 bar: '1.0.0', 285 }, 286 }), 287 node_modules: { 288 foo: { 289 'package.json': JSON.stringify({ 290 name: 'foo', 291 version: '1.0.0', 292 dependencies: { 293 bar: '^2.0.0', 294 }, 295 }), 296 }, 297 bar: { 298 'package.json': JSON.stringify({ 299 name: 'bar', 300 version: '1.0.0', 301 }), 302 }, 303 }, 304 }, 305 }) 306 307 await ls.exec([]) 308 t.matchSnapshot(cleanCwd(result()), 'should contain overridden outout') 309 }) 310 311 t.test('with filter arg', async t => { 312 const config = { 313 color: 'always', 314 } 315 const { result, ls } = await mockLs(t, { 316 config, 317 prefixDir: { 318 'package.json': JSON.stringify({ 319 name: 'test-npm-ls', 320 version: '1.0.0', 321 dependencies: { 322 foo: '^1.0.0', 323 chai: '^1.0.0', 324 }, 325 }), 326 ...simpleNmFixture, 327 }, 328 }) 329 await ls.exec(['chai']) 330 t.matchSnapshot( 331 cleanCwd(result()), 332 'should output tree contaning only occurrences of filtered by package and colored output' 333 ) 334 }) 335 336 t.test('with dot filter arg', async t => { 337 const config = { 338 all: false, 339 depth: 0, 340 } 341 const { result, ls } = await mockLs(t, { 342 config, 343 prefixDir: { 344 'package.json': JSON.stringify({ 345 name: 'test-npm-ls', 346 version: '1.0.0', 347 dependencies: { 348 foo: '^1.0.0', 349 ipsum: '^1.0.0', 350 }, 351 }), 352 ...simpleNmFixture, 353 }, 354 }) 355 await ls.exec(['.']) 356 t.matchSnapshot( 357 cleanCwd(result()), 358 'should output tree contaning only occurrences of filtered by package and colored output' 359 ) 360 }) 361 362 t.test('with filter arg nested dep', async t => { 363 const { result, ls } = await mockLs(t, { 364 config: {}, 365 prefixDir: { 366 'package.json': JSON.stringify({ 367 name: 'test-npm-ls', 368 version: '1.0.0', 369 dependencies: { 370 foo: '^1.0.0', 371 chai: '^1.0.0', 372 }, 373 }), 374 ...simpleNmFixture, 375 }, 376 }) 377 await ls.exec(['dog']) 378 t.matchSnapshot( 379 cleanCwd(result()), 380 'should output tree contaning only occurrences of filtered package and its ancestors' 381 ) 382 }) 383 384 t.test('with multiple filter args', async t => { 385 const { result, ls } = await mockLs(t, { 386 config: {}, 387 prefixDir: { 388 'package.json': JSON.stringify({ 389 name: 'test-npm-ls', 390 version: '1.0.0', 391 dependencies: { 392 foo: '^1.0.0', 393 chai: '^1.0.0', 394 ipsum: '^1.0.0', 395 }, 396 }), 397 node_modules: { 398 ...simpleNmFixture.node_modules, 399 ipsum: { 400 'package.json': JSON.stringify({ 401 name: 'ipsum', 402 version: '1.0.0', 403 }), 404 }, 405 }, 406 }, 407 }) 408 await ls.exec(['dog@*', 'chai@1.0.0']) 409 t.matchSnapshot( 410 cleanCwd(result()), 411 /* eslint-disable-next-line max-len */ 412 'should output tree contaning only occurrences of multiple filtered packages and their ancestors' 413 ) 414 }) 415 416 t.test('with missing filter arg', async t => { 417 const { result, ls } = await mockLs(t, { 418 config: {}, 419 prefixDir: { 420 'package.json': JSON.stringify({ 421 name: 'test-npm-ls', 422 version: '1.0.0', 423 dependencies: { 424 foo: '^1.0.0', 425 chai: '^1.0.0', 426 }, 427 }), 428 ...simpleNmFixture, 429 }, 430 }) 431 await ls.exec(['notadep']) 432 t.matchSnapshot(cleanCwd(result()), 'should output tree containing no dependencies info') 433 t.equal(process.exitCode, 1, 'should exit with error code 1') 434 }) 435 436 t.test('default --depth value should be 0', async t => { 437 const config = { 438 all: false, 439 } 440 const { result, ls } = await mockLs(t, { 441 config, 442 prefixDir: { 443 'package.json': JSON.stringify({ 444 name: 'test-npm-ls', 445 version: '1.0.0', 446 dependencies: { 447 foo: '^1.0.0', 448 chai: '^1.0.0', 449 }, 450 }), 451 ...simpleNmFixture, 452 }, 453 }) 454 await ls.exec([]) 455 t.matchSnapshot(cleanCwd(result()), 456 'should output tree containing only top-level dependencies') 457 }) 458 459 t.test('--depth=0', async t => { 460 const config = { 461 all: false, 462 depth: 0, 463 } 464 const { result, ls } = await mockLs(t, { 465 config, 466 prefixDir: { 467 'package.json': JSON.stringify({ 468 name: 'test-npm-ls', 469 version: '1.0.0', 470 dependencies: { 471 foo: '^1.0.0', 472 chai: '^1.0.0', 473 }, 474 }), 475 ...simpleNmFixture, 476 }, 477 }) 478 await ls.exec([]) 479 t.matchSnapshot(cleanCwd(result()), 480 'should output tree containing only top-level dependencies') 481 }) 482 483 t.test('--depth=1', async t => { 484 const config = { 485 all: false, 486 depth: 1, 487 } 488 const { result, ls } = await mockLs(t, { 489 config, 490 prefixDir: { 491 'package.json': JSON.stringify({ 492 name: 'test-npm-ls', 493 version: '1.0.0', 494 dependencies: { 495 a: '^1.0.0', 496 e: '^1.0.0', 497 }, 498 }), 499 node_modules: { 500 a: { 501 'package.json': JSON.stringify({ 502 name: 'a', 503 version: '1.0.0', 504 dependencies: { 505 b: '^1.0.0', 506 }, 507 }), 508 }, 509 b: { 510 'package.json': JSON.stringify({ 511 name: 'b', 512 version: '1.0.0', 513 dependencies: { 514 c: '^1.0.0', 515 d: '*', 516 }, 517 }), 518 }, 519 c: { 520 'package.json': JSON.stringify({ 521 name: 'c', 522 version: '1.0.0', 523 }), 524 }, 525 d: { 526 'package.json': JSON.stringify({ 527 name: 'd', 528 version: '1.0.0', 529 }), 530 }, 531 e: { 532 'package.json': JSON.stringify({ 533 name: 'e', 534 version: '1.0.0', 535 }), 536 }, 537 }, 538 }, 539 }) 540 await ls.exec([]) 541 t.matchSnapshot( 542 cleanCwd(result()), 543 'should output tree containing top-level deps and their deps only' 544 ) 545 }) 546 547 t.test('missing/invalid/extraneous', async t => { 548 t.plan(3) 549 const { result, ls } = await mockLs(t, { 550 config: {}, 551 prefixDir: { 552 'package.json': JSON.stringify({ 553 name: 'test-npm-ls', 554 version: '1.0.0', 555 dependencies: { 556 foo: '^2.0.0', 557 ipsum: '^1.0.0', 558 }, 559 }), 560 ...simpleNmFixture, 561 }, 562 }) 563 await ls.exec([]).catch(err => { 564 t.equal(err.code, 'ELSPROBLEMS', 'should have error code') 565 t.equal( 566 cleanCwd(err.message), 567 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai\n' + 568 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo\n' + 569 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', 570 'should log missing/invalid/extraneous errors' 571 ) 572 }) 573 t.matchSnapshot( 574 cleanCwd(result()), 575 'should output tree containing missing, invalid, extraneous labels' 576 ) 577 }) 578 579 t.test('colored output', async t => { 580 const config = { 581 color: 'always', 582 } 583 const { result, ls } = await mockLs(t, { 584 config, 585 prefixDir: { 586 'package.json': JSON.stringify({ 587 name: 'test-npm-ls', 588 version: '1.0.0', 589 dependencies: { 590 foo: '^2.0.0', 591 ipsum: '^1.0.0', 592 }, 593 }), 594 ...simpleNmFixture, 595 }, 596 }) 597 await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should have error code') 598 t.matchSnapshot(cleanCwd(result()), 'should output tree containing color info') 599 }) 600 601 t.test('--dev', async t => { 602 const { result, ls } = await mockLs(t, { 603 config: { 604 omit: ['peer', 'prod', 'optional'], 605 }, 606 prefixDir: { 607 'package.json': JSON.stringify({ 608 name: 'test-npm-ls', 609 version: '1.0.0', 610 dependencies: { 611 'prod-dep': '^1.0.0', 612 chai: '^1.0.0', 613 }, 614 devDependencies: { 615 'dev-dep': '^1.0.0', 616 }, 617 optionalDependencies: { 618 'optional-dep': '^1.0.0', 619 }, 620 peerDependencies: { 621 'peer-dep': '^1.0.0', 622 }, 623 }), 624 ...diffDepTypesNmFixture, 625 }, 626 }) 627 await ls.exec([]) 628 t.matchSnapshot(cleanCwd(result()), 'should output tree containing dev deps') 629 }) 630 631 t.test('--link', async t => { 632 const config = { 633 link: true, 634 } 635 const { result, ls } = await mockLs(t, { 636 config, 637 prefixDir: { 638 'package.json': JSON.stringify({ 639 name: 'test-npm-ls', 640 version: '1.0.0', 641 dependencies: { 642 'prod-dep': '^1.0.0', 643 chai: '^1.0.0', 644 'linked-dep': '^1.0.0', 645 }, 646 devDependencies: { 647 'dev-dep': '^1.0.0', 648 }, 649 optionalDependencies: { 650 'optional-dep': '^1.0.0', 651 }, 652 peerDependencies: { 653 'peer-dep': '^1.0.0', 654 }, 655 }), 656 'linked-dep': { 657 'package.json': JSON.stringify({ 658 name: 'linked-dep', 659 version: '1.0.0', 660 }), 661 }, 662 node_modules: { 663 'linked-dep': t.fixture('symlink', '../linked-dep'), 664 ...diffDepTypesNmFixture.node_modules, 665 }, 666 }, 667 }) 668 await ls.exec([]) 669 t.matchSnapshot(cleanCwd(result()), 'should output tree containing linked deps') 670 }) 671 672 t.test('print deduped symlinks', async t => { 673 const { result, ls } = await mockLs(t, { 674 config: {}, 675 prefixDir: { 676 'package.json': JSON.stringify({ 677 name: 'print-deduped-symlinks', 678 version: '1.0.0', 679 dependencies: { 680 a: '^1.0.0', 681 b: '^1.0.0', 682 }, 683 }), 684 b: { 685 'package.json': JSON.stringify({ 686 name: 'b', 687 version: '1.0.0', 688 }), 689 }, 690 node_modules: { 691 a: { 692 'package.json': JSON.stringify({ 693 name: 'a', 694 version: '1.0.0', 695 dependencies: { 696 b: '^1.0.0', 697 }, 698 }), 699 }, 700 b: t.fixture('symlink', '../b'), 701 }, 702 }, 703 }) 704 await ls.exec([]) 705 t.matchSnapshot(cleanCwd(result()), 'should output tree containing linked deps') 706 }) 707 708 t.test('--production', async t => { 709 const { result, ls } = await mockLs(t, { 710 config: { omit: ['dev', 'peer'] }, 711 prefixDir: { 712 'package.json': JSON.stringify({ 713 name: 'test-npm-ls', 714 version: '1.0.0', 715 dependencies: { 716 'prod-dep': '^1.0.0', 717 chai: '^1.0.0', 718 }, 719 devDependencies: { 720 'dev-dep': '^1.0.0', 721 }, 722 optionalDependencies: { 723 'optional-dep': '^1.0.0', 724 }, 725 peerDependencies: { 726 'peer-dep': '^1.0.0', 727 }, 728 }), 729 ...diffDepTypesNmFixture, 730 }, 731 }) 732 await ls.exec([]) 733 t.matchSnapshot(cleanCwd(result()), 'should output tree containing production deps') 734 }) 735 736 t.test('--long', async t => { 737 const config = { 738 long: true, 739 } 740 const { result, ls } = await mockLs(t, { 741 config, 742 prefixDir: { 743 'package.json': JSON.stringify({ 744 name: 'test-npm-ls', 745 version: '1.0.0', 746 dependencies: { 747 'prod-dep': '^1.0.0', 748 chai: '^1.0.0', 749 }, 750 devDependencies: { 751 'dev-dep': '^1.0.0', 752 }, 753 optionalDependencies: { 754 'optional-dep': '^1.0.0', 755 }, 756 peerDependencies: { 757 'peer-dep': '^1.0.0', 758 }, 759 }), 760 ...diffDepTypesNmFixture, 761 }, 762 }) 763 await ls.exec([]) 764 t.matchSnapshot(cleanCwd(result()), 'should output tree info with descriptions') 765 }) 766 767 t.test('--long --depth=0', async t => { 768 const config = { 769 all: false, 770 depth: 0, 771 long: true, 772 } 773 const { result, ls } = await mockLs(t, { 774 config, 775 prefixDir: { 776 'package.json': JSON.stringify({ 777 name: 'test-npm-ls', 778 version: '1.0.0', 779 dependencies: { 780 'prod-dep': '^1.0.0', 781 chai: '^1.0.0', 782 }, 783 devDependencies: { 784 'dev-dep': '^1.0.0', 785 }, 786 optionalDependencies: { 787 'optional-dep': '^1.0.0', 788 }, 789 peerDependencies: { 790 'peer-dep': '^1.0.0', 791 }, 792 }), 793 ...diffDepTypesNmFixture, 794 }, 795 }) 796 await ls.exec([]) 797 t.matchSnapshot( 798 cleanCwd(result()), 799 'should output tree containing top-level deps with descriptions' 800 ) 801 }) 802 803 t.test('json read problems', async t => { 804 const { result, ls } = await mockLs(t, { 805 config: {}, 806 prefixDir: { 807 'package.json': '{broken json', 808 }, 809 }) 810 await t.rejects(ls.exec([]), { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error') 811 t.matchSnapshot(cleanCwd(result()), 'should print empty result') 812 }) 813 814 t.test('empty location', async t => { 815 const { ls, result } = await mockLs(t) 816 await ls.exec([]) 817 t.matchSnapshot(cleanCwd(result()), 'should print empty result') 818 }) 819 820 t.test('invalid peer dep', async t => { 821 const { result, ls } = await mockLs(t, { 822 config: {}, 823 prefixDir: { 824 'package.json': JSON.stringify({ 825 name: 'test-npm-ls', 826 version: '1.0.0', 827 dependencies: { 828 'prod-dep': '^1.0.0', 829 chai: '^1.0.0', 830 }, 831 devDependencies: { 832 'dev-dep': '^1.0.0', 833 }, 834 optionalDependencies: { 835 'optional-dep': '^1.0.0', 836 }, 837 peerDependencies: { 838 'peer-dep': '^2.0.0', // mismatching version # 839 }, 840 }), 841 ...diffDepTypesNmFixture, 842 }, 843 }) 844 await t.rejects(ls.exec([])) 845 t.matchSnapshot( 846 cleanCwd(result()), 847 'should output tree signaling mismatching peer dep in problems' 848 ) 849 }) 850 851 t.test('invalid deduped dep', async t => { 852 const config = { 853 color: 'always', 854 } 855 const { result, ls } = await mockLs(t, { 856 config, 857 prefixDir: { 858 'package.json': JSON.stringify({ 859 name: 'invalid-deduped-dep', 860 version: '1.0.0', 861 dependencies: { 862 a: '^1.0.0', 863 b: '^2.0.0', 864 }, 865 }), 866 node_modules: { 867 a: { 868 'package.json': JSON.stringify({ 869 name: 'a', 870 version: '1.0.0', 871 dependencies: { 872 b: '^2.0.0', 873 }, 874 }), 875 }, 876 b: { 877 'package.json': JSON.stringify({ 878 name: 'b', 879 version: '1.0.0', 880 }), 881 }, 882 }, 883 }, 884 }) 885 await t.rejects(ls.exec([])) 886 t.matchSnapshot( 887 cleanCwd(result()), 888 'should output tree signaling mismatching peer dep in problems' 889 ) 890 }) 891 892 t.test('deduped missing dep', async t => { 893 const { result, ls } = await mockLs(t, { 894 config: {}, 895 prefixDir: { 896 'package.json': JSON.stringify({ 897 name: 'test-npm-ls', 898 version: '1.0.0', 899 dependencies: { 900 a: '^1.0.0', 901 b: '^1.0.0', 902 }, 903 }), 904 node_modules: { 905 a: { 906 'package.json': JSON.stringify({ 907 name: 'a', 908 version: '1.0.0', 909 dependencies: { 910 b: '^1.0.0', 911 }, 912 }), 913 }, 914 }, 915 }, 916 }) 917 await t.rejects( 918 ls.exec([]), 919 { code: 'ELSPROBLEMS', message: /missing: b@\^1.0.0/ }, 920 'should list missing dep problem' 921 ) 922 t.matchSnapshot( 923 cleanCwd(result()), 924 'should output parseable signaling missing peer dep in problems' 925 ) 926 }) 927 928 t.test('unmet peer dep', async t => { 929 const { result, ls } = await mockLs(t, { 930 config: {}, 931 prefixDir: { 932 'package.json': JSON.stringify({ 933 name: 'test-npm-ls', 934 version: '1.0.0', 935 peerDependencies: { 936 'peer-dep': '*', 937 }, 938 }), 939 }, 940 }) 941 await t.rejects( 942 ls.exec([]), 943 { code: 'ELSPROBLEMS', message: 'missing: peer-dep@*, required by test-npm-ls@1.0.0' }, 944 'should have missing peer-dep error msg' 945 ) 946 t.matchSnapshot(cleanCwd(result()), 947 'should output tree signaling missing peer dep in problems') 948 }) 949 950 t.test('unmet optional dep', async t => { 951 const config = { color: 'always' } 952 const { result, ls } = await mockLs(t, { 953 config, 954 prefixDir: { 955 'package.json': JSON.stringify({ 956 name: 'test-npm-ls', 957 version: '1.0.0', 958 dependencies: { 959 'prod-dep': '^1.0.0', 960 chai: '^1.0.0', 961 }, 962 devDependencies: { 963 'dev-dep': '^1.0.0', 964 }, 965 optionalDependencies: { 966 'missing-optional-dep': '^1.0.0', 967 'optional-dep': '^2.0.0', // mismatching version # 968 }, 969 peerDependencies: { 970 'peer-dep': '^1.0.0', 971 }, 972 }), 973 ...diffDepTypesNmFixture, 974 }, 975 }) 976 await t.rejects( 977 ls.exec([]), 978 { code: 'ELSPROBLEMS', message: /invalid: optional-dep@1.0.0/ }, 979 'should have invalid dep error msg' 980 ) 981 t.matchSnapshot( 982 cleanCwd(result()), 983 'should output tree with empty entry for missing optional deps' 984 ) 985 }) 986 987 t.test('cycle deps', async t => { 988 const { result, ls } = await mockLs(t, { 989 config: {}, 990 prefixDir: { 991 'package.json': JSON.stringify({ 992 name: 'test-npm-ls', 993 version: '1.0.0', 994 dependencies: { 995 a: '^1.0.0', 996 }, 997 }), 998 node_modules: { 999 a: { 1000 'package.json': JSON.stringify({ 1001 name: 'a', 1002 version: '1.0.0', 1003 dependencies: { 1004 b: '^1.0.0', 1005 }, 1006 }), 1007 }, 1008 b: { 1009 'package.json': JSON.stringify({ 1010 name: 'b', 1011 version: '1.0.0', 1012 dependencies: { 1013 a: '^1.0.0', 1014 }, 1015 }), 1016 }, 1017 }, 1018 }, 1019 }) 1020 await ls.exec([]) 1021 t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref') 1022 }) 1023 1024 t.test('cycle deps with filter args', async t => { 1025 const config = { color: 'always' } 1026 const { result, ls } = await mockLs(t, { 1027 config, 1028 prefixDir: { 1029 'package.json': JSON.stringify({ 1030 name: 'test-npm-ls', 1031 version: '1.0.0', 1032 dependencies: { 1033 a: '^1.0.0', 1034 }, 1035 }), 1036 node_modules: { 1037 a: { 1038 'package.json': JSON.stringify({ 1039 name: 'a', 1040 version: '1.0.0', 1041 dependencies: { 1042 b: '^1.0.0', 1043 }, 1044 }), 1045 }, 1046 b: { 1047 'package.json': JSON.stringify({ 1048 name: 'b', 1049 version: '1.0.0', 1050 dependencies: { 1051 a: '^1.0.0', 1052 }, 1053 }), 1054 }, 1055 }, 1056 }, 1057 }) 1058 await ls.exec(['a']) 1059 t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref') 1060 }) 1061 1062 t.test('with no args dedupe entries', async t => { 1063 const { result, ls } = await mockLs(t, { 1064 config: {}, 1065 prefixDir: { 1066 'package.json': JSON.stringify({ 1067 name: 'dedupe-entries', 1068 version: '1.0.0', 1069 dependencies: { 1070 '@npmcli/a': '^1.0.0', 1071 '@npmcli/b': '^1.0.0', 1072 '@npmcli/c': '^1.0.0', 1073 }, 1074 }), 1075 node_modules: { 1076 '@npmcli': { 1077 a: { 1078 'package.json': JSON.stringify({ 1079 name: '@npmcli/a', 1080 version: '1.0.0', 1081 dependencies: { 1082 '@npmcli/b': '^1.0.0', 1083 }, 1084 }), 1085 }, 1086 b: { 1087 'package.json': JSON.stringify({ 1088 name: '@npmcli/b', 1089 version: '1.1.2', 1090 }), 1091 }, 1092 c: { 1093 'package.json': JSON.stringify({ 1094 name: '@npmcli/c', 1095 version: '1.0.0', 1096 dependencies: { 1097 '@npmcli/b': '^1.0.0', 1098 }, 1099 }), 1100 }, 1101 }, 1102 }, 1103 }, 1104 }) 1105 await ls.exec([]) 1106 t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref') 1107 }) 1108 1109 t.test('with no args dedupe entries and not displaying all', async t => { 1110 const config = { 1111 all: false, 1112 depth: 0, 1113 } 1114 const { result, ls } = await mockLs(t, { 1115 config, 1116 prefixDir: { 1117 'package.json': JSON.stringify({ 1118 name: 'dedupe-entries', 1119 version: '1.0.0', 1120 dependencies: { 1121 '@npmcli/a': '^1.0.0', 1122 '@npmcli/b': '^1.0.0', 1123 '@npmcli/c': '^1.0.0', 1124 }, 1125 }), 1126 node_modules: { 1127 '@npmcli': { 1128 a: { 1129 'package.json': JSON.stringify({ 1130 name: '@npmcli/a', 1131 version: '1.0.0', 1132 dependencies: { 1133 '@npmcli/b': '^1.0.0', 1134 }, 1135 }), 1136 }, 1137 b: { 1138 'package.json': JSON.stringify({ 1139 name: '@npmcli/b', 1140 version: '1.1.2', 1141 }), 1142 }, 1143 c: { 1144 'package.json': JSON.stringify({ 1145 name: '@npmcli/c', 1146 version: '1.0.0', 1147 dependencies: { 1148 '@npmcli/b': '^1.0.0', 1149 }, 1150 }), 1151 }, 1152 }, 1153 }, 1154 }, 1155 }) 1156 await ls.exec([]) 1157 t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref') 1158 }) 1159 1160 t.test('with args and dedupe entries', async t => { 1161 const config = { color: 'always' } 1162 const { result, ls } = await mockLs(t, { 1163 config, 1164 prefixDir: { 1165 'package.json': JSON.stringify({ 1166 name: 'dedupe-entries', 1167 version: '1.0.0', 1168 dependencies: { 1169 '@npmcli/a': '^1.0.0', 1170 '@npmcli/b': '^1.0.0', 1171 '@npmcli/c': '^1.0.0', 1172 }, 1173 }), 1174 node_modules: { 1175 '@npmcli': { 1176 a: { 1177 'package.json': JSON.stringify({ 1178 name: '@npmcli/a', 1179 version: '1.0.0', 1180 dependencies: { 1181 '@npmcli/b': '^1.0.0', 1182 }, 1183 }), 1184 }, 1185 b: { 1186 'package.json': JSON.stringify({ 1187 name: '@npmcli/b', 1188 version: '1.1.2', 1189 }), 1190 }, 1191 c: { 1192 'package.json': JSON.stringify({ 1193 name: '@npmcli/c', 1194 version: '1.0.0', 1195 dependencies: { 1196 '@npmcli/b': '^1.0.0', 1197 }, 1198 }), 1199 }, 1200 }, 1201 }, 1202 }, 1203 }) 1204 await ls.exec(['@npmcli/b']) 1205 t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref') 1206 }) 1207 1208 t.test('with args and different order of items', async t => { 1209 const { result, ls } = await mockLs(t, { 1210 config: {}, 1211 prefixDir: { 1212 'package.json': JSON.stringify({ 1213 name: 'dedupe-entries', 1214 version: '1.0.0', 1215 dependencies: { 1216 '@npmcli/a': '^1.0.0', 1217 '@npmcli/b': '^1.0.0', 1218 '@npmcli/c': '^1.0.0', 1219 }, 1220 }), 1221 node_modules: { 1222 '@npmcli': { 1223 a: { 1224 'package.json': JSON.stringify({ 1225 name: '@npmcli/a', 1226 version: '1.0.0', 1227 dependencies: { 1228 '@npmcli/c': '^1.0.0', 1229 }, 1230 }), 1231 }, 1232 b: { 1233 'package.json': JSON.stringify({ 1234 name: '@npmcli/b', 1235 version: '1.1.2', 1236 dependencies: { 1237 '@npmcli/c': '^1.0.0', 1238 }, 1239 }), 1240 }, 1241 c: { 1242 'package.json': JSON.stringify({ 1243 name: '@npmcli/c', 1244 version: '1.0.0', 1245 }), 1246 }, 1247 }, 1248 }, 1249 }, 1250 }) 1251 await ls.exec(['@npmcli/c']) 1252 t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref') 1253 }) 1254 1255 t.test('using aliases', async t => { 1256 const { npm, result, ls } = await mockLs(t, { 1257 config: {}, 1258 prefixDir: { 1259 'package.json': JSON.stringify({ 1260 name: 'test-npm-ls', 1261 version: '1.0.0', 1262 dependencies: { 1263 a: 'npm:b@1.0.0', 1264 }, 1265 }), 1266 node_modules: { 1267 '.package-lock.json': JSON.stringify({ 1268 packages: { 1269 'node_modules/a': { 1270 name: 'b', 1271 version: '1.0.0', 1272 from: 'a@npm:b', 1273 resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', 1274 requested: { 1275 type: 'alias', 1276 }, 1277 }, 1278 }, 1279 }), 1280 a: { 1281 'package.json': JSON.stringify({ 1282 name: 'b', 1283 version: '1.0.0', 1284 _from: 'a@npm:b', 1285 _resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', 1286 _requested: { 1287 type: 'alias', 1288 }, 1289 }), 1290 }, 1291 }, 1292 }, 1293 }) 1294 touchHiddenPackageLock(npm.prefix) 1295 await ls.exec([]) 1296 t.matchSnapshot(cleanCwd(result()), 'should output tree containing aliases') 1297 }) 1298 1299 t.test('resolved points to git ref', async t => { 1300 const { npm, result, ls } = await mockLs(t, { 1301 config: {}, 1302 prefixDir: { 1303 'package.json': JSON.stringify({ 1304 name: 'test-npm-ls', 1305 version: '1.0.0', 1306 dependencies: { 1307 abbrev: 'git+https://github.com/isaacs/abbrev-js.git', 1308 }, 1309 }), 1310 node_modules: { 1311 '.package-lock.json': JSON.stringify({ 1312 packages: { 1313 'node_modules/abbrev': { 1314 name: 'abbrev', 1315 version: '1.1.1', 1316 from: 'git+https://github.com/isaacs/abbrev-js.git', 1317 /* eslint-disable-next-line max-len */ 1318 resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', 1319 }, 1320 }, 1321 }), 1322 abbrev: { 1323 'package.json': JSON.stringify({ 1324 name: 'abbrev', 1325 version: '1.1.1', 1326 _id: 'abbrev@1.1.1', 1327 _from: 'git+https://github.com/isaacs/abbrev-js.git', 1328 /* eslint-disable-next-line max-len */ 1329 _resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', 1330 _requested: { 1331 type: 'git', 1332 raw: 'git+https:github.com/isaacs/abbrev-js.git', 1333 rawSpec: 'git+https:github.com/isaacs/abbrev-js.git', 1334 saveSpec: 'git+https://github.com/isaacs/abbrev-js.git', 1335 fetchSpec: 'https://github.com/isaacs/abbrev-js.git', 1336 gitCommittish: null, 1337 }, 1338 }), 1339 }, 1340 }, 1341 }, 1342 }) 1343 touchHiddenPackageLock(npm.prefix) 1344 await ls.exec([]) 1345 t.matchSnapshot(cleanCwd(result()), 'should output tree containing git refs') 1346 }) 1347 1348 t.test('broken resolved field', async t => { 1349 const { result, ls } = await mockLs(t, { 1350 config: {}, 1351 prefixDir: { 1352 node_modules: { 1353 a: { 1354 'package.json': JSON.stringify({ 1355 name: 'a', 1356 version: '1.0.1', 1357 }), 1358 }, 1359 }, 1360 'package-lock.json': JSON.stringify({ 1361 name: 'npm-broken-resolved-field-test', 1362 version: '1.0.0', 1363 lockfileVersion: 2, 1364 requires: true, 1365 packages: { 1366 '': { 1367 name: 'a', 1368 version: '1.0.1', 1369 }, 1370 }, 1371 dependencies: { 1372 a: { 1373 version: '1.0.1', 1374 resolved: 'foo@dog://b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', 1375 /* eslint-disable-next-line max-len */ 1376 integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==', 1377 }, 1378 }, 1379 }), 1380 'package.json': JSON.stringify({ 1381 name: 'npm-broken-resolved-field-test', 1382 version: '1.0.0', 1383 dependencies: { 1384 a: '^1.0.1', 1385 }, 1386 }), 1387 }, 1388 }) 1389 await ls.exec([]) 1390 t.matchSnapshot(cleanCwd(result()), 'should NOT print git refs in output tree') 1391 }) 1392 1393 t.test('from and resolved properties', async t => { 1394 const { npm, result, ls } = await mockLs(t, { 1395 config: {}, 1396 prefixDir: { 1397 'package.json': JSON.stringify({ 1398 name: 'test-npm-ls', 1399 version: '1.0.0', 1400 dependencies: { 1401 'simple-output': '^2.0.0', 1402 }, 1403 }), 1404 node_modules: { 1405 '.package-lock.json': JSON.stringify({ 1406 packages: { 1407 'node_modules/simple-output': { 1408 name: 'simple-output', 1409 version: '2.1.1', 1410 resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', 1411 shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', 1412 }, 1413 }, 1414 }), 1415 'simple-output': { 1416 'package.json': JSON.stringify({ 1417 name: 'simple-output', 1418 version: '2.1.1', 1419 _from: 'simple-output', 1420 _id: 'simple-output@2.1.1', 1421 _resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', 1422 _requested: { 1423 type: 'tag', 1424 registry: true, 1425 raw: 'simple-output', 1426 name: 'simple-output', 1427 escapedName: 'simple-output', 1428 rawSpec: '', 1429 saveSpec: null, 1430 fetchSpec: 'latest', 1431 }, 1432 _requiredBy: ['#USER', '/'], 1433 _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', 1434 _spec: 'simple-output', 1435 }), 1436 }, 1437 }, 1438 }, 1439 }) 1440 touchHiddenPackageLock(npm.prefix) 1441 await ls.exec([]) 1442 t.matchSnapshot(cleanCwd(result()), 'should not be printed in tree output') 1443 }) 1444 1445 t.test('global', async t => { 1446 const config = { 1447 global: true, 1448 } 1449 const { result, ls } = await mockLs(t, { 1450 config, 1451 globalPrefixDir: { 1452 node_modules: { 1453 a: { 1454 'package.json': JSON.stringify({ 1455 name: 'a', 1456 version: '1.0.0', 1457 }), 1458 }, 1459 b: { 1460 'package.json': JSON.stringify({ 1461 name: 'b', 1462 version: '1.0.0', 1463 }), 1464 node_modules: { 1465 c: { 1466 'package.json': JSON.stringify({ 1467 name: 'c', 1468 version: '1.0.0', 1469 }), 1470 }, 1471 }, 1472 }, 1473 }, 1474 }, 1475 }) 1476 1477 await ls.exec([]) 1478 t.matchSnapshot(cleanCwd(result()), 1479 'should print tree and not mark top-level items extraneous') 1480 }) 1481 1482 t.test('filtering by child of missing dep', async t => { 1483 const { result, ls } = await mockLs(t, { 1484 config: {}, 1485 prefixDir: { 1486 'package.json': JSON.stringify({ 1487 name: 'filter-by-child-of-missing-dep', 1488 version: '1.0.0', 1489 dependencies: { 1490 a: '^1.0.0', 1491 }, 1492 }), 1493 node_modules: { 1494 b: { 1495 'package.json': JSON.stringify({ 1496 name: 'b', 1497 version: '1.0.0', 1498 dependencies: { 1499 c: '^1.0.0', 1500 }, 1501 }), 1502 }, 1503 c: { 1504 'package.json': JSON.stringify({ 1505 name: 'c', 1506 version: '1.0.0', 1507 }), 1508 }, 1509 d: { 1510 'package.json': JSON.stringify({ 1511 name: 'd', 1512 version: '1.0.0', 1513 dependencies: { 1514 c: '^2.0.0', 1515 }, 1516 }), 1517 node_modules: { 1518 c: { 1519 'package.json': JSON.stringify({ 1520 name: 'c', 1521 version: '2.0.0', 1522 }), 1523 }, 1524 }, 1525 }, 1526 }, 1527 }, 1528 }) 1529 1530 await ls.exec(['c']) 1531 t.matchSnapshot( 1532 cleanCwd(result()), 1533 'should print tree and not duplicate child of missing items' 1534 ) 1535 }) 1536 1537 t.test('loading a tree containing workspaces', async t => { 1538 const mockWorkspaces = async (t, exec = [], config = {}) => { 1539 const { result, ls } = await mockLs(t, { 1540 config, 1541 prefixDir: { 1542 'package.json': JSON.stringify({ 1543 name: 'workspaces-tree', 1544 version: '1.0.0', 1545 workspaces: ['./a', './b', './d', './group/*'], 1546 dependencies: { pacote: '1.0.0' }, 1547 }), 1548 node_modules: { 1549 a: t.fixture('symlink', '../a'), 1550 b: t.fixture('symlink', '../b'), 1551 c: { 1552 'package.json': JSON.stringify({ 1553 name: 'c', 1554 version: '1.0.0', 1555 }), 1556 }, 1557 d: t.fixture('symlink', '../d'), 1558 e: t.fixture('symlink', '../group/e'), 1559 f: t.fixture('symlink', '../group/f'), 1560 foo: { 1561 'package.json': JSON.stringify({ 1562 name: 'foo', 1563 version: '1.1.1', 1564 dependencies: { 1565 bar: '^1.0.0', 1566 }, 1567 }), 1568 }, 1569 bar: { 1570 'package.json': JSON.stringify({ name: 'bar', version: '1.0.0' }), 1571 }, 1572 baz: { 1573 'package.json': JSON.stringify({ name: 'baz', version: '1.0.0' }), 1574 }, 1575 pacote: { 1576 'package.json': JSON.stringify({ name: 'pacote', version: '1.0.0' }), 1577 }, 1578 }, 1579 a: { 1580 'package.json': JSON.stringify({ 1581 name: 'a', 1582 version: '1.0.0', 1583 dependencies: { 1584 c: '^1.0.0', 1585 d: '^1.0.0', 1586 }, 1587 devDependencies: { 1588 baz: '^1.0.0', 1589 }, 1590 }), 1591 }, 1592 b: { 1593 'package.json': JSON.stringify({ 1594 name: 'b', 1595 version: '1.0.0', 1596 }), 1597 }, 1598 d: { 1599 'package.json': JSON.stringify({ 1600 name: 'd', 1601 version: '1.0.0', 1602 dependencies: { 1603 foo: '^1.1.1', 1604 }, 1605 }), 1606 }, 1607 group: { 1608 e: { 1609 'package.json': JSON.stringify({ 1610 name: 'e', 1611 version: '1.0.0', 1612 }), 1613 }, 1614 f: { 1615 'package.json': JSON.stringify({ 1616 name: 'f', 1617 version: '1.0.0', 1618 }), 1619 }, 1620 }, 1621 }, 1622 }) 1623 1624 await ls.exec(exec) 1625 1626 t.matchSnapshot(cleanCwd(result(), t), 'output') 1627 } 1628 1629 t.test('should list workspaces properly with default configs', t => mockWorkspaces(t, [], { 1630 depth: 0, 1631 color: 'always', 1632 })) 1633 1634 t.test('should not list workspaces with --no-workspaces', t => mockWorkspaces(t, [], { 1635 depth: 0, 1636 color: 'always', 1637 workspaces: false, 1638 })) 1639 1640 // --all 1641 t.test('should list --all workspaces properly', t => mockWorkspaces(t)) 1642 1643 // --production 1644 t.test('should list only prod deps of workspaces', t => mockWorkspaces(t, [], { 1645 omit: ['dev', 'peer', 'optional'], 1646 })) 1647 1648 // filter out a single workspace using args 1649 t.test('should filter single workspace', t => mockWorkspaces(t, ['d'])) 1650 1651 // filter out a single workspace and its deps using workspaces filters 1652 t.test('should filter using workspace config', t => mockWorkspaces(t, [], { 1653 workspace: 'a', 1654 })) 1655 1656 // filter out a single workspace and include root 1657 t.test('should inlude root and specified workspace', t => mockWorkspaces(t, [], { 1658 'include-workspace-root': true, 1659 workspace: 'd', 1660 })) 1661 1662 // filter out a workspace by parent path 1663 t.test('should filter by parent folder workspace config', t => mockWorkspaces(t, [], { 1664 workspace: './group', 1665 })) 1666 1667 // filter by a dep within a workspaces sub tree 1668 t.test('should print all tree and filter by dep within only the ws subtree', t => 1669 mockWorkspaces(t, ['bar'], { 1670 workspace: 'd', 1671 })) 1672 }) 1673 1674 t.test('filter pkg arg using depth option', async t => { 1675 const mock = async (t, exec, depth = 0) => { 1676 const { result, ls } = await mockLs(t, { 1677 config: typeof depth === 'number' ? { depth } : {}, 1678 prefixDir: { 1679 'package.json': JSON.stringify({ 1680 name: 'test-pkg-arg-filter-with-depth-opt', 1681 version: '1.0.0', 1682 dependencies: { 1683 a: '^1.0.0', 1684 b: '^1.0.0', 1685 }, 1686 }), 1687 node_modules: { 1688 a: { 1689 'package.json': JSON.stringify({ 1690 name: 'a', 1691 version: '1.0.0', 1692 }), 1693 }, 1694 b: { 1695 'package.json': JSON.stringify({ 1696 name: 'b', 1697 version: '1.0.0', 1698 dependencies: { 1699 c: '^1.0.0', 1700 }, 1701 }), 1702 }, 1703 c: { 1704 'package.json': JSON.stringify({ 1705 name: 'c', 1706 version: '1.0.0', 1707 dependencies: { 1708 d: '^1.0.0', 1709 }, 1710 }), 1711 }, 1712 d: { 1713 'package.json': JSON.stringify({ 1714 name: 'd', 1715 version: '1.0.0', 1716 dependencies: { 1717 a: '^1.0.0', 1718 }, 1719 }), 1720 }, 1721 }, 1722 }, 1723 }) 1724 1725 await ls.exec(exec) 1726 1727 t.matchSnapshot(cleanCwd(result(), t), 'output') 1728 } 1729 1730 t.test('should list a in top-level only', t => mock(t, ['a'])) 1731 1732 t.test('should print empty results msg', t => mock(t, ['d'])) 1733 1734 // if no --depth config is defined, should print path to dep 1735 t.test('should print expected result', t => mock(t, ['d'], null)) 1736 }) 1737}) 1738 1739t.test('ls --parseable', async t => { 1740 const parseable = { parseable: true } 1741 t.test('no args', async t => { 1742 const { result, ls } = await mockLs(t, { 1743 config: parseable, 1744 prefixDir: { 1745 'package.json': JSON.stringify({ 1746 name: 'test-npm-ls', 1747 version: '1.0.0', 1748 dependencies: { 1749 foo: '^1.0.0', 1750 chai: '^1.0.0', 1751 }, 1752 }), 1753 ...simpleNmFixture, 1754 }, 1755 }) 1756 await ls.exec([]) 1757 t.matchSnapshot( 1758 cleanCwd(result()), 1759 'should output parseable representation of dependencies structure' 1760 ) 1761 }) 1762 1763 t.test('missing package.json', async t => { 1764 const { result, ls } = await mockLs(t, { 1765 config: parseable, 1766 prefixDir: { 1767 ...simpleNmFixture, 1768 }, 1769 }) 1770 await ls.exec([]) 1771 t.matchSnapshot( 1772 cleanCwd(result()), 1773 'should output parseable missing name/version of top-level package' 1774 ) 1775 }) 1776 1777 t.test('extraneous deps', async t => { 1778 const { result, ls } = await mockLs(t, { 1779 config: parseable, 1780 prefixDir: { 1781 'package.json': JSON.stringify({ 1782 name: 'test-npm-ls', 1783 version: '1.0.0', 1784 dependencies: { 1785 foo: '^1.0.0', 1786 }, 1787 }), 1788 ...simpleNmFixture, 1789 }, 1790 }) 1791 await ls.exec([]) 1792 t.matchSnapshot(cleanCwd(result()), 'should output containing problems info') 1793 }) 1794 1795 t.test('overridden dep', async t => { 1796 const { result, ls } = await mockLs(t, { 1797 config: { ...parseable, long: true }, 1798 prefixDir: { 1799 'package.json': JSON.stringify({ 1800 name: 'test-overridden', 1801 version: '1.0.0', 1802 dependencies: { 1803 foo: '^1.0.0', 1804 }, 1805 overrides: { 1806 bar: '1.0.0', 1807 }, 1808 }), 1809 node_modules: { 1810 foo: { 1811 'package.json': JSON.stringify({ 1812 name: 'foo', 1813 version: '1.0.0', 1814 dependencies: { 1815 bar: '^2.0.0', 1816 }, 1817 }), 1818 }, 1819 bar: { 1820 'package.json': JSON.stringify({ 1821 name: 'bar', 1822 version: '1.0.0', 1823 }), 1824 }, 1825 }, 1826 }, 1827 }) 1828 1829 await ls.exec([]) 1830 t.matchSnapshot(cleanCwd(result()), 'should contain overridden outout') 1831 }) 1832 1833 t.test('with filter arg', async t => { 1834 const { result, ls } = await mockLs(t, { 1835 config: parseable, 1836 prefixDir: { 1837 'package.json': JSON.stringify({ 1838 name: 'test-npm-ls', 1839 version: '1.0.0', 1840 dependencies: { 1841 foo: '^1.0.0', 1842 chai: '^1.0.0', 1843 }, 1844 }), 1845 ...simpleNmFixture, 1846 }, 1847 }) 1848 await ls.exec(['chai']) 1849 t.matchSnapshot( 1850 cleanCwd(result()), 1851 'should output parseable contaning only occurrences of filtered by package' 1852 ) 1853 }) 1854 1855 t.test('with filter arg nested dep', async t => { 1856 const { result, ls } = await mockLs(t, { 1857 config: parseable, 1858 prefixDir: { 1859 'package.json': JSON.stringify({ 1860 name: 'test-npm-ls', 1861 version: '1.0.0', 1862 dependencies: { 1863 foo: '^1.0.0', 1864 chai: '^1.0.0', 1865 }, 1866 }), 1867 ...simpleNmFixture, 1868 }, 1869 }) 1870 await ls.exec(['dog']) 1871 t.matchSnapshot( 1872 cleanCwd(result()), 1873 'should output parseable contaning only occurrences of filtered package' 1874 ) 1875 }) 1876 1877 t.test('with multiple filter args', async t => { 1878 const { result, ls } = await mockLs(t, { 1879 config: parseable, 1880 prefixDir: { 1881 'package.json': JSON.stringify({ 1882 name: 'test-npm-ls', 1883 version: '1.0.0', 1884 dependencies: { 1885 foo: '^1.0.0', 1886 chai: '^1.0.0', 1887 ipsum: '^1.0.0', 1888 }, 1889 }), 1890 node_modules: { 1891 ...simpleNmFixture.node_modules, 1892 ipsum: { 1893 'package.json': JSON.stringify({ 1894 name: 'ipsum', 1895 version: '1.0.0', 1896 }), 1897 }, 1898 }, 1899 }, 1900 }) 1901 await ls.exec(['dog@*', 'chai@1.0.0']) 1902 t.matchSnapshot( 1903 cleanCwd(result()), 1904 /* eslint-disable-next-line max-len */ 1905 'should output parseable contaning only occurrences of multiple filtered packages and their ancestors' 1906 ) 1907 }) 1908 1909 t.test('with missing filter arg', async t => { 1910 const { result, ls } = await mockLs(t, { 1911 config: parseable, 1912 prefixDir: { 1913 'package.json': JSON.stringify({ 1914 name: 'test-npm-ls', 1915 version: '1.0.0', 1916 dependencies: { 1917 foo: '^1.0.0', 1918 chai: '^1.0.0', 1919 }, 1920 }), 1921 ...simpleNmFixture, 1922 }, 1923 }) 1924 await ls.exec(['notadep']) 1925 t.matchSnapshot( 1926 cleanCwd(result()), 1927 'should output parseable output containing no dependencies info' 1928 ) 1929 }) 1930 1931 t.test('default --depth value should be 0', async t => { 1932 const { result, ls } = await mockLs(t, { 1933 config: { ...parseable, all: false }, 1934 prefixDir: { 1935 'package.json': JSON.stringify({ 1936 name: 'test-npm-ls', 1937 version: '1.0.0', 1938 dependencies: { 1939 foo: '^1.0.0', 1940 chai: '^1.0.0', 1941 }, 1942 }), 1943 ...simpleNmFixture, 1944 }, 1945 }) 1946 await ls.exec([]) 1947 t.matchSnapshot( 1948 cleanCwd(result()), 1949 'should output parseable output containing only top-level dependencies' 1950 ) 1951 }) 1952 1953 t.test('--depth=0', async t => { 1954 const { result, ls } = await mockLs(t, { 1955 config: { ...parseable, all: false, depth: 0 }, 1956 prefixDir: { 1957 'package.json': JSON.stringify({ 1958 name: 'test-npm-ls', 1959 version: '1.0.0', 1960 dependencies: { 1961 foo: '^1.0.0', 1962 chai: '^1.0.0', 1963 }, 1964 }), 1965 ...simpleNmFixture, 1966 }, 1967 }) 1968 await ls.exec([]) 1969 t.matchSnapshot(cleanCwd(result()), 1970 'should output tree containing only top-level dependencies') 1971 }) 1972 1973 t.test('--depth=1', async t => { 1974 const { result, ls } = await mockLs(t, { 1975 config: { ...parseable, all: false, depth: 1 }, 1976 prefixDir: { 1977 'package.json': JSON.stringify({ 1978 name: 'test-npm-ls', 1979 version: '1.0.0', 1980 dependencies: { 1981 foo: '^1.0.0', 1982 chai: '^1.0.0', 1983 }, 1984 }), 1985 ...simpleNmFixture, 1986 }, 1987 }) 1988 await ls.exec([]) 1989 t.matchSnapshot( 1990 cleanCwd(result()), 1991 'should output parseable containing top-level deps and their deps only' 1992 ) 1993 }) 1994 1995 t.test('missing/invalid/extraneous', async t => { 1996 const { result, ls } = await mockLs(t, { 1997 config: parseable, 1998 prefixDir: { 1999 'package.json': JSON.stringify({ 2000 name: 'test-npm-ls', 2001 version: '1.0.0', 2002 dependencies: { 2003 foo: '^2.0.0', 2004 ipsum: '^1.0.0', 2005 }, 2006 }), 2007 ...simpleNmFixture, 2008 }, 2009 }) 2010 await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems') 2011 t.matchSnapshot( 2012 cleanCwd(result()), 2013 'should output parseable containing top-level deps and their deps only' 2014 ) 2015 }) 2016 2017 t.test('--dev', async t => { 2018 const { result, ls } = await mockLs(t, { 2019 config: { 2020 ...parseable, 2021 omit: ['peer', 'prod', 'optional'], 2022 }, 2023 prefixDir: { 2024 'package.json': JSON.stringify({ 2025 name: 'test-npm-ls', 2026 version: '1.0.0', 2027 dependencies: { 2028 'prod-dep': '^1.0.0', 2029 chai: '^1.0.0', 2030 }, 2031 devDependencies: { 2032 'dev-dep': '^1.0.0', 2033 }, 2034 optionalDependencies: { 2035 'optional-dep': '^1.0.0', 2036 }, 2037 peerDependencies: { 2038 'peer-dep': '^1.0.0', 2039 }, 2040 }), 2041 ...diffDepTypesNmFixture, 2042 }, 2043 }) 2044 await ls.exec([]) 2045 t.matchSnapshot(cleanCwd(result()), 'should output tree containing dev deps') 2046 }) 2047 2048 t.test('--link', async t => { 2049 const { result, ls } = await mockLs(t, { 2050 config: { 2051 ...parseable, 2052 link: true, 2053 }, 2054 prefixDir: { 2055 'package.json': JSON.stringify({ 2056 name: 'test-npm-ls', 2057 version: '1.0.0', 2058 dependencies: { 2059 'prod-dep': '^1.0.0', 2060 chai: '^1.0.0', 2061 'linked-dep': '^1.0.0', 2062 }, 2063 devDependencies: { 2064 'dev-dep': '^1.0.0', 2065 }, 2066 optionalDependencies: { 2067 'optional-dep': '^1.0.0', 2068 }, 2069 peerDependencies: { 2070 'peer-dep': '^1.0.0', 2071 }, 2072 }), 2073 'linked-dep': { 2074 'package.json': JSON.stringify({ 2075 name: 'linked-dep', 2076 version: '1.0.0', 2077 }), 2078 }, 2079 node_modules: { 2080 'linked-dep': t.fixture('symlink', '../linked-dep'), 2081 ...diffDepTypesNmFixture.node_modules, 2082 }, 2083 }, 2084 }) 2085 await ls.exec([]) 2086 t.matchSnapshot(cleanCwd(result()), 'should output tree containing linked deps') 2087 }) 2088 2089 t.test('--production', async t => { 2090 const { result, ls } = await mockLs(t, { 2091 config: { 2092 ...parseable, 2093 omit: ['dev', 'peer'], 2094 }, 2095 prefixDir: { 2096 'package.json': JSON.stringify({ 2097 name: 'test-npm-ls', 2098 version: '1.0.0', 2099 dependencies: { 2100 'prod-dep': '^1.0.0', 2101 chai: '^1.0.0', 2102 }, 2103 devDependencies: { 2104 'dev-dep': '^1.0.0', 2105 }, 2106 optionalDependencies: { 2107 'optional-dep': '^1.0.0', 2108 }, 2109 peerDependencies: { 2110 'peer-dep': '^1.0.0', 2111 }, 2112 }), 2113 ...diffDepTypesNmFixture, 2114 }, 2115 }) 2116 await ls.exec([]) 2117 t.matchSnapshot(cleanCwd(result()), 'should output tree containing production deps') 2118 }) 2119 2120 t.test('--long', async t => { 2121 const { result, ls } = await mockLs(t, { 2122 config: { 2123 ...parseable, 2124 long: true, 2125 }, 2126 prefixDir: { 2127 'package.json': JSON.stringify({ 2128 name: 'test-npm-ls', 2129 version: '1.0.0', 2130 dependencies: { 2131 'prod-dep': '^1.0.0', 2132 chai: '^1.0.0', 2133 }, 2134 devDependencies: { 2135 'dev-dep': '^1.0.0', 2136 }, 2137 optionalDependencies: { 2138 'optional-dep': '^1.0.0', 2139 }, 2140 peerDependencies: { 2141 'peer-dep': '^1.0.0', 2142 }, 2143 }), 2144 ...diffDepTypesNmFixture, 2145 }, 2146 }) 2147 await ls.exec([]) 2148 t.matchSnapshot(cleanCwd(result()), 'should output tree info with descriptions') 2149 }) 2150 2151 t.test('--long with extraneous deps', async t => { 2152 const { result, ls } = await mockLs(t, { 2153 config: { 2154 ...parseable, 2155 long: true, 2156 }, 2157 prefixDir: { 2158 'package.json': JSON.stringify({ 2159 name: 'test-npm-ls', 2160 version: '1.0.0', 2161 dependencies: { 2162 foo: '^1.0.0', 2163 }, 2164 }), 2165 ...simpleNmFixture, 2166 }, 2167 }) 2168 await ls.exec([]) 2169 t.matchSnapshot(cleanCwd(result()), 'should output long parseable output with extraneous info') 2170 }) 2171 2172 t.test('--long missing/invalid/extraneous', async t => { 2173 const { result, ls } = await mockLs(t, { 2174 config: { 2175 ...parseable, 2176 long: true, 2177 }, 2178 prefixDir: { 2179 'package.json': JSON.stringify({ 2180 name: 'test-npm-ls', 2181 version: '1.0.0', 2182 dependencies: { 2183 foo: '^2.0.0', 2184 ipsum: '^1.0.0', 2185 }, 2186 }), 2187 ...simpleNmFixture, 2188 }, 2189 }) 2190 await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems') 2191 t.matchSnapshot( 2192 cleanCwd(result()), 2193 'should output parseable result containing EXTRANEOUS/INVALID labels' 2194 ) 2195 }) 2196 2197 t.test('--long print symlink target location', async t => { 2198 const { result, ls } = await mockLs(t, { 2199 config: { 2200 ...parseable, 2201 long: true, 2202 }, 2203 prefixDir: { 2204 'package.json': JSON.stringify({ 2205 name: 'test-npm-ls', 2206 version: '1.0.0', 2207 dependencies: { 2208 'prod-dep': '^1.0.0', 2209 chai: '^1.0.0', 2210 'linked-dep': '^1.0.0', 2211 }, 2212 devDependencies: { 2213 'dev-dep': '^1.0.0', 2214 }, 2215 optionalDependencies: { 2216 'optional-dep': '^1.0.0', 2217 }, 2218 peerDependencies: { 2219 'peer-dep': '^1.0.0', 2220 }, 2221 }), 2222 'linked-dep': { 2223 'package.json': JSON.stringify({ 2224 name: 'linked-dep', 2225 version: '1.0.0', 2226 }), 2227 }, 2228 node_modules: { 2229 'linked-dep': t.fixture('symlink', '../linked-dep'), 2230 ...diffDepTypesNmFixture.node_modules, 2231 }, 2232 }, 2233 }) 2234 await ls.exec([]) 2235 t.matchSnapshot(cleanCwd(result()), 'should output parseable results with symlink targets') 2236 }) 2237 2238 t.test('--long --depth=0', async t => { 2239 const { result, ls } = await mockLs(t, { 2240 config: { 2241 ...parseable, 2242 all: false, 2243 depth: 0, 2244 long: true, 2245 }, 2246 prefixDir: { 2247 'package.json': JSON.stringify({ 2248 name: 'test-npm-ls', 2249 version: '1.0.0', 2250 dependencies: { 2251 'prod-dep': '^1.0.0', 2252 chai: '^1.0.0', 2253 }, 2254 devDependencies: { 2255 'dev-dep': '^1.0.0', 2256 }, 2257 optionalDependencies: { 2258 'optional-dep': '^1.0.0', 2259 }, 2260 peerDependencies: { 2261 'peer-dep': '^1.0.0', 2262 }, 2263 }), 2264 ...diffDepTypesNmFixture, 2265 }, 2266 }) 2267 await ls.exec([]) 2268 t.matchSnapshot( 2269 cleanCwd(result()), 2270 'should output tree containing top-level deps with descriptions' 2271 ) 2272 }) 2273 2274 t.test('json read problems', async t => { 2275 const { result, ls } = await mockLs(t, { 2276 config: { 2277 ...parseable, 2278 }, 2279 prefixDir: { 2280 'package.json': '{broken json', 2281 }, 2282 }) 2283 await t.rejects(ls.exec([]), { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error') 2284 t.matchSnapshot(cleanCwd(result()), 'should print empty result') 2285 }) 2286 2287 t.test('empty location', async t => { 2288 const { ls, result } = await mockLs(t, { 2289 config: { 2290 ...parseable, 2291 }, 2292 }) 2293 await ls.exec([]) 2294 t.matchSnapshot(cleanCwd(result()), 'should print empty result') 2295 }) 2296 2297 t.test('unmet peer dep', async t => { 2298 const { result, ls } = await mockLs(t, { 2299 config: { 2300 ...parseable, 2301 }, 2302 prefixDir: { 2303 'package.json': JSON.stringify({ 2304 name: 'test-npm-ls', 2305 version: '1.0.0', 2306 dependencies: { 2307 'prod-dep': '^1.0.0', 2308 chai: '^1.0.0', 2309 }, 2310 devDependencies: { 2311 'dev-dep': '^1.0.0', 2312 }, 2313 optionalDependencies: { 2314 'optional-dep': '^1.0.0', 2315 }, 2316 peerDependencies: { 2317 'peer-dep': '^2.0.0', // mismatching version # 2318 }, 2319 }), 2320 ...diffDepTypesNmFixture, 2321 }, 2322 }) 2323 await t.rejects(ls.exec([])) 2324 t.matchSnapshot( 2325 cleanCwd(result()), 2326 'should output parseable signaling missing peer dep in problems' 2327 ) 2328 }) 2329 2330 t.test('unmet optional dep', async t => { 2331 const { result, ls } = await mockLs(t, { 2332 config: { 2333 ...parseable, 2334 }, 2335 prefixDir: { 2336 'package.json': JSON.stringify({ 2337 name: 'test-npm-ls', 2338 version: '1.0.0', 2339 dependencies: { 2340 'prod-dep': '^1.0.0', 2341 chai: '^1.0.0', 2342 }, 2343 devDependencies: { 2344 'dev-dep': '^1.0.0', 2345 }, 2346 optionalDependencies: { 2347 'missing-optional-dep': '^1.0.0', 2348 'optional-dep': '^2.0.0', // mismatching version # 2349 }, 2350 peerDependencies: { 2351 'peer-dep': '^1.0.0', 2352 }, 2353 }), 2354 ...diffDepTypesNmFixture, 2355 }, 2356 }) 2357 await t.rejects( 2358 ls.exec([]), 2359 { code: 'ELSPROBLEMS', message: /invalid: optional-dep@1.0.0/ }, 2360 'should have invalid dep error msg' 2361 ) 2362 t.matchSnapshot( 2363 cleanCwd(result()), 2364 'should output parseable with empty entry for missing optional deps' 2365 ) 2366 }) 2367 2368 t.test('cycle deps', async t => { 2369 const { result, ls } = await mockLs(t, { 2370 config: { 2371 ...parseable, 2372 }, 2373 prefixDir: { 2374 'package.json': JSON.stringify({ 2375 name: 'test-npm-ls', 2376 version: '1.0.0', 2377 dependencies: { 2378 a: '^1.0.0', 2379 }, 2380 }), 2381 node_modules: { 2382 a: { 2383 'package.json': JSON.stringify({ 2384 name: 'a', 2385 version: '1.0.0', 2386 dependencies: { 2387 b: '^1.0.0', 2388 }, 2389 }), 2390 }, 2391 b: { 2392 'package.json': JSON.stringify({ 2393 name: 'b', 2394 version: '1.0.0', 2395 dependencies: { 2396 a: '^1.0.0', 2397 }, 2398 }), 2399 }, 2400 }, 2401 }, 2402 }) 2403 await ls.exec([]) 2404 t.matchSnapshot(cleanCwd(result()), 'should print tree output omitting deduped ref') 2405 }) 2406 2407 t.test('using aliases', async t => { 2408 const { npm, result, ls } = await mockLs(t, { 2409 config: { 2410 ...parseable, 2411 }, 2412 prefixDir: { 2413 'package.json': JSON.stringify({ 2414 name: 'test-npm-ls', 2415 version: '1.0.0', 2416 dependencies: { 2417 a: 'npm:b@1.0.0', 2418 }, 2419 }), 2420 node_modules: { 2421 '.package-lock.json': JSON.stringify({ 2422 packages: { 2423 'node_modules/a': { 2424 name: 'b', 2425 version: '1.0.0', 2426 resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', 2427 }, 2428 }, 2429 }), 2430 a: { 2431 'package.json': JSON.stringify({ 2432 name: 'b', 2433 version: '1.0.0', 2434 _from: 'a@npm:b', 2435 _resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', 2436 _requested: { 2437 type: 'alias', 2438 }, 2439 }), 2440 }, 2441 }, 2442 }, 2443 }) 2444 touchHiddenPackageLock(npm.prefix) 2445 await ls.exec([]) 2446 t.matchSnapshot(cleanCwd(result()), 'should output tree containing aliases') 2447 }) 2448 2449 t.test('resolved points to git ref', async t => { 2450 const { npm, result, ls } = await mockLs(t, { 2451 config: { 2452 ...parseable, 2453 }, 2454 prefixDir: { 2455 'package.json': JSON.stringify({ 2456 name: 'test-npm-ls', 2457 version: '1.0.0', 2458 dependencies: { 2459 abbrev: 'git+https://github.com/isaacs/abbrev-js.git', 2460 }, 2461 }), 2462 node_modules: { 2463 '.package-lock.json': JSON.stringify({ 2464 packages: { 2465 'node_modules/abbrev': { 2466 name: 'abbrev', 2467 version: '1.1.1', 2468 /* eslint-disable-next-line max-len */ 2469 resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', 2470 }, 2471 }, 2472 }), 2473 abbrev: { 2474 'package.json': JSON.stringify({ 2475 name: 'abbrev', 2476 version: '1.1.1', 2477 _id: 'abbrev@1.1.1', 2478 _from: 'git+https://github.com/isaacs/abbrev-js.git', 2479 /* eslint-disable-next-line max-len */ 2480 _resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', 2481 _requested: { 2482 type: 'git', 2483 raw: 'git+https:github.com/isaacs/abbrev-js.git', 2484 rawSpec: 'git+https:github.com/isaacs/abbrev-js.git', 2485 saveSpec: 'git+https://github.com/isaacs/abbrev-js.git', 2486 fetchSpec: 'https://github.com/isaacs/abbrev-js.git', 2487 gitCommittish: null, 2488 }, 2489 }), 2490 }, 2491 }, 2492 }, 2493 }) 2494 touchHiddenPackageLock(npm.prefix) 2495 await ls.exec([]) 2496 t.matchSnapshot(cleanCwd(result()), 'should output tree containing git refs') 2497 }) 2498 2499 t.test('from and resolved properties', async t => { 2500 const { npm, result, ls } = await mockLs(t, { 2501 config: { 2502 ...parseable, 2503 }, 2504 prefixDir: { 2505 'package.json': JSON.stringify({ 2506 name: 'test-npm-ls', 2507 version: '1.0.0', 2508 dependencies: { 2509 'simple-output': '^2.0.0', 2510 }, 2511 }), 2512 node_modules: { 2513 '.package-lock.json': JSON.stringify({ 2514 packages: { 2515 'node_modules/simple-output': { 2516 name: 'simple-output', 2517 version: '2.1.1', 2518 resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', 2519 shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', 2520 }, 2521 }, 2522 }), 2523 'simple-output': { 2524 'package.json': JSON.stringify({ 2525 name: 'simple-output', 2526 version: '2.1.1', 2527 _from: 'simple-output', 2528 _id: 'simple-output@2.1.1', 2529 _resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', 2530 _requested: { 2531 type: 'tag', 2532 registry: true, 2533 raw: 'simple-output', 2534 name: 'simple-output', 2535 escapedName: 'simple-output', 2536 rawSpec: '', 2537 saveSpec: null, 2538 fetchSpec: 'latest', 2539 }, 2540 _requiredBy: ['#USER', '/'], 2541 _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', 2542 _spec: 'simple-output', 2543 }), 2544 }, 2545 }, 2546 }, 2547 }) 2548 touchHiddenPackageLock(npm.prefix) 2549 await ls.exec([]) 2550 t.matchSnapshot(cleanCwd(result()), 'should not be printed in tree output') 2551 }) 2552 2553 t.test('global', async t => { 2554 const { result, ls } = await mockLs(t, { 2555 config: { ...parseable, global: true }, 2556 globalPrefixDir: { 2557 node_modules: { 2558 a: { 2559 'package.json': JSON.stringify({ 2560 name: 'a', 2561 version: '1.0.0', 2562 }), 2563 }, 2564 b: { 2565 'package.json': JSON.stringify({ 2566 name: 'b', 2567 version: '1.0.0', 2568 }), 2569 node_modules: { 2570 c: { 2571 'package.json': JSON.stringify({ 2572 name: 'c', 2573 version: '1.0.0', 2574 }), 2575 }, 2576 }, 2577 }, 2578 }, 2579 }, 2580 }) 2581 2582 await ls.exec([]) 2583 t.matchSnapshot(cleanCwd(result()), 'should print parseable output for global deps') 2584 }) 2585}) 2586 2587t.test('ignore missing optional deps', async t => { 2588 const mock = async (t, config = {}) => { 2589 const { result, ls } = await mockLs(t, { 2590 config: config, 2591 prefixDir: { 2592 'package.json': JSON.stringify({ 2593 name: 'test-npm-ls-ignore-missing-optional', 2594 version: '1.2.3', 2595 peerDependencies: { 2596 'peer-ok': '1', 2597 'peer-missing': '1', 2598 'peer-wrong': '1', 2599 'peer-optional-ok': '1', 2600 'peer-optional-missing': '1', 2601 'peer-optional-wrong': '1', 2602 }, 2603 peerDependenciesMeta: { 2604 'peer-optional-ok': { 2605 optional: true, 2606 }, 2607 'peer-optional-missing': { 2608 optional: true, 2609 }, 2610 'peer-optional-wrong': { 2611 optional: true, 2612 }, 2613 }, 2614 optionalDependencies: { 2615 'optional-ok': '1', 2616 'optional-missing': '1', 2617 'optional-wrong': '1', 2618 }, 2619 dependencies: { 2620 'prod-ok': '1', 2621 'prod-missing': '1', 2622 'prod-wrong': '1', 2623 }, 2624 }), 2625 node_modules: { 2626 'prod-ok': { 2627 'package.json': JSON.stringify({ name: 'prod-ok', version: '1.2.3' }), 2628 }, 2629 'prod-wrong': { 2630 'package.json': JSON.stringify({ name: 'prod-wrong', version: '3.2.1' }), 2631 }, 2632 'optional-ok': { 2633 'package.json': JSON.stringify({ name: 'optional-ok', version: '1.2.3' }), 2634 }, 2635 'optional-wrong': { 2636 'package.json': JSON.stringify({ name: 'optional-wrong', version: '3.2.1' }), 2637 }, 2638 'peer-optional-ok': { 2639 'package.json': JSON.stringify({ name: 'peer-optional-ok', version: '1.2.3' }), 2640 }, 2641 'peer-optional-wrong': { 2642 'package.json': JSON.stringify({ name: 'peer-optional-wrong', version: '3.2.1' }), 2643 }, 2644 'peer-ok': { 2645 'package.json': JSON.stringify({ name: 'peer-ok', version: '1.2.3' }), 2646 }, 2647 'peer-wrong': { 2648 'package.json': JSON.stringify({ name: 'peer-wrong', version: '3.2.1' }), 2649 }, 2650 }, 2651 }, 2652 }) 2653 2654 await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }) 2655 2656 return config.json ? jsonParse(result()).problems : cleanCwd(result()) 2657 } 2658 2659 t.test('--json', async t => { 2660 const result = await mock(t, { json: true }) 2661 t.matchSnapshot(result, 'ls --json problems') 2662 }) 2663 2664 t.test('--parseable', async t => { 2665 const result = await mock(t, { parseable: true }) 2666 t.matchSnapshot(result, 'ls --parseable result') 2667 }) 2668 2669 t.test('human output', async t => { 2670 const result = await mock(t) 2671 t.matchSnapshot(result, 'ls result') 2672 }) 2673}) 2674 2675t.test('ls --json', async t => { 2676 const json = { json: true } 2677 t.test('no args', async t => { 2678 const { result, ls } = await mockLs(t, { 2679 config: { 2680 ...json, 2681 }, 2682 prefixDir: { 2683 'package.json': JSON.stringify({ 2684 name: 'test-npm-ls', 2685 version: '1.0.0', 2686 dependencies: { 2687 foo: '^1.0.0', 2688 chai: '^1.0.0', 2689 }, 2690 }), 2691 ...simpleNmFixture, 2692 }, 2693 }) 2694 await ls.exec([]) 2695 t.same( 2696 jsonParse(result()), 2697 { 2698 name: 'test-npm-ls', 2699 version: '1.0.0', 2700 dependencies: { 2701 foo: { 2702 version: '1.0.0', 2703 overridden: false, 2704 dependencies: { 2705 dog: { 2706 version: '1.0.0', 2707 overridden: false, 2708 }, 2709 }, 2710 }, 2711 chai: { 2712 version: '1.0.0', 2713 overridden: false, 2714 }, 2715 }, 2716 }, 2717 'should output json representation of dependencies structure' 2718 ) 2719 }) 2720 2721 t.test('missing package.json', async t => { 2722 const { result, ls } = await mockLs(t, { 2723 config: { 2724 ...json, 2725 }, 2726 prefixDir: { 2727 ...simpleNmFixture, 2728 }, 2729 }) 2730 await ls.exec([]) 2731 t.same( 2732 jsonParse(result()), 2733 { 2734 problems: [ 2735 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', 2736 'extraneous: dog@1.0.0 {CWD}/prefix/node_modules/dog', 2737 'extraneous: foo@1.0.0 {CWD}/prefix/node_modules/foo', 2738 ], 2739 dependencies: { 2740 dog: { 2741 version: '1.0.0', 2742 extraneous: true, 2743 overridden: false, 2744 problems: [ 2745 'extraneous: dog@1.0.0 {CWD}/prefix/node_modules/dog', 2746 ], 2747 }, 2748 foo: { 2749 version: '1.0.0', 2750 extraneous: true, 2751 overridden: false, 2752 problems: [ 2753 'extraneous: foo@1.0.0 {CWD}/prefix/node_modules/foo', 2754 ], 2755 dependencies: { 2756 dog: { 2757 version: '1.0.0', 2758 }, 2759 }, 2760 }, 2761 chai: { 2762 version: '1.0.0', 2763 extraneous: true, 2764 overridden: false, 2765 problems: [ 2766 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', 2767 ], 2768 }, 2769 }, 2770 }, 2771 'should output json missing name/version of top-level package' 2772 ) 2773 }) 2774 2775 t.test('extraneous deps', async t => { 2776 const { result, ls } = await mockLs(t, { 2777 config: { 2778 ...json, 2779 }, 2780 prefixDir: { 2781 'package.json': JSON.stringify({ 2782 name: 'test-npm-ls', 2783 version: '1.0.0', 2784 dependencies: { 2785 foo: '^1.0.0', 2786 }, 2787 }), 2788 ...simpleNmFixture, 2789 }, 2790 }) 2791 await ls.exec([]) 2792 t.same( 2793 jsonParse(result()), 2794 { 2795 name: 'test-npm-ls', 2796 version: '1.0.0', 2797 problems: [ 2798 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', 2799 ], 2800 dependencies: { 2801 foo: { 2802 version: '1.0.0', 2803 overridden: false, 2804 dependencies: { 2805 dog: { 2806 version: '1.0.0', 2807 overridden: false, 2808 }, 2809 }, 2810 }, 2811 chai: { 2812 version: '1.0.0', 2813 extraneous: true, 2814 overridden: false, 2815 problems: [ 2816 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', 2817 ], 2818 }, 2819 }, 2820 }, 2821 'should output json containing problems info' 2822 ) 2823 }) 2824 2825 t.test('overridden dep', async t => { 2826 const { result, ls } = await mockLs(t, { 2827 config: { 2828 ...json, 2829 }, 2830 prefixDir: { 2831 'package.json': JSON.stringify({ 2832 name: 'test-overridden', 2833 version: '1.0.0', 2834 dependencies: { 2835 foo: '^1.0.0', 2836 }, 2837 overrides: { 2838 bar: '1.0.0', 2839 }, 2840 }), 2841 node_modules: { 2842 foo: { 2843 'package.json': JSON.stringify({ 2844 name: 'foo', 2845 version: '1.0.0', 2846 dependencies: { 2847 bar: '^2.0.0', 2848 }, 2849 }), 2850 }, 2851 bar: { 2852 'package.json': JSON.stringify({ 2853 name: 'bar', 2854 version: '1.0.0', 2855 }), 2856 }, 2857 }, 2858 }, 2859 }) 2860 2861 await ls.exec([]) 2862 t.same(JSON.parse(result()), { 2863 name: 'test-overridden', 2864 version: '1.0.0', 2865 dependencies: { 2866 foo: { 2867 version: '1.0.0', 2868 overridden: false, 2869 dependencies: { 2870 bar: { 2871 version: '1.0.0', 2872 overridden: true, 2873 }, 2874 }, 2875 }, 2876 }, 2877 }) 2878 }) 2879 2880 t.test('missing deps --long', async t => { 2881 t.plan(3) 2882 const { result, ls } = await mockLs(t, { 2883 config: { 2884 ...json, 2885 long: true, 2886 }, 2887 prefixDir: { 2888 'package.json': JSON.stringify({ 2889 name: 'test-npm-ls', 2890 version: '1.0.0', 2891 dependencies: { 2892 foo: '^1.0.0', 2893 dog: '^1.0.0', 2894 chai: '^1.0.0', 2895 ipsum: '^1.0.0', 2896 }, 2897 }), 2898 ...simpleNmFixture, 2899 }, 2900 }) 2901 2902 await ls.exec([]).catch(err => { 2903 t.equal( 2904 cleanCwd(err.message), 2905 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', 2906 'should log missing dep as error' 2907 ) 2908 t.equal(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') 2909 }) 2910 t.match( 2911 jsonParse(result()), 2912 { 2913 name: 'test-npm-ls', 2914 version: '1.0.0', 2915 problems: ['missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0'], 2916 }, 2917 'should output json containing problems info' 2918 ) 2919 }) 2920 2921 t.test('with filter arg', async t => { 2922 const { result, ls } = await mockLs(t, { 2923 config: { 2924 ...json, 2925 }, 2926 prefixDir: { 2927 'package.json': JSON.stringify({ 2928 name: 'test-npm-ls', 2929 version: '1.0.0', 2930 dependencies: { 2931 foo: '^1.0.0', 2932 chai: '^1.0.0', 2933 }, 2934 }), 2935 ...simpleNmFixture, 2936 }, 2937 }) 2938 await ls.exec(['chai']) 2939 t.same( 2940 jsonParse(result()), 2941 { 2942 name: 'test-npm-ls', 2943 version: '1.0.0', 2944 dependencies: { 2945 chai: { 2946 version: '1.0.0', 2947 overridden: false, 2948 }, 2949 }, 2950 }, 2951 'should output json contaning only occurrences of filtered by package' 2952 ) 2953 t.not(process.exitCode, 1, 'should not exit with error code 1') 2954 }) 2955 2956 t.test('with filter arg nested dep', async t => { 2957 const { result, ls } = await mockLs(t, { 2958 config: { 2959 ...json, 2960 }, 2961 prefixDir: { 2962 'package.json': JSON.stringify({ 2963 name: 'test-npm-ls', 2964 version: '1.0.0', 2965 dependencies: { 2966 foo: '^1.0.0', 2967 chai: '^1.0.0', 2968 }, 2969 }), 2970 ...simpleNmFixture, 2971 }, 2972 }) 2973 await ls.exec(['dog']) 2974 t.same( 2975 jsonParse(result()), 2976 { 2977 name: 'test-npm-ls', 2978 version: '1.0.0', 2979 dependencies: { 2980 foo: { 2981 version: '1.0.0', 2982 overridden: false, 2983 dependencies: { 2984 dog: { 2985 version: '1.0.0', 2986 overridden: false, 2987 }, 2988 }, 2989 }, 2990 }, 2991 }, 2992 'should output json contaning only occurrences of filtered by package' 2993 ) 2994 t.notOk(jsonParse(result()).dependencies.chai) 2995 }) 2996 2997 t.test('with multiple filter args', async t => { 2998 const { result, ls } = await mockLs(t, { 2999 config: { 3000 ...json, 3001 }, 3002 prefixDir: { 3003 'package.json': JSON.stringify({ 3004 name: 'test-npm-ls', 3005 version: '1.0.0', 3006 dependencies: { 3007 foo: '^1.0.0', 3008 chai: '^1.0.0', 3009 ipsum: '^1.0.0', 3010 }, 3011 }), 3012 node_modules: { 3013 ...simpleNmFixture.node_modules, 3014 ipsum: { 3015 'package.json': JSON.stringify({ 3016 name: 'ipsum', 3017 version: '1.0.0', 3018 }), 3019 }, 3020 }, 3021 }, 3022 }) 3023 await ls.exec(['dog@*', 'chai@1.0.0']) 3024 t.same( 3025 jsonParse(result()), 3026 { 3027 version: '1.0.0', 3028 name: 'test-npm-ls', 3029 dependencies: { 3030 foo: { 3031 version: '1.0.0', 3032 overridden: false, 3033 dependencies: { 3034 dog: { 3035 version: '1.0.0', 3036 overridden: false, 3037 }, 3038 }, 3039 }, 3040 chai: { 3041 version: '1.0.0', 3042 overridden: false, 3043 }, 3044 }, 3045 }, 3046 /* eslint-disable-next-line max-len */ 3047 'should output json contaning only occurrences of multiple filtered packages and their ancestors' 3048 ) 3049 }) 3050 3051 t.test('with missing filter arg', async t => { 3052 const { result, ls } = await mockLs(t, { 3053 config: { 3054 ...json, 3055 }, 3056 prefixDir: { 3057 'package.json': JSON.stringify({ 3058 name: 'test-npm-ls', 3059 version: '1.0.0', 3060 dependencies: { 3061 foo: '^1.0.0', 3062 chai: '^1.0.0', 3063 }, 3064 }), 3065 ...simpleNmFixture, 3066 }, 3067 }) 3068 await ls.exec(['notadep']) 3069 t.same( 3070 jsonParse(result()), 3071 { 3072 name: 'test-npm-ls', 3073 version: '1.0.0', 3074 }, 3075 'should output json containing no dependencies info' 3076 ) 3077 t.equal(process.exitCode, 1, 'should exit with error code 1') 3078 }) 3079 3080 t.test('default --depth value should now be 0', async t => { 3081 const { result, ls } = await mockLs(t, { 3082 config: { 3083 ...json, 3084 all: false, 3085 }, 3086 prefixDir: { 3087 'package.json': JSON.stringify({ 3088 name: 'test-npm-ls', 3089 version: '1.0.0', 3090 dependencies: { 3091 foo: '^1.0.0', 3092 chai: '^1.0.0', 3093 }, 3094 }), 3095 ...simpleNmFixture, 3096 }, 3097 }) 3098 await ls.exec([]) 3099 t.same( 3100 jsonParse(result()), 3101 { 3102 name: 'test-npm-ls', 3103 version: '1.0.0', 3104 dependencies: { 3105 foo: { 3106 version: '1.0.0', 3107 overridden: false, 3108 }, 3109 chai: { 3110 version: '1.0.0', 3111 overridden: false, 3112 }, 3113 }, 3114 }, 3115 'should output json containing only top-level dependencies' 3116 ) 3117 }) 3118 3119 t.test('--depth=0', async t => { 3120 const { result, ls } = await mockLs(t, { 3121 config: { 3122 ...json, 3123 all: false, 3124 depth: 0, 3125 }, 3126 prefixDir: { 3127 'package.json': JSON.stringify({ 3128 name: 'test-npm-ls', 3129 version: '1.0.0', 3130 dependencies: { 3131 foo: '^1.0.0', 3132 chai: '^1.0.0', 3133 }, 3134 }), 3135 ...simpleNmFixture, 3136 }, 3137 }) 3138 await ls.exec([]) 3139 t.same( 3140 jsonParse(result()), 3141 { 3142 name: 'test-npm-ls', 3143 version: '1.0.0', 3144 dependencies: { 3145 foo: { 3146 version: '1.0.0', 3147 overridden: false, 3148 }, 3149 chai: { 3150 version: '1.0.0', 3151 overridden: false, 3152 }, 3153 }, 3154 }, 3155 'should output json containing only top-level dependencies' 3156 ) 3157 }) 3158 3159 t.test('--depth=1', async t => { 3160 const { result, ls } = await mockLs(t, { 3161 config: { 3162 ...json, 3163 all: false, 3164 depth: 1, 3165 }, 3166 prefixDir: { 3167 'package.json': JSON.stringify({ 3168 name: 'test-npm-ls', 3169 version: '1.0.0', 3170 dependencies: { 3171 foo: '^1.0.0', 3172 chai: '^1.0.0', 3173 }, 3174 }), 3175 ...simpleNmFixture, 3176 }, 3177 }) 3178 await ls.exec([]) 3179 t.same( 3180 jsonParse(result()), 3181 { 3182 name: 'test-npm-ls', 3183 version: '1.0.0', 3184 dependencies: { 3185 foo: { 3186 version: '1.0.0', 3187 overridden: false, 3188 dependencies: { 3189 dog: { 3190 version: '1.0.0', 3191 overridden: false, 3192 }, 3193 }, 3194 }, 3195 chai: { 3196 version: '1.0.0', 3197 overridden: false, 3198 }, 3199 }, 3200 }, 3201 'should output json containing top-level deps and their deps only' 3202 ) 3203 }) 3204 3205 t.test('missing/invalid/extraneous', async t => { 3206 const { result, ls } = await mockLs(t, { 3207 config: { 3208 ...json, 3209 }, 3210 prefixDir: { 3211 'package.json': JSON.stringify({ 3212 name: 'test-npm-ls', 3213 version: '1.0.0', 3214 dependencies: { 3215 foo: '^2.0.0', 3216 ipsum: '^1.0.0', 3217 }, 3218 }), 3219 ...simpleNmFixture, 3220 }, 3221 }) 3222 await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems') 3223 t.same( 3224 jsonParse(result()), 3225 { 3226 name: 'test-npm-ls', 3227 version: '1.0.0', 3228 problems: [ 3229 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', 3230 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo', 3231 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', 3232 ], 3233 dependencies: { 3234 foo: { 3235 version: '1.0.0', 3236 invalid: '"^2.0.0" from the root project', 3237 overridden: false, 3238 problems: [ 3239 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo', 3240 ], 3241 dependencies: { 3242 dog: { 3243 version: '1.0.0', 3244 overridden: false, 3245 }, 3246 }, 3247 }, 3248 chai: { 3249 version: '1.0.0', 3250 extraneous: true, 3251 overridden: false, 3252 problems: [ 3253 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', 3254 ], 3255 }, 3256 ipsum: { 3257 required: '^1.0.0', 3258 missing: true, 3259 problems: ['missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0'], 3260 }, 3261 }, 3262 error: { 3263 code: 'ELSPROBLEMS', 3264 summary: [ 3265 'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai', 3266 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo', 3267 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', 3268 ].join('\n'), 3269 detail: '', 3270 }, 3271 }, 3272 'should output json containing top-level deps and their deps only' 3273 ) 3274 }) 3275 3276 t.test('--dev', async t => { 3277 const { result, ls } = await mockLs(t, { 3278 config: { 3279 ...json, 3280 omit: ['prod', 'optional', 'peer'], 3281 }, 3282 prefixDir: { 3283 'package.json': JSON.stringify({ 3284 name: 'test-npm-ls', 3285 version: '1.0.0', 3286 dependencies: { 3287 'prod-dep': '^1.0.0', 3288 chai: '^1.0.0', 3289 }, 3290 devDependencies: { 3291 'dev-dep': '^1.0.0', 3292 }, 3293 optionalDependencies: { 3294 'optional-dep': '^1.0.0', 3295 }, 3296 peerDependencies: { 3297 'peer-dep': '^1.0.0', 3298 }, 3299 }), 3300 ...diffDepTypesNmFixture, 3301 }, 3302 }) 3303 await ls.exec([]) 3304 t.same( 3305 jsonParse(result()), 3306 { 3307 name: 'test-npm-ls', 3308 version: '1.0.0', 3309 dependencies: { 3310 'dev-dep': { 3311 version: '1.0.0', 3312 overridden: false, 3313 dependencies: { 3314 foo: { 3315 version: '1.0.0', 3316 overridden: false, 3317 dependencies: { 3318 dog: { 3319 version: '1.0.0', 3320 overridden: false, 3321 }, 3322 }, 3323 }, 3324 }, 3325 }, 3326 }, 3327 }, 3328 'should output json containing dev deps' 3329 ) 3330 }) 3331 3332 t.test('--link', async t => { 3333 const { result, ls } = await mockLs(t, { 3334 config: { 3335 ...json, 3336 link: true, 3337 }, 3338 prefixDir: { 3339 'package.json': JSON.stringify({ 3340 name: 'test-npm-ls', 3341 version: '1.0.0', 3342 dependencies: { 3343 'prod-dep': '^1.0.0', 3344 chai: '^1.0.0', 3345 'linked-dep': '^1.0.0', 3346 }, 3347 devDependencies: { 3348 'dev-dep': '^1.0.0', 3349 }, 3350 optionalDependencies: { 3351 'optional-dep': '^1.0.0', 3352 }, 3353 peerDependencies: { 3354 'peer-dep': '^1.0.0', 3355 }, 3356 }), 3357 'linked-dep': { 3358 'package.json': JSON.stringify({ 3359 name: 'linked-dep', 3360 version: '1.0.0', 3361 }), 3362 }, 3363 node_modules: { 3364 'linked-dep': t.fixture('symlink', '../linked-dep'), 3365 ...diffDepTypesNmFixture.node_modules, 3366 }, 3367 }, 3368 }) 3369 await ls.exec([]) 3370 t.same( 3371 jsonParse(result()), 3372 { 3373 name: 'test-npm-ls', 3374 version: '1.0.0', 3375 dependencies: { 3376 'linked-dep': { 3377 version: '1.0.0', 3378 resolved: 'file:../linked-dep', 3379 overridden: false, 3380 }, 3381 }, 3382 }, 3383 'should output json containing linked deps' 3384 ) 3385 }) 3386 3387 t.test('--production', async t => { 3388 const { result, ls } = await mockLs(t, { 3389 config: { 3390 ...json, 3391 omit: ['dev', 'peer'], 3392 }, 3393 prefixDir: { 3394 'package.json': JSON.stringify({ 3395 name: 'test-npm-ls', 3396 version: '1.0.0', 3397 dependencies: { 3398 'prod-dep': '^1.0.0', 3399 chai: '^1.0.0', 3400 }, 3401 devDependencies: { 3402 'dev-dep': '^1.0.0', 3403 }, 3404 optionalDependencies: { 3405 'optional-dep': '^1.0.0', 3406 }, 3407 peerDependencies: { 3408 'peer-dep': '^1.0.0', 3409 }, 3410 }), 3411 ...diffDepTypesNmFixture, 3412 }, 3413 }) 3414 await ls.exec([]) 3415 t.same( 3416 jsonParse(result()), 3417 { 3418 name: 'test-npm-ls', 3419 version: '1.0.0', 3420 dependencies: { 3421 chai: { 3422 version: '1.0.0', 3423 overridden: false, 3424 }, 3425 'optional-dep': { 3426 version: '1.0.0', 3427 overridden: false, 3428 }, 3429 'prod-dep': { 3430 version: '1.0.0', 3431 overridden: false, 3432 dependencies: { 3433 dog: { 3434 version: '2.0.0', 3435 overridden: false, 3436 }, 3437 }, 3438 }, 3439 }, 3440 }, 3441 'should output json containing production deps' 3442 ) 3443 }) 3444 3445 t.test('from lockfile', async t => { 3446 const { result, ls } = await mockLs(t, { 3447 config: { 3448 ...json, 3449 }, 3450 prefixDir: { 3451 node_modules: { 3452 '@isaacs': { 3453 'dedupe-tests-a': { 3454 'package.json': JSON.stringify({ 3455 name: '@isaacs/dedupe-tests-a', 3456 version: '1.0.1', 3457 }), 3458 node_modules: { 3459 '@isaacs': { 3460 'dedupe-tests-b': { 3461 name: '@isaacs/dedupe-tests-b', 3462 version: '1.0.0', 3463 }, 3464 }, 3465 }, 3466 }, 3467 'dedupe-tests-b': { 3468 'package.json': JSON.stringify({ 3469 name: '@isaacs/dedupe-tests-b', 3470 version: '2.0.0', 3471 }), 3472 }, 3473 }, 3474 }, 3475 'package-lock.json': JSON.stringify({ 3476 name: 'dedupe-lockfile', 3477 version: '1.0.0', 3478 lockfileVersion: 2, 3479 requires: true, 3480 packages: { 3481 '': { 3482 name: 'dedupe-lockfile', 3483 version: '1.0.0', 3484 dependencies: { 3485 '@isaacs/dedupe-tests-a': '1.0.1', 3486 '@isaacs/dedupe-tests-b': '1||2', 3487 }, 3488 }, 3489 'node_modules/@isaacs/dedupe-tests-a': { 3490 name: '@isaacs/dedupe-tests-a', 3491 version: '1.0.1', 3492 /* eslint-disable-next-line max-len */ 3493 resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', 3494 /* eslint-disable-next-line max-len */ 3495 integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==', 3496 dependencies: { 3497 '@isaacs/dedupe-tests-b': '1', 3498 }, 3499 }, 3500 'node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b': { 3501 name: '@isaacs/dedupe-tests-b', 3502 version: '1.0.0', 3503 /* eslint-disable-next-line max-len */ 3504 resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', 3505 /* eslint-disable-next-line max-len */ 3506 integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==', 3507 }, 3508 'node_modules/@isaacs/dedupe-tests-b': { 3509 name: '@isaacs/dedupe-tests-b', 3510 version: '2.0.0', 3511 /* eslint-disable-next-line max-len */ 3512 resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', 3513 /* eslint-disable-next-line max-len */ 3514 integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==', 3515 }, 3516 }, 3517 dependencies: { 3518 '@isaacs/dedupe-tests-a': { 3519 version: '1.0.1', 3520 /* eslint-disable-next-line max-len */ 3521 resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', 3522 /* eslint-disable-next-line max-len */ 3523 integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==', 3524 requires: { 3525 '@isaacs/dedupe-tests-b': '1', 3526 }, 3527 dependencies: { 3528 '@isaacs/dedupe-tests-b': { 3529 version: '1.0.0', 3530 /* eslint-disable-next-line max-len */ 3531 resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', 3532 /* eslint-disable-next-line max-len */ 3533 integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==', 3534 }, 3535 }, 3536 }, 3537 '@isaacs/dedupe-tests-b': { 3538 version: '2.0.0', 3539 /* eslint-disable-next-line max-len */ 3540 resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', 3541 /* eslint-disable-next-line max-len */ 3542 integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==', 3543 }, 3544 }, 3545 }), 3546 'package.json': JSON.stringify({ 3547 name: 'dedupe-lockfile', 3548 version: '1.0.0', 3549 dependencies: { 3550 '@isaacs/dedupe-tests-a': '1.0.1', 3551 '@isaacs/dedupe-tests-b': '1||2', 3552 }, 3553 }), 3554 }, 3555 }) 3556 await ls.exec([]) 3557 t.same( 3558 jsonParse(result()), 3559 { 3560 version: '1.0.0', 3561 name: 'dedupe-lockfile', 3562 dependencies: { 3563 '@isaacs/dedupe-tests-a': { 3564 version: '1.0.1', 3565 overridden: false, 3566 resolved: 3567 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', 3568 dependencies: { 3569 '@isaacs/dedupe-tests-b': { 3570 resolved: 3571 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', 3572 extraneous: true, 3573 overridden: false, 3574 problems: [ 3575 /* eslint-disable-next-line max-len */ 3576 'extraneous: @isaacs/dedupe-tests-b@ {CWD}/prefix/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b', 3577 ], 3578 }, 3579 }, 3580 }, 3581 '@isaacs/dedupe-tests-b': { 3582 version: '2.0.0', 3583 overridden: false, 3584 resolved: 3585 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', 3586 }, 3587 }, 3588 problems: [ 3589 /* eslint-disable-next-line max-len */ 3590 'extraneous: @isaacs/dedupe-tests-b@ {CWD}/prefix/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b', 3591 ], 3592 }, 3593 'should output json containing only prod deps' 3594 ) 3595 }) 3596 3597 t.test('--long', async t => { 3598 const { result, ls } = await mockLs(t, { 3599 config: { 3600 ...json, 3601 long: true, 3602 }, 3603 prefixDir: { 3604 'package.json': JSON.stringify({ 3605 name: 'test-npm-ls', 3606 version: '1.0.0', 3607 dependencies: { 3608 'prod-dep': '^1.0.0', 3609 chai: '^1.0.0', 3610 }, 3611 devDependencies: { 3612 'dev-dep': '^1.0.0', 3613 }, 3614 optionalDependencies: { 3615 'optional-dep': '^1.0.0', 3616 }, 3617 peerDependencies: { 3618 'peer-dep': '^1.0.0', 3619 }, 3620 }), 3621 ...diffDepTypesNmFixture, 3622 }, 3623 }) 3624 await ls.exec([]) 3625 t.same( 3626 jsonParse(result()), 3627 { 3628 name: 'test-npm-ls', 3629 version: '1.0.0', 3630 dependencies: { 3631 'peer-dep': { 3632 name: 'peer-dep', 3633 overridden: false, 3634 description: 'Peer-dep description here', 3635 version: '1.0.0', 3636 _id: 'peer-dep@1.0.0', 3637 devDependencies: {}, 3638 peerDependencies: {}, 3639 _dependencies: {}, 3640 path: '{CWD}/prefix/node_modules/peer-dep', 3641 extraneous: false, 3642 }, 3643 'dev-dep': { 3644 name: 'dev-dep', 3645 overridden: false, 3646 description: 'A DEV dep kind of dep', 3647 version: '1.0.0', 3648 dependencies: { 3649 foo: { 3650 name: 'foo', 3651 version: '1.0.0', 3652 overridden: false, 3653 dependencies: { 3654 dog: { 3655 name: 'dog', 3656 overridden: false, 3657 version: '1.0.0', 3658 _id: 'dog@1.0.0', 3659 devDependencies: {}, 3660 peerDependencies: {}, 3661 _dependencies: {}, 3662 path: '{CWD}/prefix/node_modules/dog', 3663 extraneous: false, 3664 }, 3665 }, 3666 _id: 'foo@1.0.0', 3667 devDependencies: {}, 3668 peerDependencies: {}, 3669 _dependencies: { dog: '^1.0.0' }, 3670 path: '{CWD}/prefix/node_modules/foo', 3671 extraneous: false, 3672 }, 3673 }, 3674 _id: 'dev-dep@1.0.0', 3675 devDependencies: {}, 3676 peerDependencies: {}, 3677 _dependencies: { foo: '^1.0.0' }, 3678 path: '{CWD}/prefix/node_modules/dev-dep', 3679 extraneous: false, 3680 }, 3681 chai: { 3682 name: 'chai', 3683 overridden: false, 3684 version: '1.0.0', 3685 _id: 'chai@1.0.0', 3686 devDependencies: {}, 3687 peerDependencies: {}, 3688 _dependencies: {}, 3689 path: '{CWD}/prefix/node_modules/chai', 3690 extraneous: false, 3691 }, 3692 'optional-dep': { 3693 name: 'optional-dep', 3694 overridden: false, 3695 description: 'Maybe a dep?', 3696 version: '1.0.0', 3697 _id: 'optional-dep@1.0.0', 3698 devDependencies: {}, 3699 peerDependencies: {}, 3700 _dependencies: {}, 3701 path: '{CWD}/prefix/node_modules/optional-dep', 3702 extraneous: false, 3703 }, 3704 'prod-dep': { 3705 name: 'prod-dep', 3706 overridden: false, 3707 description: 'A PROD dep kind of dep', 3708 version: '1.0.0', 3709 dependencies: { 3710 dog: { 3711 name: 'dog', 3712 overridden: false, 3713 description: 'A dep that bars', 3714 version: '2.0.0', 3715 _id: 'dog@2.0.0', 3716 devDependencies: {}, 3717 peerDependencies: {}, 3718 _dependencies: {}, 3719 path: '{CWD}/prefix/node_modules/prod-dep/node_modules/dog', 3720 extraneous: false, 3721 }, 3722 }, 3723 _id: 'prod-dep@1.0.0', 3724 devDependencies: {}, 3725 peerDependencies: {}, 3726 _dependencies: { dog: '^2.0.0' }, 3727 path: '{CWD}/prefix/node_modules/prod-dep', 3728 extraneous: false, 3729 }, 3730 }, 3731 devDependencies: { 'dev-dep': '^1.0.0' }, 3732 optionalDependencies: { 'optional-dep': '^1.0.0' }, 3733 peerDependencies: { 'peer-dep': '^1.0.0' }, 3734 _id: 'test-npm-ls@1.0.0', 3735 _dependencies: { 'prod-dep': '^1.0.0', chai: '^1.0.0', 'optional-dep': '^1.0.0' }, 3736 path: '{CWD}/prefix', 3737 extraneous: false, 3738 }, 3739 'should output long json info' 3740 ) 3741 }) 3742 3743 t.test('--long --depth=0', async t => { 3744 const { result, ls } = await mockLs(t, { 3745 config: { 3746 ...json, 3747 all: false, 3748 depth: 0, 3749 long: true, 3750 }, 3751 prefixDir: { 3752 'package.json': JSON.stringify({ 3753 name: 'test-npm-ls', 3754 version: '1.0.0', 3755 dependencies: { 3756 'prod-dep': '^1.0.0', 3757 chai: '^1.0.0', 3758 }, 3759 devDependencies: { 3760 'dev-dep': '^1.0.0', 3761 }, 3762 optionalDependencies: { 3763 'optional-dep': '^1.0.0', 3764 }, 3765 peerDependencies: { 3766 'peer-dep': '^1.0.0', 3767 }, 3768 }), 3769 ...diffDepTypesNmFixture, 3770 }, 3771 }) 3772 await ls.exec([]) 3773 t.same( 3774 jsonParse(result()), 3775 { 3776 name: 'test-npm-ls', 3777 version: '1.0.0', 3778 dependencies: { 3779 'peer-dep': { 3780 name: 'peer-dep', 3781 overridden: false, 3782 description: 'Peer-dep description here', 3783 version: '1.0.0', 3784 _id: 'peer-dep@1.0.0', 3785 devDependencies: {}, 3786 peerDependencies: {}, 3787 _dependencies: {}, 3788 path: '{CWD}/prefix/node_modules/peer-dep', 3789 extraneous: false, 3790 }, 3791 'dev-dep': { 3792 name: 'dev-dep', 3793 overridden: false, 3794 description: 'A DEV dep kind of dep', 3795 version: '1.0.0', 3796 _id: 'dev-dep@1.0.0', 3797 devDependencies: {}, 3798 peerDependencies: {}, 3799 _dependencies: { foo: '^1.0.0' }, 3800 path: '{CWD}/prefix/node_modules/dev-dep', 3801 extraneous: false, 3802 }, 3803 chai: { 3804 name: 'chai', 3805 overridden: false, 3806 version: '1.0.0', 3807 _id: 'chai@1.0.0', 3808 devDependencies: {}, 3809 peerDependencies: {}, 3810 _dependencies: {}, 3811 path: '{CWD}/prefix/node_modules/chai', 3812 extraneous: false, 3813 }, 3814 'optional-dep': { 3815 name: 'optional-dep', 3816 overridden: false, 3817 description: 'Maybe a dep?', 3818 version: '1.0.0', 3819 _id: 'optional-dep@1.0.0', 3820 devDependencies: {}, 3821 peerDependencies: {}, 3822 _dependencies: {}, 3823 path: '{CWD}/prefix/node_modules/optional-dep', 3824 extraneous: false, 3825 }, 3826 'prod-dep': { 3827 name: 'prod-dep', 3828 overridden: false, 3829 description: 'A PROD dep kind of dep', 3830 version: '1.0.0', 3831 _id: 'prod-dep@1.0.0', 3832 devDependencies: {}, 3833 peerDependencies: {}, 3834 _dependencies: { dog: '^2.0.0' }, 3835 path: '{CWD}/prefix/node_modules/prod-dep', 3836 extraneous: false, 3837 }, 3838 }, 3839 devDependencies: { 'dev-dep': '^1.0.0' }, 3840 optionalDependencies: { 'optional-dep': '^1.0.0' }, 3841 peerDependencies: { 'peer-dep': '^1.0.0' }, 3842 _id: 'test-npm-ls@1.0.0', 3843 _dependencies: { 'prod-dep': '^1.0.0', chai: '^1.0.0', 'optional-dep': '^1.0.0' }, 3844 path: '{CWD}/prefix', 3845 extraneous: false, 3846 }, 3847 'should output json containing top-level deps in long format' 3848 ) 3849 }) 3850 3851 t.test('json read problems', async t => { 3852 const { result, ls } = await mockLs(t, { 3853 config: { 3854 ...json, 3855 }, 3856 prefixDir: { 3857 'package.json': '{broken json', 3858 }, 3859 }) 3860 await t.rejects( 3861 ls.exec([]), 3862 { code: 'EJSONPARSE', message: 'Failed to parse root package.json' }, 3863 'should have missin root package.json msg' 3864 ) 3865 t.same( 3866 jsonParse(result()), 3867 { 3868 invalid: true, 3869 problems: [ 3870 'error in {CWD}/prefix: Failed to parse root package.json', 3871 ], 3872 error: { 3873 code: 'EJSONPARSE', 3874 summary: 'Failed to parse root package.json', 3875 detail: [ 3876 'Failed to parse JSON data.', 3877 'Note: package.json must be actual JSON, not just JavaScript.', 3878 ].join('\n'), 3879 }, 3880 }, 3881 'should print empty json result' 3882 ) 3883 }) 3884 3885 t.test('empty location', async t => { 3886 const { ls, result } = await mockLs(t, { config: json }) 3887 await ls.exec([]) 3888 t.same(jsonParse(result()), {}, 'should print empty json result') 3889 }) 3890 3891 t.test('unmet peer dep', async t => { 3892 const { result, ls } = await mockLs(t, { 3893 config: { 3894 ...json, 3895 }, 3896 prefixDir: { 3897 'package.json': JSON.stringify({ 3898 name: 'test-npm-ls', 3899 version: '1.0.0', 3900 dependencies: { 3901 'prod-dep': '^1.0.0', 3902 chai: '^1.0.0', 3903 }, 3904 devDependencies: { 3905 'dev-dep': '^1.0.0', 3906 }, 3907 optionalDependencies: { 3908 'optional-dep': '^1.0.0', 3909 }, 3910 peerDependencies: { 3911 'peer-dep': '^2.0.0', // mismatching version # 3912 }, 3913 }), 3914 ...diffDepTypesNmFixture, 3915 }, 3916 }) 3917 await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'Should have ELSPROBLEMS error code') 3918 t.same( 3919 jsonParse(result()), 3920 { 3921 name: 'test-npm-ls', 3922 version: '1.0.0', 3923 problems: [ 3924 'invalid: peer-dep@1.0.0 {CWD}/prefix/node_modules/peer-dep', 3925 ], 3926 dependencies: { 3927 'peer-dep': { 3928 version: '1.0.0', 3929 invalid: '"^2.0.0" from the root project', 3930 overridden: false, 3931 problems: [ 3932 'invalid: peer-dep@1.0.0 {CWD}/prefix/node_modules/peer-dep', 3933 ], 3934 }, 3935 'dev-dep': { 3936 version: '1.0.0', 3937 overridden: false, 3938 dependencies: { 3939 foo: { 3940 version: '1.0.0', 3941 overridden: false, 3942 dependencies: { 3943 dog: { 3944 version: '1.0.0', 3945 overridden: false, 3946 }, 3947 }, 3948 }, 3949 }, 3950 }, 3951 chai: { 3952 version: '1.0.0', 3953 overridden: false, 3954 }, 3955 'optional-dep': { 3956 version: '1.0.0', 3957 overridden: false, 3958 }, 3959 'prod-dep': { 3960 version: '1.0.0', 3961 overridden: false, 3962 dependencies: { 3963 dog: { 3964 version: '2.0.0', 3965 overridden: false, 3966 }, 3967 }, 3968 }, 3969 }, 3970 error: { 3971 code: 'ELSPROBLEMS', 3972 summary: 'invalid: peer-dep@1.0.0 {CWD}/prefix/node_modules/peer-dep', 3973 detail: '', 3974 }, 3975 }, 3976 'should output json signaling missing peer dep in problems' 3977 ) 3978 }) 3979 3980 t.test('unmet optional dep', async t => { 3981 const { result, ls } = await mockLs(t, { 3982 config: { 3983 ...json, 3984 }, 3985 prefixDir: { 3986 'package.json': JSON.stringify({ 3987 name: 'test-npm-ls', 3988 version: '1.0.0', 3989 dependencies: { 3990 'prod-dep': '^1.0.0', 3991 chai: '^1.0.0', 3992 }, 3993 devDependencies: { 3994 'dev-dep': '^1.0.0', 3995 }, 3996 optionalDependencies: { 3997 'missing-optional-dep': '^1.0.0', 3998 'optional-dep': '^2.0.0', // mismatching version # 3999 }, 4000 peerDependencies: { 4001 'peer-dep': '^1.0.0', 4002 }, 4003 }), 4004 ...diffDepTypesNmFixture, 4005 }, 4006 }) 4007 await t.rejects( 4008 ls.exec([]), 4009 { code: 'ELSPROBLEMS', message: /invalid: optional-dep@1.0.0/ }, 4010 'should have invalid dep error msg' 4011 ) 4012 t.same( 4013 jsonParse(result()), 4014 { 4015 name: 'test-npm-ls', 4016 version: '1.0.0', 4017 problems: [ 4018 // mismatching optional deps get flagged in problems 4019 'invalid: optional-dep@1.0.0 {CWD}/prefix/node_modules/optional-dep', 4020 ], 4021 dependencies: { 4022 'optional-dep': { 4023 version: '1.0.0', 4024 invalid: '"^2.0.0" from the root project', 4025 overridden: false, 4026 problems: [ 4027 'invalid: optional-dep@1.0.0 {CWD}/prefix/node_modules/optional-dep', 4028 ], 4029 }, 4030 'peer-dep': { 4031 version: '1.0.0', 4032 overridden: false, 4033 }, 4034 'dev-dep': { 4035 version: '1.0.0', 4036 overridden: false, 4037 dependencies: { 4038 foo: { 4039 version: '1.0.0', 4040 overridden: false, 4041 dependencies: { 4042 dog: { 4043 version: '1.0.0', 4044 overridden: false, 4045 }, 4046 }, 4047 }, 4048 }, 4049 }, 4050 chai: { 4051 version: '1.0.0', 4052 overridden: false, 4053 }, 4054 'prod-dep': { 4055 version: '1.0.0', 4056 overridden: false, 4057 dependencies: { 4058 dog: { 4059 version: '2.0.0', 4060 overridden: false, 4061 }, 4062 }, 4063 }, 4064 'missing-optional-dep': {}, // missing optional dep has an empty entry in json output 4065 }, 4066 error: { 4067 code: 'ELSPROBLEMS', 4068 summary: 'invalid: optional-dep@1.0.0 {CWD}/prefix/node_modules/optional-dep', 4069 detail: '', 4070 }, 4071 }, 4072 'should output json with empty entry for missing optional deps' 4073 ) 4074 }) 4075 4076 t.test('cycle deps', async t => { 4077 const { result, ls } = await mockLs(t, { 4078 config: { 4079 ...json, 4080 }, 4081 prefixDir: { 4082 'package.json': JSON.stringify({ 4083 name: 'test-npm-ls', 4084 version: '1.0.0', 4085 dependencies: { 4086 a: '^1.0.0', 4087 }, 4088 }), 4089 node_modules: { 4090 a: { 4091 'package.json': JSON.stringify({ 4092 name: 'a', 4093 version: '1.0.0', 4094 dependencies: { 4095 b: '^1.0.0', 4096 }, 4097 }), 4098 }, 4099 b: { 4100 'package.json': JSON.stringify({ 4101 name: 'b', 4102 version: '1.0.0', 4103 dependencies: { 4104 a: '^1.0.0', 4105 }, 4106 }), 4107 }, 4108 }, 4109 }, 4110 }) 4111 await ls.exec([]) 4112 t.same( 4113 jsonParse(result()), 4114 { 4115 name: 'test-npm-ls', 4116 version: '1.0.0', 4117 dependencies: { 4118 a: { 4119 version: '1.0.0', 4120 overridden: false, 4121 dependencies: { 4122 b: { 4123 version: '1.0.0', 4124 overridden: false, 4125 dependencies: { 4126 a: { 4127 version: '1.0.0', 4128 }, 4129 }, 4130 }, 4131 }, 4132 }, 4133 }, 4134 }, 4135 'should print json output containing deduped ref' 4136 ) 4137 }) 4138 4139 t.test('using aliases', async t => { 4140 const { npm, result, ls } = await mockLs(t, { 4141 config: { 4142 ...json, 4143 }, 4144 prefixDir: { 4145 'package.json': JSON.stringify({ 4146 name: 'test-npm-ls', 4147 version: '1.0.0', 4148 dependencies: { 4149 a: 'npm:b@1.0.0', 4150 }, 4151 }), 4152 node_modules: { 4153 '.package-lock.json': JSON.stringify({ 4154 packages: { 4155 'node_modules/a': { 4156 name: 'b', 4157 version: '1.0.0', 4158 from: 'a@npm:b', 4159 resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', 4160 requested: { 4161 type: 'alias', 4162 }, 4163 }, 4164 }, 4165 }), 4166 a: { 4167 'package.json': JSON.stringify({ 4168 name: 'b', 4169 version: '1.0.0', 4170 }), 4171 }, 4172 }, 4173 }, 4174 }) 4175 touchHiddenPackageLock(npm.prefix) 4176 await ls.exec([]) 4177 t.same( 4178 jsonParse(result()), 4179 { 4180 name: 'test-npm-ls', 4181 version: '1.0.0', 4182 dependencies: { 4183 a: { 4184 version: '1.0.0', 4185 overridden: false, 4186 resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz', 4187 }, 4188 }, 4189 }, 4190 'should output json containing aliases' 4191 ) 4192 }) 4193 4194 t.test('resolved points to git ref', async t => { 4195 const { npm, result, ls } = await mockLs(t, { 4196 config: { 4197 ...json, 4198 }, 4199 prefixDir: { 4200 'package.json': JSON.stringify({ 4201 name: 'test-npm-ls', 4202 version: '1.0.0', 4203 dependencies: { 4204 abbrev: 'git+https://github.com/isaacs/abbrev-js.git', 4205 }, 4206 }), 4207 node_modules: { 4208 '.package-lock.json': JSON.stringify({ 4209 packages: { 4210 'node_modules/abbrev': { 4211 name: 'abbrev', 4212 version: '1.1.1', 4213 id: 'abbrev@1.1.1', 4214 from: 'git+https://github.com/isaacs/abbrev-js.git', 4215 /* eslint-disable-next-line max-len */ 4216 resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', 4217 }, 4218 }, 4219 }), 4220 abbrev: { 4221 'package.json': JSON.stringify({ 4222 name: 'abbrev', 4223 version: '1.1.1', 4224 _id: 'abbrev@1.1.1', 4225 _from: 'git+https://github.com/isaacs/abbrev-js.git', 4226 /* eslint-disable-next-line max-len */ 4227 _resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', 4228 _requested: { 4229 type: 'git', 4230 raw: 'git+https:github.com/isaacs/abbrev-js.git', 4231 rawSpec: 'git+https:github.com/isaacs/abbrev-js.git', 4232 saveSpec: 'git+https://github.com/isaacs/abbrev-js.git', 4233 fetchSpec: 'https://github.com/isaacs/abbrev-js.git', 4234 gitCommittish: null, 4235 }, 4236 }), 4237 }, 4238 }, 4239 }, 4240 }) 4241 touchHiddenPackageLock(npm.prefix) 4242 await ls.exec([]) 4243 t.same( 4244 jsonParse(result()), 4245 { 4246 name: 'test-npm-ls', 4247 version: '1.0.0', 4248 dependencies: { 4249 abbrev: { 4250 version: '1.1.1', 4251 overridden: false, 4252 /* eslint-disable-next-line max-len */ 4253 resolved: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', 4254 }, 4255 }, 4256 }, 4257 'should output json containing git refs' 4258 ) 4259 }) 4260 4261 t.test('from and resolved properties', async t => { 4262 const { npm, result, ls } = await mockLs(t, { 4263 config: { 4264 ...json, 4265 }, 4266 prefixDir: { 4267 'package.json': JSON.stringify({ 4268 name: 'test-npm-ls', 4269 version: '1.0.0', 4270 dependencies: { 4271 'simple-output': '^2.0.0', 4272 }, 4273 }), 4274 node_modules: { 4275 '.package-lock.json': JSON.stringify({ 4276 packages: { 4277 'node_modules/simple-output': { 4278 name: 'simple-output', 4279 version: '2.1.1', 4280 _from: 'simple-output', 4281 _id: 'simple-output@2.1.1', 4282 _resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', 4283 _requested: { 4284 type: 'tag', 4285 registry: true, 4286 raw: 'simple-output', 4287 name: 'simple-output', 4288 escapedName: 'simple-output', 4289 rawSpec: '', 4290 saveSpec: null, 4291 fetchSpec: 'latest', 4292 }, 4293 _requiredBy: ['#USER', '/'], 4294 _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', 4295 _spec: 'simple-output', 4296 }, 4297 }, 4298 }), 4299 'simple-output': { 4300 'package.json': JSON.stringify({ 4301 name: 'simple-output', 4302 version: '2.1.1', 4303 _from: 'simple-output', 4304 _id: 'simple-output@2.1.1', 4305 _resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', 4306 _requested: { 4307 type: 'tag', 4308 registry: true, 4309 raw: 'simple-output', 4310 name: 'simple-output', 4311 escapedName: 'simple-output', 4312 rawSpec: '', 4313 saveSpec: null, 4314 fetchSpec: 'latest', 4315 }, 4316 _requiredBy: ['#USER', '/'], 4317 _shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc', 4318 _spec: 'simple-output', 4319 }), 4320 }, 4321 }, 4322 }, 4323 }) 4324 touchHiddenPackageLock(npm.prefix) 4325 await ls.exec([]) 4326 t.same( 4327 jsonParse(result()), 4328 { 4329 name: 'test-npm-ls', 4330 version: '1.0.0', 4331 dependencies: { 4332 'simple-output': { 4333 version: '2.1.1', 4334 overridden: false, 4335 resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz', 4336 }, 4337 }, 4338 }, 4339 'should be printed in json output' 4340 ) 4341 }) 4342 4343 t.test('node.name fallback if missing root package name', async t => { 4344 const { result, ls } = await mockLs(t, { 4345 config: { 4346 ...json, 4347 }, 4348 prefixDir: { 4349 'package.json': JSON.stringify({ 4350 version: '1.0.0', 4351 }), 4352 }, 4353 }) 4354 await ls.exec([]) 4355 t.same( 4356 jsonParse(result()), 4357 { 4358 version: '1.0.0', 4359 name: 'prefix', 4360 }, 4361 'should use node.name as key in json result obj' 4362 ) 4363 }) 4364 4365 t.test('global', async t => { 4366 const { result, ls } = await mockLs(t, { 4367 config: { 4368 ...json, 4369 global: true, 4370 }, 4371 globalPrefixDir: { 4372 node_modules: { 4373 a: { 4374 'package.json': JSON.stringify({ 4375 name: 'a', 4376 version: '1.0.0', 4377 }), 4378 }, 4379 b: { 4380 'package.json': JSON.stringify({ 4381 name: 'b', 4382 version: '1.0.0', 4383 }), 4384 node_modules: { 4385 c: { 4386 'package.json': JSON.stringify({ 4387 name: 'c', 4388 version: '1.0.0', 4389 }), 4390 }, 4391 }, 4392 }, 4393 }, 4394 }, 4395 }) 4396 4397 await ls.exec([]) 4398 t.same( 4399 jsonParse(result()), 4400 { 4401 name: process.platform === 'win32' ? 'global' : 'lib', 4402 dependencies: { 4403 a: { 4404 version: '1.0.0', 4405 overridden: false, 4406 }, 4407 b: { 4408 version: '1.0.0', 4409 overridden: false, 4410 dependencies: { 4411 c: { 4412 version: '1.0.0', 4413 overridden: false, 4414 }, 4415 }, 4416 }, 4417 }, 4418 }, 4419 'should print json output for global deps' 4420 ) 4421 }) 4422}) 4423 4424t.test('show multiple invalid reasons', async t => { 4425 const { result, ls } = await mockLs(t, { 4426 config: {}, 4427 prefixDir: { 4428 'package.json': JSON.stringify({ 4429 name: 'test-npm-ls', 4430 version: '1.0.0', 4431 dependencies: { 4432 cat: '^2.0.0', 4433 dog: '^1.2.3', 4434 }, 4435 }), 4436 node_modules: { 4437 cat: { 4438 'package.json': JSON.stringify({ 4439 name: 'cat', 4440 version: '1.0.0', 4441 dependencies: { 4442 dog: '^2.0.0', 4443 }, 4444 }), 4445 }, 4446 dog: { 4447 'package.json': JSON.stringify({ 4448 name: 'dog', 4449 version: '1.0.0', 4450 dependencies: { 4451 cat: '', 4452 }, 4453 }), 4454 }, 4455 chai: { 4456 'package.json': JSON.stringify({ 4457 name: 'chai', 4458 version: '1.0.0', 4459 dependencies: { 4460 dog: '2.x', 4461 }, 4462 }), 4463 }, 4464 }, 4465 }, 4466 }) 4467 4468 await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems') 4469 t.matchSnapshot(cleanCwd(result()), 'ls result') 4470}) 4471 4472t.test('ls --package-lock-only', async t => { 4473 const lock = { 'package-lock-only': true } 4474 4475 t.test('ls --package-lock-only --json', async t => { 4476 const json = { json: true } 4477 4478 t.test('no args', async t => { 4479 const { result, ls } = await mockLs(t, { 4480 config: { 4481 ...lock, 4482 ...json, 4483 }, 4484 prefixDir: { 4485 'package.json': JSON.stringify({ 4486 name: 'test-npm-ls', 4487 version: '1.0.0', 4488 dependencies: { 4489 foo: '^1.0.0', 4490 chai: '^1.0.0', 4491 }, 4492 }), 4493 'package-lock.json': JSON.stringify({ 4494 dependencies: { 4495 foo: { 4496 version: '1.0.0', 4497 requires: { 4498 dog: '^1.0.0', 4499 }, 4500 }, 4501 dog: { 4502 version: '1.0.0', 4503 }, 4504 chai: { 4505 version: '1.0.0', 4506 }, 4507 }, 4508 }), 4509 }, 4510 }) 4511 await ls.exec([]) 4512 t.same( 4513 jsonParse(result()), 4514 { 4515 name: 'test-npm-ls', 4516 version: '1.0.0', 4517 dependencies: { 4518 foo: { 4519 version: '1.0.0', 4520 overridden: false, 4521 dependencies: { 4522 dog: { 4523 version: '1.0.0', 4524 overridden: false, 4525 }, 4526 }, 4527 }, 4528 chai: { 4529 version: '1.0.0', 4530 overridden: false, 4531 }, 4532 }, 4533 }, 4534 'should output json representation of dependencies structure' 4535 ) 4536 }) 4537 4538 t.test('extraneous deps', async t => { 4539 const { result, ls } = await mockLs(t, { 4540 config: { 4541 ...lock, 4542 ...json, 4543 }, 4544 prefixDir: { 4545 'package.json': JSON.stringify({ 4546 name: 'test-npm-ls', 4547 version: '1.0.0', 4548 dependencies: { 4549 foo: '^1.0.0', 4550 }, 4551 }), 4552 'package-lock.json': JSON.stringify({ 4553 dependencies: { 4554 foo: { 4555 version: '1.0.0', 4556 requires: { 4557 dog: '^1.0.0', 4558 }, 4559 }, 4560 dog: { 4561 version: '1.0.0', 4562 }, 4563 chai: { 4564 version: '1.0.0', 4565 }, 4566 }, 4567 }), 4568 }, 4569 }) 4570 await ls.exec([]) 4571 t.same( 4572 jsonParse(result()), 4573 { 4574 name: 'test-npm-ls', 4575 version: '1.0.0', 4576 dependencies: { 4577 foo: { 4578 version: '1.0.0', 4579 overridden: false, 4580 dependencies: { 4581 dog: { 4582 version: '1.0.0', 4583 overridden: false, 4584 }, 4585 }, 4586 }, 4587 }, 4588 }, 4589 'should output json containing no problem info' 4590 ) 4591 }) 4592 4593 t.test('missing deps --long', async t => { 4594 const { result, ls } = await mockLs(t, { 4595 config: { 4596 ...lock, 4597 ...json, 4598 long: true, 4599 }, 4600 prefixDir: { 4601 'package.json': JSON.stringify({ 4602 name: 'test-npm-ls', 4603 version: '1.0.0', 4604 dependencies: { 4605 foo: '^1.0.0', 4606 dog: '^1.0.0', 4607 chai: '^1.0.0', 4608 ipsum: '^1.0.0', 4609 }, 4610 }), 4611 'package-lock.json': JSON.stringify({ 4612 dependencies: { 4613 foo: { 4614 version: '1.0.0', 4615 requires: { 4616 dog: '^1.0.0', 4617 }, 4618 }, 4619 dog: { 4620 version: '1.0.0', 4621 }, 4622 chai: { 4623 version: '1.0.0', 4624 }, 4625 ipsum: { 4626 version: '1.0.0', 4627 }, 4628 }, 4629 }), 4630 }, 4631 }) 4632 await ls.exec([]) 4633 t.match( 4634 jsonParse(result()), 4635 { 4636 name: 'test-npm-ls', 4637 version: '1.0.0', 4638 }, 4639 'should output json containing no problems info' 4640 ) 4641 }) 4642 4643 t.test('with filter arg', async t => { 4644 const { result, ls } = await mockLs(t, { 4645 config: { 4646 ...lock, 4647 ...json, 4648 }, 4649 prefixDir: { 4650 'package.json': JSON.stringify({ 4651 name: 'test-npm-ls', 4652 version: '1.0.0', 4653 dependencies: { 4654 foo: '^1.0.0', 4655 chai: '^1.0.0', 4656 }, 4657 }), 4658 'package-lock.json': JSON.stringify({ 4659 dependencies: { 4660 foo: { 4661 version: '1.0.0', 4662 requires: { 4663 dog: '^1.0.0', 4664 }, 4665 }, 4666 dog: { 4667 version: '1.0.0', 4668 }, 4669 chai: { 4670 version: '1.0.0', 4671 }, 4672 ipsum: { 4673 version: '1.0.0', 4674 }, 4675 }, 4676 }), 4677 }, 4678 }) 4679 await ls.exec(['chai']) 4680 t.same( 4681 jsonParse(result()), 4682 { 4683 name: 'test-npm-ls', 4684 version: '1.0.0', 4685 dependencies: { 4686 chai: { 4687 version: '1.0.0', 4688 overridden: false, 4689 }, 4690 }, 4691 }, 4692 'should output json contaning only occurrences of filtered by package' 4693 ) 4694 t.notOk(process.exitCode, 'should not set exit code') 4695 }) 4696 4697 t.test('with filter arg nested dep', async t => { 4698 const { result, ls } = await mockLs(t, { 4699 config: { 4700 ...lock, 4701 ...json, 4702 }, 4703 prefixDir: { 4704 'package.json': JSON.stringify({ 4705 name: 'test-npm-ls', 4706 version: '1.0.0', 4707 dependencies: { 4708 foo: '^1.0.0', 4709 chai: '^1.0.0', 4710 }, 4711 }), 4712 'package-lock.json': JSON.stringify({ 4713 dependencies: { 4714 foo: { 4715 version: '1.0.0', 4716 requires: { 4717 dog: '^1.0.0', 4718 }, 4719 }, 4720 dog: { 4721 version: '1.0.0', 4722 }, 4723 chai: { 4724 version: '1.0.0', 4725 }, 4726 ipsum: { 4727 version: '1.0.0', 4728 }, 4729 }, 4730 }), 4731 }, 4732 }) 4733 await ls.exec(['dog']) 4734 t.same( 4735 jsonParse(result()), 4736 { 4737 name: 'test-npm-ls', 4738 version: '1.0.0', 4739 dependencies: { 4740 foo: { 4741 version: '1.0.0', 4742 overridden: false, 4743 dependencies: { 4744 dog: { 4745 version: '1.0.0', 4746 overridden: false, 4747 }, 4748 }, 4749 }, 4750 }, 4751 }, 4752 'should output json contaning only occurrences of filtered by package' 4753 ) 4754 }) 4755 4756 t.test('with multiple filter args', async t => { 4757 const { result, ls } = await mockLs(t, { 4758 config: { 4759 ...lock, 4760 ...json, 4761 }, 4762 prefixDir: { 4763 'package.json': JSON.stringify({ 4764 name: 'test-npm-ls', 4765 version: '1.0.0', 4766 dependencies: { 4767 foo: '^1.0.0', 4768 chai: '^1.0.0', 4769 ipsum: '^1.0.0', 4770 }, 4771 }), 4772 'package-lock.json': JSON.stringify({ 4773 dependencies: { 4774 foo: { 4775 version: '1.0.0', 4776 requires: { 4777 dog: '^1.0.0', 4778 }, 4779 }, 4780 dog: { 4781 version: '1.0.0', 4782 }, 4783 chai: { 4784 version: '1.0.0', 4785 }, 4786 ipsum: { 4787 version: '1.0.0', 4788 }, 4789 }, 4790 }), 4791 }, 4792 }) 4793 await ls.exec(['dog@*', 'chai@1.0.0']) 4794 t.same( 4795 jsonParse(result()), 4796 { 4797 version: '1.0.0', 4798 name: 'test-npm-ls', 4799 dependencies: { 4800 foo: { 4801 version: '1.0.0', 4802 overridden: false, 4803 dependencies: { 4804 dog: { 4805 version: '1.0.0', 4806 overridden: false, 4807 }, 4808 }, 4809 }, 4810 chai: { 4811 version: '1.0.0', 4812 overridden: false, 4813 }, 4814 }, 4815 }, 4816 /* eslint-disable-next-line max-len */ 4817 'should output json contaning only occurrences of multiple filtered packages and their ancestors' 4818 ) 4819 }) 4820 4821 t.test('with missing filter arg', async t => { 4822 const { result, ls } = await mockLs(t, { 4823 config: { 4824 ...lock, 4825 ...json, 4826 }, 4827 prefixDir: { 4828 'package.json': JSON.stringify({ 4829 name: 'test-npm-ls', 4830 version: '1.0.0', 4831 dependencies: { 4832 foo: '^1.0.0', 4833 chai: '^1.0.0', 4834 }, 4835 }), 4836 'package-lock.json': JSON.stringify({ 4837 dependencies: { 4838 foo: { 4839 version: '1.0.0', 4840 requires: { 4841 dog: '^1.0.0', 4842 }, 4843 }, 4844 dog: { 4845 version: '1.0.0', 4846 }, 4847 chai: { 4848 version: '1.0.0', 4849 }, 4850 }, 4851 }), 4852 }, 4853 }) 4854 await ls.exec(['notadep']) 4855 t.same( 4856 jsonParse(result()), 4857 { 4858 name: 'test-npm-ls', 4859 version: '1.0.0', 4860 }, 4861 'should output json containing no dependencies info' 4862 ) 4863 t.equal(process.exitCode, 1, 'should exit with error code 1') 4864 }) 4865 4866 t.test('default --depth value should now be 0', async t => { 4867 const { result, ls } = await mockLs(t, { 4868 config: { 4869 ...lock, 4870 ...json, 4871 all: false, 4872 }, 4873 prefixDir: { 4874 'package.json': JSON.stringify({ 4875 name: 'test-npm-ls', 4876 version: '1.0.0', 4877 dependencies: { 4878 foo: '^1.0.0', 4879 chai: '^1.0.0', 4880 }, 4881 }), 4882 'package-lock.json': JSON.stringify({ 4883 dependencies: { 4884 foo: { 4885 version: '1.0.0', 4886 requires: { 4887 dog: '^1.0.0', 4888 }, 4889 }, 4890 dog: { 4891 version: '1.0.0', 4892 }, 4893 chai: { 4894 version: '1.0.0', 4895 }, 4896 }, 4897 }), 4898 }, 4899 }) 4900 await ls.exec([]) 4901 t.same( 4902 jsonParse(result()), 4903 { 4904 name: 'test-npm-ls', 4905 version: '1.0.0', 4906 dependencies: { 4907 foo: { 4908 version: '1.0.0', 4909 overridden: false, 4910 }, 4911 chai: { 4912 version: '1.0.0', 4913 overridden: false, 4914 }, 4915 }, 4916 }, 4917 'should output json containing only top-level dependencies' 4918 ) 4919 }) 4920 4921 t.test('--depth=0', async t => { 4922 const { result, ls } = await mockLs(t, { 4923 config: { 4924 ...lock, 4925 ...json, 4926 depth: 0, 4927 all: false, 4928 }, 4929 prefixDir: { 4930 'package.json': JSON.stringify({ 4931 name: 'test-npm-ls', 4932 version: '1.0.0', 4933 dependencies: { 4934 foo: '^1.0.0', 4935 chai: '^1.0.0', 4936 }, 4937 }), 4938 'package-lock.json': JSON.stringify({ 4939 dependencies: { 4940 foo: { 4941 version: '1.0.0', 4942 requires: { 4943 dog: '^1.0.0', 4944 }, 4945 }, 4946 dog: { 4947 version: '1.0.0', 4948 }, 4949 chai: { 4950 version: '1.0.0', 4951 }, 4952 }, 4953 }), 4954 }, 4955 }) 4956 await ls.exec([]) 4957 t.same( 4958 jsonParse(result()), 4959 { 4960 name: 'test-npm-ls', 4961 version: '1.0.0', 4962 dependencies: { 4963 foo: { 4964 version: '1.0.0', 4965 overridden: false, 4966 }, 4967 chai: { 4968 version: '1.0.0', 4969 overridden: false, 4970 }, 4971 }, 4972 }, 4973 'should output json containing only top-level dependencies' 4974 ) 4975 }) 4976 4977 t.test('--depth=1', async t => { 4978 const { result, ls } = await mockLs(t, { 4979 config: { 4980 ...lock, 4981 ...json, 4982 all: false, 4983 depth: 1, 4984 }, 4985 prefixDir: { 4986 'package.json': JSON.stringify({ 4987 name: 'test-npm-ls', 4988 version: '1.0.0', 4989 dependencies: { 4990 foo: '^1.0.0', 4991 chai: '^1.0.0', 4992 }, 4993 }), 4994 'package-lock.json': JSON.stringify({ 4995 dependencies: { 4996 foo: { 4997 version: '1.0.0', 4998 requires: { 4999 dog: '^1.0.0', 5000 }, 5001 }, 5002 dog: { 5003 version: '1.0.0', 5004 }, 5005 chai: { 5006 version: '1.0.0', 5007 }, 5008 }, 5009 }), 5010 }, 5011 }) 5012 await ls.exec([]) 5013 t.same( 5014 jsonParse(result()), 5015 { 5016 name: 'test-npm-ls', 5017 version: '1.0.0', 5018 dependencies: { 5019 foo: { 5020 version: '1.0.0', 5021 overridden: false, 5022 dependencies: { 5023 dog: { 5024 version: '1.0.0', 5025 overridden: false, 5026 }, 5027 }, 5028 }, 5029 chai: { 5030 version: '1.0.0', 5031 overridden: false, 5032 }, 5033 }, 5034 }, 5035 'should output json containing top-level deps and their deps only' 5036 ) 5037 }) 5038 5039 t.test('missing/invalid/extraneous', async t => { 5040 const { result, ls } = await mockLs(t, { 5041 config: { 5042 ...lock, 5043 ...json, 5044 }, 5045 prefixDir: { 5046 'package.json': JSON.stringify({ 5047 name: 'test-npm-ls', 5048 version: '1.0.0', 5049 dependencies: { 5050 foo: '^2.0.0', 5051 ipsum: '^1.0.0', 5052 }, 5053 }), 5054 'package-lock.json': JSON.stringify({ 5055 dependencies: { 5056 foo: { 5057 version: '1.0.0', 5058 requires: { 5059 dog: '^1.0.0', 5060 }, 5061 }, 5062 dog: { 5063 version: '1.0.0', 5064 }, 5065 chai: { 5066 version: '1.0.0', 5067 }, 5068 }, 5069 }), 5070 }, 5071 }) 5072 await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems') 5073 t.same( 5074 jsonParse(result()), 5075 { 5076 name: 'test-npm-ls', 5077 version: '1.0.0', 5078 problems: [ 5079 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo', 5080 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', 5081 ], 5082 dependencies: { 5083 foo: { 5084 version: '1.0.0', 5085 overridden: false, 5086 invalid: '"^2.0.0" from the root project', 5087 problems: [ 5088 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo', 5089 ], 5090 dependencies: { 5091 dog: { 5092 version: '1.0.0', 5093 overridden: false, 5094 }, 5095 }, 5096 }, 5097 ipsum: { 5098 required: '^1.0.0', 5099 missing: true, 5100 problems: ['missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0'], 5101 }, 5102 }, 5103 error: { 5104 code: 'ELSPROBLEMS', 5105 summary: [ 5106 'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo', 5107 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', 5108 ].join('\n'), 5109 detail: '', 5110 }, 5111 }, 5112 'should output json containing top-level deps and their deps only' 5113 ) 5114 }) 5115 5116 t.test('from lockfile', async t => { 5117 const { result, ls } = await mockLs(t, { 5118 config: { 5119 ...lock, 5120 ...json, 5121 }, 5122 prefixDir: { 5123 'package-lock.json': JSON.stringify({ 5124 name: 'dedupe-lockfile', 5125 version: '1.0.0', 5126 lockfileVersion: 2, 5127 requires: true, 5128 packages: { 5129 '': { 5130 name: 'dedupe-lockfile', 5131 version: '1.0.0', 5132 dependencies: { 5133 '@isaacs/dedupe-tests-a': '1.0.1', 5134 '@isaacs/dedupe-tests-b': '1||2', 5135 }, 5136 }, 5137 'node_modules/@isaacs/dedupe-tests-a': { 5138 name: '@isaacs/dedupe-tests-a', 5139 version: '1.0.1', 5140 /* eslint-disable-next-line max-len */ 5141 resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', 5142 /* eslint-disable-next-line max-len */ 5143 integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==', 5144 dependencies: { 5145 '@isaacs/dedupe-tests-b': '1', 5146 }, 5147 }, 5148 'node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b': { 5149 name: '@isaacs/dedupe-tests-b', 5150 version: '1.0.0', 5151 /* eslint-disable-next-line max-len */ 5152 resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', 5153 /* eslint-disable-next-line max-len */ 5154 integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==', 5155 }, 5156 'node_modules/@isaacs/dedupe-tests-b': { 5157 name: '@isaacs/dedupe-tests-b', 5158 version: '2.0.0', 5159 /* eslint-disable-next-line max-len */ 5160 resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', 5161 /* eslint-disable-next-line max-len */ 5162 integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==', 5163 }, 5164 }, 5165 dependencies: { 5166 '@isaacs/dedupe-tests-a': { 5167 version: '1.0.1', 5168 /* eslint-disable-next-line max-len */ 5169 resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', 5170 /* eslint-disable-next-line max-len */ 5171 integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==', 5172 requires: { 5173 '@isaacs/dedupe-tests-b': '1', 5174 }, 5175 dependencies: { 5176 '@isaacs/dedupe-tests-b': { 5177 version: '1.0.0', 5178 /* eslint-disable-next-line max-len */ 5179 resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', 5180 /* eslint-disable-next-line max-len */ 5181 integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==', 5182 }, 5183 }, 5184 }, 5185 '@isaacs/dedupe-tests-b': { 5186 version: '2.0.0', 5187 /* eslint-disable-next-line max-len */ 5188 resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', 5189 /* eslint-disable-next-line max-len */ 5190 integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==', 5191 }, 5192 }, 5193 }), 5194 'package.json': JSON.stringify({ 5195 name: 'dedupe-lockfile', 5196 version: '1.0.0', 5197 dependencies: { 5198 '@isaacs/dedupe-tests-a': '1.0.1', 5199 '@isaacs/dedupe-tests-b': '1||2', 5200 }, 5201 }), 5202 }, 5203 }) 5204 await ls.exec([]) 5205 t.same( 5206 jsonParse(result()), 5207 { 5208 version: '1.0.0', 5209 name: 'dedupe-lockfile', 5210 dependencies: { 5211 '@isaacs/dedupe-tests-a': { 5212 version: '1.0.1', 5213 overridden: false, 5214 resolved: 5215 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz', 5216 dependencies: { 5217 '@isaacs/dedupe-tests-b': { 5218 version: '1.0.0', 5219 overridden: false, 5220 resolved: 5221 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', 5222 }, 5223 }, 5224 }, 5225 '@isaacs/dedupe-tests-b': { 5226 version: '2.0.0', 5227 overridden: false, 5228 resolved: 5229 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz', 5230 }, 5231 }, 5232 }, 5233 'should output json containing only prod deps' 5234 ) 5235 }) 5236 5237 t.test('using aliases', async t => { 5238 const { result, ls } = await mockLs(t, { 5239 config: { 5240 ...lock, 5241 ...json, 5242 }, 5243 prefixDir: { 5244 'package.json': JSON.stringify({ 5245 name: 'test-npm-ls', 5246 version: '1.0.0', 5247 dependencies: { 5248 a: 'npm:b@1.0.0', 5249 }, 5250 }), 5251 'package-lock.json': JSON.stringify({ 5252 dependencies: { 5253 a: { 5254 version: 'npm:b@1.0.0', 5255 resolved: 'https://localhost:8080/abbrev/-/abbrev-1.0.0.tgz', 5256 }, 5257 }, 5258 }), 5259 }, 5260 }) 5261 await ls.exec([]) 5262 t.same( 5263 jsonParse(result()), 5264 { 5265 name: 'test-npm-ls', 5266 version: '1.0.0', 5267 dependencies: { 5268 a: { 5269 version: '1.0.0', 5270 overridden: false, 5271 resolved: 'https://localhost:8080/abbrev/-/abbrev-1.0.0.tgz', 5272 }, 5273 }, 5274 }, 5275 'should output json containing aliases' 5276 ) 5277 }) 5278 5279 t.test('resolved points to git ref', async t => { 5280 const { result, ls } = await mockLs(t, { 5281 config: { 5282 ...lock, 5283 ...json, 5284 long: false, 5285 }, 5286 prefixDir: { 5287 'package.json': JSON.stringify({ 5288 name: 'test-npm-ls', 5289 version: '1.0.0', 5290 dependencies: { 5291 abbrev: 'git+https://github.com/isaacs/abbrev-js.git', 5292 }, 5293 }), 5294 'package-lock.json': JSON.stringify({ 5295 name: 'test-npm-ls', 5296 version: '1.0.0', 5297 lockfileVersion: 2, 5298 requires: true, 5299 dependencies: { 5300 abbrev: { 5301 /* eslint-disable-next-line max-len */ 5302 version: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', 5303 from: 'abbrev@git+https://github.com/isaacs/abbrev-js.git', 5304 }, 5305 }, 5306 }), 5307 }, 5308 }) 5309 await ls.exec([]) 5310 t.same( 5311 jsonParse(result()), 5312 { 5313 name: 'test-npm-ls', 5314 version: '1.0.0', 5315 dependencies: { 5316 abbrev: { 5317 /* eslint-disable-next-line max-len */ 5318 resolved: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', 5319 overridden: false, 5320 }, 5321 }, 5322 }, 5323 'should output json containing git refs' 5324 ) 5325 }) 5326 }) 5327}) 5328