xref: /third_party/node/deps/npm/test/lib/commands/ls.js (revision 1cb0ef41)
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