PR-URL: https://github.com/nodejs/node/pull/56818 Reviewed-By: Jordan Harband <ljharb@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
5288 lines
139 KiB
JavaScript
5288 lines
139 KiB
JavaScript
// TODO(isaacs): This test has a lot of very large objects pasted inline.
|
|
// Consider using t.matchSnapshot on these instead, especially since many
|
|
// of them contain the tap testdir folders, which are auto-generated and
|
|
// may change when node-tap is updated.
|
|
|
|
const t = require('tap')
|
|
const { utimesSync } = require('node:fs')
|
|
const mockNpm = require('../../fixtures/mock-npm.js')
|
|
const { cleanCwd } = require('../../fixtures/clean-snapshot')
|
|
|
|
const touchHiddenPackageLock = prefix => {
|
|
const later = new Date(Date.now() + 10000)
|
|
utimesSync(`${prefix}/node_modules/.package-lock.json`, later, later)
|
|
}
|
|
|
|
t.cleanSnapshot = str => cleanCwd(str)
|
|
|
|
const simpleNmFixture = {
|
|
node_modules: {
|
|
foo: {
|
|
'package.json': JSON.stringify({
|
|
name: 'foo',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
dog: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
dog: {
|
|
'package.json': JSON.stringify({
|
|
name: 'dog',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
chai: {
|
|
'package.json': JSON.stringify({
|
|
name: 'chai',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
}
|
|
|
|
const diffDepTypesNmFixture = {
|
|
node_modules: {
|
|
'dev-dep': {
|
|
'package.json': JSON.stringify({
|
|
name: 'dev-dep',
|
|
description: 'A DEV dep kind of dep',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
'prod-dep': {
|
|
'package.json': JSON.stringify({
|
|
name: 'prod-dep',
|
|
description: 'A PROD dep kind of dep',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
dog: '^2.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
dog: {
|
|
'package.json': JSON.stringify({
|
|
name: 'dog',
|
|
description: 'A dep that bars',
|
|
version: '2.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
'optional-dep': {
|
|
'package.json': JSON.stringify({
|
|
name: 'optional-dep',
|
|
description: 'Maybe a dep?',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
'peer-dep': {
|
|
'package.json': JSON.stringify({
|
|
name: 'peer-dep',
|
|
description: 'Peer-dep description here',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
...simpleNmFixture.node_modules,
|
|
},
|
|
}
|
|
|
|
const mockLs = async (t, { mocks, config, ...opts } = {}) => {
|
|
const mock = await mockNpm(t, {
|
|
...opts,
|
|
config: {
|
|
all: true,
|
|
...config,
|
|
},
|
|
command: 'ls',
|
|
mocks: {
|
|
path: {
|
|
...require('node:path'),
|
|
sep: '/',
|
|
},
|
|
...mocks,
|
|
},
|
|
})
|
|
|
|
return {
|
|
...mock,
|
|
result: () => mock.joinedOutput(),
|
|
}
|
|
}
|
|
|
|
const redactCwdObj = obj => {
|
|
if (Array.isArray(obj)) {
|
|
return obj.map(o => redactCwdObj(o))
|
|
}
|
|
if (obj && typeof obj === 'object') {
|
|
return Object.keys(obj).reduce((o, k) => {
|
|
o[k] = redactCwdObj(obj[k])
|
|
return o
|
|
}, {})
|
|
}
|
|
return typeof obj === 'string' ? cleanCwd(obj) : obj
|
|
}
|
|
|
|
const jsonParse = res => redactCwdObj(JSON.parse(res))
|
|
|
|
t.test('ls', async t => {
|
|
t.test('no args', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
// config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output tree representation of dependencies structure'
|
|
)
|
|
})
|
|
|
|
t.test('missing package.json', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output tree missing name/version of top-level package'
|
|
)
|
|
})
|
|
|
|
t.test('workspace and missing optional dep', async t => {
|
|
const config = {
|
|
'include-workspace-root': true,
|
|
workspace: 'baz',
|
|
}
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'root',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
bar: '^1.0.0',
|
|
},
|
|
workspaces: ['./baz'],
|
|
}),
|
|
baz: {
|
|
'package.json': JSON.stringify({
|
|
name: 'baz',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
node_modules: {
|
|
baz: t.fixture('symlink', '../baz'),
|
|
foo: {
|
|
'package.json': JSON.stringify({
|
|
name: 'foo',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should omit missing optional dep')
|
|
})
|
|
|
|
t.test('extraneous deps', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output containing problems info')
|
|
})
|
|
|
|
t.test('overridden dep', async t => {
|
|
const config = {
|
|
}
|
|
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-overridden',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
},
|
|
overrides: {
|
|
bar: '1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
foo: {
|
|
'package.json': JSON.stringify({
|
|
name: 'foo',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
bar: '^2.0.0',
|
|
},
|
|
}),
|
|
},
|
|
bar: {
|
|
'package.json': JSON.stringify({
|
|
name: 'bar',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
await
|
|
|
|
ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should contain overridden outout')
|
|
})
|
|
|
|
t.test('overridden dep w/ color', async t => {
|
|
const config = {
|
|
color: 'always',
|
|
}
|
|
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-overridden',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
},
|
|
overrides: {
|
|
bar: '1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
foo: {
|
|
'package.json': JSON.stringify({
|
|
name: 'foo',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
bar: '^2.0.0',
|
|
},
|
|
}),
|
|
},
|
|
bar: {
|
|
'package.json': JSON.stringify({
|
|
name: 'bar',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should contain overridden outout')
|
|
})
|
|
|
|
t.test('with filter arg', async t => {
|
|
const config = {
|
|
color: 'always',
|
|
}
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec(['chai'])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output tree contaning only occurrences of filtered by package and colored output'
|
|
)
|
|
})
|
|
|
|
t.test('with dot filter arg', async t => {
|
|
const config = {
|
|
all: false,
|
|
depth: 0,
|
|
}
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
ipsum: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec(['.'])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output tree contaning only occurrences of filtered by package and colored output'
|
|
)
|
|
})
|
|
|
|
t.test('with filter arg nested dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec(['dog'])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output tree contaning only occurrences of filtered package and its ancestors'
|
|
)
|
|
})
|
|
|
|
t.test('with multiple filter args', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
ipsum: '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
...simpleNmFixture.node_modules,
|
|
ipsum: {
|
|
'package.json': JSON.stringify({
|
|
name: 'ipsum',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await ls.exec(['dog@*', 'chai@1.0.0'])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output tree contaning only occurrences of multiple filtered packages and their ancestors'
|
|
)
|
|
})
|
|
|
|
t.test('with missing filter arg', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec(['notadep'])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree containing no dependencies info')
|
|
t.equal(process.exitCode, 1, 'should exit with error code 1')
|
|
})
|
|
|
|
t.test('default --depth value should be 0', async t => {
|
|
const config = {
|
|
all: false,
|
|
}
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()),
|
|
'should output tree containing only top-level dependencies')
|
|
})
|
|
|
|
t.test('--depth=0', async t => {
|
|
const config = {
|
|
all: false,
|
|
depth: 0,
|
|
}
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()),
|
|
'should output tree containing only top-level dependencies')
|
|
})
|
|
|
|
t.test('--depth=1', async t => {
|
|
const config = {
|
|
all: false,
|
|
depth: 1,
|
|
}
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
e: '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
b: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
c: '^1.0.0',
|
|
d: '*',
|
|
},
|
|
}),
|
|
},
|
|
c: {
|
|
'package.json': JSON.stringify({
|
|
name: 'c',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
d: {
|
|
'package.json': JSON.stringify({
|
|
name: 'd',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
e: {
|
|
'package.json': JSON.stringify({
|
|
name: 'e',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output tree containing top-level deps and their deps only'
|
|
)
|
|
})
|
|
|
|
t.test('missing/invalid/extraneous', async t => {
|
|
t.plan(3)
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^2.0.0',
|
|
ipsum: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([]).catch(err => {
|
|
t.equal(err.code, 'ELSPROBLEMS', 'should have error code')
|
|
t.equal(
|
|
cleanCwd(err.message),
|
|
'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai\n' +
|
|
'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo\n' +
|
|
'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0',
|
|
'should log missing/invalid/extraneous errors'
|
|
)
|
|
})
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output tree containing missing, invalid, extraneous labels'
|
|
)
|
|
})
|
|
|
|
t.test('colored output', async t => {
|
|
const config = {
|
|
color: 'always',
|
|
}
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^2.0.0',
|
|
ipsum: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should have error code')
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree containing color info')
|
|
})
|
|
|
|
t.test('--dev', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
omit: ['peer', 'prod', 'optional'],
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree containing dev deps')
|
|
})
|
|
|
|
t.test('--link', async t => {
|
|
const config = {
|
|
link: true,
|
|
}
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
'linked-dep': '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
'linked-dep': {
|
|
'package.json': JSON.stringify({
|
|
name: 'linked-dep',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
node_modules: {
|
|
'linked-dep': t.fixture('symlink', '../linked-dep'),
|
|
...diffDepTypesNmFixture.node_modules,
|
|
},
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree containing linked deps')
|
|
})
|
|
|
|
t.test('print deduped symlinks', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'print-deduped-symlinks',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
b: '^1.0.0',
|
|
},
|
|
}),
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
node_modules: {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
b: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
b: t.fixture('symlink', '../b'),
|
|
},
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree containing linked deps')
|
|
})
|
|
|
|
t.test('--production', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: { omit: ['dev', 'peer'] },
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree containing production deps')
|
|
})
|
|
|
|
t.test('--long', async t => {
|
|
const config = {
|
|
long: true,
|
|
}
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree info with descriptions')
|
|
})
|
|
|
|
t.test('--long --depth=0', async t => {
|
|
const config = {
|
|
all: false,
|
|
depth: 0,
|
|
long: true,
|
|
}
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output tree containing top-level deps with descriptions'
|
|
)
|
|
})
|
|
|
|
t.test('json read problems', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': '{broken json',
|
|
},
|
|
})
|
|
await t.rejects(ls.exec([]), { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error')
|
|
t.matchSnapshot(cleanCwd(result()), 'should print empty result')
|
|
})
|
|
|
|
t.test('empty location', async t => {
|
|
const { ls, result } = await mockLs(t)
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should print empty result')
|
|
})
|
|
|
|
t.test('invalid peer dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^2.0.0', // mismatching version #
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await t.rejects(ls.exec([]))
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output tree signaling mismatching peer dep in problems'
|
|
)
|
|
})
|
|
|
|
t.test('invalid deduped dep', async t => {
|
|
const config = {
|
|
color: 'always',
|
|
}
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'invalid-deduped-dep',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
b: '^2.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
b: '^2.0.0',
|
|
},
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await t.rejects(ls.exec([]))
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output tree signaling mismatching peer dep in problems'
|
|
)
|
|
})
|
|
|
|
t.test('deduped missing dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
b: '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
b: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await t.rejects(
|
|
ls.exec([]),
|
|
{ code: 'ELSPROBLEMS', message: /missing: b@\^1.0.0/ },
|
|
'should list missing dep problem'
|
|
)
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output parseable signaling missing peer dep in problems'
|
|
)
|
|
})
|
|
|
|
t.test('unmet peer dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
peerDependencies: {
|
|
'peer-dep': '*',
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await t.rejects(
|
|
ls.exec([]),
|
|
{ code: 'ELSPROBLEMS', message: 'missing: peer-dep@*, required by test-npm-ls@1.0.0' },
|
|
'should have missing peer-dep error msg'
|
|
)
|
|
t.matchSnapshot(cleanCwd(result()),
|
|
'should output tree signaling missing peer dep in problems')
|
|
})
|
|
|
|
t.test('unmet optional dep', async t => {
|
|
const config = { color: 'always' }
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'missing-optional-dep': '^1.0.0',
|
|
'optional-dep': '^2.0.0', // mismatching version #
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await t.rejects(
|
|
ls.exec([]),
|
|
{ code: 'ELSPROBLEMS', message: /invalid: optional-dep@1.0.0/ },
|
|
'should have invalid dep error msg'
|
|
)
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output tree with empty entry for missing optional deps'
|
|
)
|
|
})
|
|
|
|
t.test('cycle deps', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
b: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref')
|
|
})
|
|
|
|
t.test('cycle deps with filter args', async t => {
|
|
const config = { color: 'always' }
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
b: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await ls.exec(['a'])
|
|
t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref')
|
|
})
|
|
|
|
t.test('with no args dedupe entries', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'dedupe-entries',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@npmcli/a': '^1.0.0',
|
|
'@npmcli/b': '^1.0.0',
|
|
'@npmcli/c': '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'@npmcli': {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: '@npmcli/a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@npmcli/b': '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: '@npmcli/b',
|
|
version: '1.1.2',
|
|
}),
|
|
},
|
|
c: {
|
|
'package.json': JSON.stringify({
|
|
name: '@npmcli/c',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@npmcli/b': '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref')
|
|
})
|
|
|
|
t.test('with no args dedupe entries and not displaying all', async t => {
|
|
const config = {
|
|
all: false,
|
|
depth: 0,
|
|
}
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'dedupe-entries',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@npmcli/a': '^1.0.0',
|
|
'@npmcli/b': '^1.0.0',
|
|
'@npmcli/c': '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'@npmcli': {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: '@npmcli/a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@npmcli/b': '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: '@npmcli/b',
|
|
version: '1.1.2',
|
|
}),
|
|
},
|
|
c: {
|
|
'package.json': JSON.stringify({
|
|
name: '@npmcli/c',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@npmcli/b': '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref')
|
|
})
|
|
|
|
t.test('with args and dedupe entries', async t => {
|
|
const config = { color: 'always' }
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'dedupe-entries',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@npmcli/a': '^1.0.0',
|
|
'@npmcli/b': '^1.0.0',
|
|
'@npmcli/c': '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'@npmcli': {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: '@npmcli/a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@npmcli/b': '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: '@npmcli/b',
|
|
version: '1.1.2',
|
|
}),
|
|
},
|
|
c: {
|
|
'package.json': JSON.stringify({
|
|
name: '@npmcli/c',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@npmcli/b': '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await ls.exec(['@npmcli/b'])
|
|
t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref')
|
|
})
|
|
|
|
t.test('with args and different order of items', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'dedupe-entries',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@npmcli/a': '^1.0.0',
|
|
'@npmcli/b': '^1.0.0',
|
|
'@npmcli/c': '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'@npmcli': {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: '@npmcli/a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@npmcli/c': '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: '@npmcli/b',
|
|
version: '1.1.2',
|
|
dependencies: {
|
|
'@npmcli/c': '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
c: {
|
|
'package.json': JSON.stringify({
|
|
name: '@npmcli/c',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await ls.exec(['@npmcli/c'])
|
|
t.matchSnapshot(cleanCwd(result()), 'should print tree output containing deduped ref')
|
|
})
|
|
|
|
t.test('using aliases', async t => {
|
|
const { npm, result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: 'npm:b@1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'.package-lock.json': JSON.stringify({
|
|
packages: {
|
|
'node_modules/a': {
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
from: 'a@npm:b',
|
|
resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz',
|
|
requested: {
|
|
type: 'alias',
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
_from: 'a@npm:b',
|
|
_resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz',
|
|
_requested: {
|
|
type: 'alias',
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
touchHiddenPackageLock(npm.prefix)
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree containing aliases')
|
|
})
|
|
|
|
t.test('resolved points to git ref', async t => {
|
|
const { npm, result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
abbrev: 'git+https://github.com/isaacs/abbrev-js.git',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'.package-lock.json': JSON.stringify({
|
|
packages: {
|
|
'node_modules/abbrev': {
|
|
name: 'abbrev',
|
|
version: '1.1.1',
|
|
from: 'git+https://github.com/isaacs/abbrev-js.git',
|
|
resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c',
|
|
},
|
|
},
|
|
}),
|
|
abbrev: {
|
|
'package.json': JSON.stringify({
|
|
name: 'abbrev',
|
|
version: '1.1.1',
|
|
_id: 'abbrev@1.1.1',
|
|
_from: 'git+https://github.com/isaacs/abbrev-js.git',
|
|
_resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c',
|
|
_requested: {
|
|
type: 'git',
|
|
raw: 'git+https:github.com/isaacs/abbrev-js.git',
|
|
rawSpec: 'git+https:github.com/isaacs/abbrev-js.git',
|
|
saveSpec: 'git+https://github.com/isaacs/abbrev-js.git',
|
|
fetchSpec: 'https://github.com/isaacs/abbrev-js.git',
|
|
gitCommittish: null,
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
touchHiddenPackageLock(npm.prefix)
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree containing git refs')
|
|
})
|
|
|
|
t.test('broken resolved field', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
node_modules: {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.1',
|
|
}),
|
|
},
|
|
},
|
|
'package-lock.json': JSON.stringify({
|
|
name: 'npm-broken-resolved-field-test',
|
|
version: '1.0.0',
|
|
lockfileVersion: 2,
|
|
requires: true,
|
|
packages: {
|
|
'': {
|
|
name: 'a',
|
|
version: '1.0.1',
|
|
},
|
|
},
|
|
dependencies: {
|
|
a: {
|
|
version: '1.0.1',
|
|
resolved: 'foo@dog://b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c',
|
|
integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==',
|
|
},
|
|
},
|
|
}),
|
|
'package.json': JSON.stringify({
|
|
name: 'npm-broken-resolved-field-test',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.1',
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should NOT print git refs in output tree')
|
|
})
|
|
|
|
t.test('from and resolved properties', async t => {
|
|
const { npm, result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'simple-output': '^2.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'.package-lock.json': JSON.stringify({
|
|
packages: {
|
|
'node_modules/simple-output': {
|
|
name: 'simple-output',
|
|
version: '2.1.1',
|
|
resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz',
|
|
shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc',
|
|
},
|
|
},
|
|
}),
|
|
'simple-output': {
|
|
'package.json': JSON.stringify({
|
|
name: 'simple-output',
|
|
version: '2.1.1',
|
|
_from: 'simple-output',
|
|
_id: 'simple-output@2.1.1',
|
|
_resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz',
|
|
_requested: {
|
|
type: 'tag',
|
|
registry: true,
|
|
raw: 'simple-output',
|
|
name: 'simple-output',
|
|
escapedName: 'simple-output',
|
|
rawSpec: '',
|
|
saveSpec: null,
|
|
fetchSpec: 'latest',
|
|
},
|
|
_requiredBy: ['#USER', '/'],
|
|
_shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc',
|
|
_spec: 'simple-output',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
touchHiddenPackageLock(npm.prefix)
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should not be printed in tree output')
|
|
})
|
|
|
|
t.test('global', async t => {
|
|
const config = {
|
|
global: true,
|
|
}
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
globalPrefixDir: {
|
|
node_modules: {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
}),
|
|
node_modules: {
|
|
c: {
|
|
'package.json': JSON.stringify({
|
|
name: 'c',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()),
|
|
'should print tree and not mark top-level items extraneous')
|
|
})
|
|
|
|
t.test('filtering by child of missing dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'filter-by-child-of-missing-dep',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
c: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
c: {
|
|
'package.json': JSON.stringify({
|
|
name: 'c',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
d: {
|
|
'package.json': JSON.stringify({
|
|
name: 'd',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
c: '^2.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
c: {
|
|
'package.json': JSON.stringify({
|
|
name: 'c',
|
|
version: '2.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
await ls.exec(['c'])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should print tree and not duplicate child of missing items'
|
|
)
|
|
})
|
|
|
|
t.test('loading a tree containing workspaces', async t => {
|
|
const mockWorkspaces = async (t, exec = [], config = {}) => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'workspaces-tree',
|
|
version: '1.0.0',
|
|
workspaces: ['./a', './b', './d', './group/*'],
|
|
dependencies: { pacote: '1.0.0' },
|
|
}),
|
|
node_modules: {
|
|
a: t.fixture('symlink', '../a'),
|
|
b: t.fixture('symlink', '../b'),
|
|
c: {
|
|
'package.json': JSON.stringify({
|
|
name: 'c',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
d: t.fixture('symlink', '../d'),
|
|
e: t.fixture('symlink', '../group/e'),
|
|
f: t.fixture('symlink', '../group/f'),
|
|
foo: {
|
|
'package.json': JSON.stringify({
|
|
name: 'foo',
|
|
version: '1.1.1',
|
|
dependencies: {
|
|
bar: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
bar: {
|
|
'package.json': JSON.stringify({ name: 'bar', version: '1.0.0' }),
|
|
},
|
|
baz: {
|
|
'package.json': JSON.stringify({ name: 'baz', version: '1.0.0' }),
|
|
},
|
|
pacote: {
|
|
'package.json': JSON.stringify({ name: 'pacote', version: '1.0.0' }),
|
|
},
|
|
},
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
c: '^1.0.0',
|
|
d: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
baz: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
d: {
|
|
'package.json': JSON.stringify({
|
|
name: 'd',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.1.1',
|
|
},
|
|
}),
|
|
},
|
|
group: {
|
|
e: {
|
|
'package.json': JSON.stringify({
|
|
name: 'e',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
f: {
|
|
'package.json': JSON.stringify({
|
|
name: 'f',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
await ls.exec(exec)
|
|
|
|
t.matchSnapshot(cleanCwd(result(), t), 'output')
|
|
}
|
|
|
|
t.test('should list workspaces properly with default configs', t => mockWorkspaces(t, [], {
|
|
depth: 0,
|
|
color: 'always',
|
|
}))
|
|
|
|
t.test('should not list workspaces with --no-workspaces', t => mockWorkspaces(t, [], {
|
|
depth: 0,
|
|
color: 'always',
|
|
workspaces: false,
|
|
}))
|
|
|
|
// --all
|
|
t.test('should list --all workspaces properly', t => mockWorkspaces(t))
|
|
|
|
// --production
|
|
t.test('should list only prod deps of workspaces', t => mockWorkspaces(t, [], {
|
|
omit: ['dev', 'peer', 'optional'],
|
|
}))
|
|
|
|
// filter out a single workspace using args
|
|
t.test('should filter single workspace', t => mockWorkspaces(t, ['d']))
|
|
|
|
// filter out a single workspace and its deps using workspaces filters
|
|
t.test('should filter using workspace config', t => mockWorkspaces(t, [], {
|
|
workspace: 'a',
|
|
}))
|
|
|
|
// filter out a single workspace and include root
|
|
t.test('should inlude root and specified workspace', t => mockWorkspaces(t, [], {
|
|
'include-workspace-root': true,
|
|
workspace: 'd',
|
|
}))
|
|
|
|
// filter out a workspace by parent path
|
|
t.test('should filter by parent folder workspace config', t => mockWorkspaces(t, [], {
|
|
workspace: './group',
|
|
}))
|
|
|
|
// filter by a dep within a workspaces sub tree
|
|
t.test('should print all tree and filter by dep within only the ws subtree', t =>
|
|
mockWorkspaces(t, ['bar'], {
|
|
workspace: 'd',
|
|
}))
|
|
})
|
|
|
|
t.test('filter pkg arg using depth option', async t => {
|
|
const mock = async (t, exec, depth = 0) => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: typeof depth === 'number' ? { depth } : {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-pkg-arg-filter-with-depth-opt',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
b: '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
c: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
c: {
|
|
'package.json': JSON.stringify({
|
|
name: 'c',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
d: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
d: {
|
|
'package.json': JSON.stringify({
|
|
name: 'd',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
await ls.exec(exec)
|
|
|
|
t.matchSnapshot(cleanCwd(result(), t), 'output')
|
|
}
|
|
|
|
t.test('should list a in top-level only', t => mock(t, ['a']))
|
|
|
|
t.test('should print empty results msg', t => mock(t, ['d']))
|
|
|
|
// if no --depth config is defined, should print path to dep
|
|
t.test('should print expected result', t => mock(t, ['d'], null))
|
|
})
|
|
})
|
|
|
|
t.test('ls --parseable', async t => {
|
|
const parseable = { parseable: true }
|
|
t.test('no args', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: parseable,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output parseable representation of dependencies structure'
|
|
)
|
|
})
|
|
|
|
t.test('missing package.json', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: parseable,
|
|
prefixDir: {
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output parseable missing name/version of top-level package'
|
|
)
|
|
})
|
|
|
|
t.test('extraneous deps', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: parseable,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output containing problems info')
|
|
})
|
|
|
|
t.test('overridden dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: { ...parseable, long: true },
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-overridden',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
},
|
|
overrides: {
|
|
bar: '1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
foo: {
|
|
'package.json': JSON.stringify({
|
|
name: 'foo',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
bar: '^2.0.0',
|
|
},
|
|
}),
|
|
},
|
|
bar: {
|
|
'package.json': JSON.stringify({
|
|
name: 'bar',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should contain overridden outout')
|
|
})
|
|
|
|
t.test('with filter arg', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: parseable,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec(['chai'])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output parseable contaning only occurrences of filtered by package'
|
|
)
|
|
})
|
|
|
|
t.test('with filter arg nested dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: parseable,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec(['dog'])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output parseable contaning only occurrences of filtered package'
|
|
)
|
|
})
|
|
|
|
t.test('with multiple filter args', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: parseable,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
ipsum: '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
...simpleNmFixture.node_modules,
|
|
ipsum: {
|
|
'package.json': JSON.stringify({
|
|
name: 'ipsum',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await ls.exec(['dog@*', 'chai@1.0.0'])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output parseable contaning only occurrences of multiple filtered packages and their ancestors'
|
|
)
|
|
})
|
|
|
|
t.test('with missing filter arg', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: parseable,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec(['notadep'])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output parseable output containing no dependencies info'
|
|
)
|
|
})
|
|
|
|
t.test('default --depth value should be 0', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: { ...parseable, all: false },
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output parseable output containing only top-level dependencies'
|
|
)
|
|
})
|
|
|
|
t.test('--depth=0', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: { ...parseable, all: false, depth: 0 },
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()),
|
|
'should output tree containing only top-level dependencies')
|
|
})
|
|
|
|
t.test('--depth=1', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: { ...parseable, all: false, depth: 1 },
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output parseable containing top-level deps and their deps only'
|
|
)
|
|
})
|
|
|
|
t.test('missing/invalid/extraneous', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: parseable,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^2.0.0',
|
|
ipsum: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems')
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output parseable containing top-level deps and their deps only'
|
|
)
|
|
})
|
|
|
|
t.test('--dev', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
omit: ['peer', 'prod', 'optional'],
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree containing dev deps')
|
|
})
|
|
|
|
t.test('--link', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
link: true,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
'linked-dep': '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
'linked-dep': {
|
|
'package.json': JSON.stringify({
|
|
name: 'linked-dep',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
node_modules: {
|
|
'linked-dep': t.fixture('symlink', '../linked-dep'),
|
|
...diffDepTypesNmFixture.node_modules,
|
|
},
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree containing linked deps')
|
|
})
|
|
|
|
t.test('--production', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
omit: ['dev', 'peer'],
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree containing production deps')
|
|
})
|
|
|
|
t.test('--long', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
long: true,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree info with descriptions')
|
|
})
|
|
|
|
t.test('--long with extraneous deps', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
long: true,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output long parseable output with extraneous info')
|
|
})
|
|
|
|
t.test('--long missing/invalid/extraneous', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
long: true,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^2.0.0',
|
|
ipsum: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems')
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output parseable result containing EXTRANEOUS/INVALID labels'
|
|
)
|
|
})
|
|
|
|
t.test('--long print symlink target location', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
long: true,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
'linked-dep': '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
'linked-dep': {
|
|
'package.json': JSON.stringify({
|
|
name: 'linked-dep',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
node_modules: {
|
|
'linked-dep': t.fixture('symlink', '../linked-dep'),
|
|
...diffDepTypesNmFixture.node_modules,
|
|
},
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output parseable results with symlink targets')
|
|
})
|
|
|
|
t.test('--long --depth=0', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
all: false,
|
|
depth: 0,
|
|
long: true,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output tree containing top-level deps with descriptions'
|
|
)
|
|
})
|
|
|
|
t.test('json read problems', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
},
|
|
prefixDir: {
|
|
'package.json': '{broken json',
|
|
},
|
|
})
|
|
await t.rejects(ls.exec([]), { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error')
|
|
t.matchSnapshot(cleanCwd(result()), 'should print empty result')
|
|
})
|
|
|
|
t.test('empty location', async t => {
|
|
const { ls, result } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should print empty result')
|
|
})
|
|
|
|
t.test('unmet peer dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^2.0.0', // mismatching version #
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await t.rejects(ls.exec([]))
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output parseable signaling missing peer dep in problems'
|
|
)
|
|
})
|
|
|
|
t.test('unmet optional dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'missing-optional-dep': '^1.0.0',
|
|
'optional-dep': '^2.0.0', // mismatching version #
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await t.rejects(
|
|
ls.exec([]),
|
|
{ code: 'ELSPROBLEMS', message: /invalid: optional-dep@1.0.0/ },
|
|
'should have invalid dep error msg'
|
|
)
|
|
t.matchSnapshot(
|
|
cleanCwd(result()),
|
|
'should output parseable with empty entry for missing optional deps'
|
|
)
|
|
})
|
|
|
|
t.test('cycle deps', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
b: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should print tree output omitting deduped ref')
|
|
})
|
|
|
|
t.test('using aliases', async t => {
|
|
const { npm, result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: 'npm:b@1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'.package-lock.json': JSON.stringify({
|
|
packages: {
|
|
'node_modules/a': {
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz',
|
|
},
|
|
},
|
|
}),
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
_from: 'a@npm:b',
|
|
_resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz',
|
|
_requested: {
|
|
type: 'alias',
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
touchHiddenPackageLock(npm.prefix)
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree containing aliases')
|
|
})
|
|
|
|
t.test('resolved points to git ref', async t => {
|
|
const { npm, result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
abbrev: 'git+https://github.com/isaacs/abbrev-js.git',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'.package-lock.json': JSON.stringify({
|
|
packages: {
|
|
'node_modules/abbrev': {
|
|
name: 'abbrev',
|
|
version: '1.1.1',
|
|
resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c',
|
|
},
|
|
},
|
|
}),
|
|
abbrev: {
|
|
'package.json': JSON.stringify({
|
|
name: 'abbrev',
|
|
version: '1.1.1',
|
|
_id: 'abbrev@1.1.1',
|
|
_from: 'git+https://github.com/isaacs/abbrev-js.git',
|
|
_resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c',
|
|
_requested: {
|
|
type: 'git',
|
|
raw: 'git+https:github.com/isaacs/abbrev-js.git',
|
|
rawSpec: 'git+https:github.com/isaacs/abbrev-js.git',
|
|
saveSpec: 'git+https://github.com/isaacs/abbrev-js.git',
|
|
fetchSpec: 'https://github.com/isaacs/abbrev-js.git',
|
|
gitCommittish: null,
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
touchHiddenPackageLock(npm.prefix)
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should output tree containing git refs')
|
|
})
|
|
|
|
t.test('from and resolved properties', async t => {
|
|
const { npm, result, ls } = await mockLs(t, {
|
|
config: {
|
|
...parseable,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'simple-output': '^2.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'.package-lock.json': JSON.stringify({
|
|
packages: {
|
|
'node_modules/simple-output': {
|
|
name: 'simple-output',
|
|
version: '2.1.1',
|
|
resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz',
|
|
shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc',
|
|
},
|
|
},
|
|
}),
|
|
'simple-output': {
|
|
'package.json': JSON.stringify({
|
|
name: 'simple-output',
|
|
version: '2.1.1',
|
|
_from: 'simple-output',
|
|
_id: 'simple-output@2.1.1',
|
|
_resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz',
|
|
_requested: {
|
|
type: 'tag',
|
|
registry: true,
|
|
raw: 'simple-output',
|
|
name: 'simple-output',
|
|
escapedName: 'simple-output',
|
|
rawSpec: '',
|
|
saveSpec: null,
|
|
fetchSpec: 'latest',
|
|
},
|
|
_requiredBy: ['#USER', '/'],
|
|
_shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc',
|
|
_spec: 'simple-output',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
touchHiddenPackageLock(npm.prefix)
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should not be printed in tree output')
|
|
})
|
|
|
|
t.test('global', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: { ...parseable, global: true },
|
|
globalPrefixDir: {
|
|
node_modules: {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
}),
|
|
node_modules: {
|
|
c: {
|
|
'package.json': JSON.stringify({
|
|
name: 'c',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
await ls.exec([])
|
|
t.matchSnapshot(cleanCwd(result()), 'should print parseable output for global deps')
|
|
})
|
|
})
|
|
|
|
t.test('ignore missing optional deps', async t => {
|
|
const mock = async (t, config = {}) => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: config,
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls-ignore-missing-optional',
|
|
version: '1.2.3',
|
|
peerDependencies: {
|
|
'peer-ok': '1',
|
|
'peer-missing': '1',
|
|
'peer-wrong': '1',
|
|
'peer-optional-ok': '1',
|
|
'peer-optional-missing': '1',
|
|
'peer-optional-wrong': '1',
|
|
},
|
|
peerDependenciesMeta: {
|
|
'peer-optional-ok': {
|
|
optional: true,
|
|
},
|
|
'peer-optional-missing': {
|
|
optional: true,
|
|
},
|
|
'peer-optional-wrong': {
|
|
optional: true,
|
|
},
|
|
},
|
|
optionalDependencies: {
|
|
'optional-ok': '1',
|
|
'optional-missing': '1',
|
|
'optional-wrong': '1',
|
|
},
|
|
dependencies: {
|
|
'prod-ok': '1',
|
|
'prod-missing': '1',
|
|
'prod-wrong': '1',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'prod-ok': {
|
|
'package.json': JSON.stringify({ name: 'prod-ok', version: '1.2.3' }),
|
|
},
|
|
'prod-wrong': {
|
|
'package.json': JSON.stringify({ name: 'prod-wrong', version: '3.2.1' }),
|
|
},
|
|
'optional-ok': {
|
|
'package.json': JSON.stringify({ name: 'optional-ok', version: '1.2.3' }),
|
|
},
|
|
'optional-wrong': {
|
|
'package.json': JSON.stringify({ name: 'optional-wrong', version: '3.2.1' }),
|
|
},
|
|
'peer-optional-ok': {
|
|
'package.json': JSON.stringify({ name: 'peer-optional-ok', version: '1.2.3' }),
|
|
},
|
|
'peer-optional-wrong': {
|
|
'package.json': JSON.stringify({ name: 'peer-optional-wrong', version: '3.2.1' }),
|
|
},
|
|
'peer-ok': {
|
|
'package.json': JSON.stringify({ name: 'peer-ok', version: '1.2.3' }),
|
|
},
|
|
'peer-wrong': {
|
|
'package.json': JSON.stringify({ name: 'peer-wrong', version: '3.2.1' }),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' })
|
|
|
|
return config.json ? jsonParse(result()).problems : cleanCwd(result())
|
|
}
|
|
|
|
t.test('--json', async t => {
|
|
const result = await mock(t, { json: true })
|
|
t.matchSnapshot(result, 'ls --json problems')
|
|
})
|
|
|
|
t.test('--parseable', async t => {
|
|
const result = await mock(t, { parseable: true })
|
|
t.matchSnapshot(result, 'ls --parseable result')
|
|
})
|
|
|
|
t.test('human output', async t => {
|
|
const result = await mock(t)
|
|
t.matchSnapshot(result, 'ls result')
|
|
})
|
|
})
|
|
|
|
t.test('ls --json', async t => {
|
|
const json = { json: true }
|
|
t.test('no args', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json representation of dependencies structure'
|
|
)
|
|
})
|
|
|
|
t.test('missing package.json', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
problems: [
|
|
'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai',
|
|
'extraneous: dog@1.0.0 {CWD}/prefix/node_modules/dog',
|
|
'extraneous: foo@1.0.0 {CWD}/prefix/node_modules/foo',
|
|
],
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
extraneous: true,
|
|
overridden: false,
|
|
problems: [
|
|
'extraneous: dog@1.0.0 {CWD}/prefix/node_modules/dog',
|
|
],
|
|
},
|
|
foo: {
|
|
version: '1.0.0',
|
|
extraneous: true,
|
|
overridden: false,
|
|
problems: [
|
|
'extraneous: foo@1.0.0 {CWD}/prefix/node_modules/foo',
|
|
],
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
extraneous: true,
|
|
overridden: false,
|
|
problems: [
|
|
'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai',
|
|
],
|
|
},
|
|
},
|
|
},
|
|
'should output json missing name/version of top-level package'
|
|
)
|
|
})
|
|
|
|
t.test('extraneous deps', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
problems: [
|
|
'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai',
|
|
],
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
extraneous: true,
|
|
overridden: false,
|
|
problems: [
|
|
'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai',
|
|
],
|
|
},
|
|
},
|
|
},
|
|
'should output json containing problems info'
|
|
)
|
|
})
|
|
|
|
t.test('overridden dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-overridden',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
},
|
|
overrides: {
|
|
bar: '1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
foo: {
|
|
'package.json': JSON.stringify({
|
|
name: 'foo',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
bar: '^2.0.0',
|
|
},
|
|
}),
|
|
},
|
|
bar: {
|
|
'package.json': JSON.stringify({
|
|
name: 'bar',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
await ls.exec([])
|
|
t.same(JSON.parse(result()), {
|
|
name: 'test-overridden',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
bar: {
|
|
version: '1.0.0',
|
|
overridden: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
})
|
|
|
|
t.test('missing deps --long', async t => {
|
|
t.plan(3)
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
long: true,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
dog: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
ipsum: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
|
|
await ls.exec([]).catch(err => {
|
|
t.equal(
|
|
cleanCwd(err.message),
|
|
'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0',
|
|
'should log missing dep as error'
|
|
)
|
|
t.equal(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code')
|
|
})
|
|
t.match(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
problems: ['missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0'],
|
|
},
|
|
'should output json containing problems info'
|
|
)
|
|
})
|
|
|
|
t.test('with filter arg', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec(['chai'])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json contaning only occurrences of filtered by package'
|
|
)
|
|
t.not(process.exitCode, 1, 'should not exit with error code 1')
|
|
})
|
|
|
|
t.test('with filter arg nested dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec(['dog'])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'should output json contaning only occurrences of filtered by package'
|
|
)
|
|
t.notOk(jsonParse(result()).dependencies.chai)
|
|
})
|
|
|
|
t.test('with multiple filter args', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
ipsum: '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
...simpleNmFixture.node_modules,
|
|
ipsum: {
|
|
'package.json': JSON.stringify({
|
|
name: 'ipsum',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await ls.exec(['dog@*', 'chai@1.0.0'])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
version: '1.0.0',
|
|
name: 'test-npm-ls',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json contaning only occurrences of multiple filtered packages and their ancestors'
|
|
)
|
|
})
|
|
|
|
t.test('with missing filter arg', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec(['notadep'])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
},
|
|
'should output json containing no dependencies info'
|
|
)
|
|
t.equal(process.exitCode, 1, 'should exit with error code 1')
|
|
})
|
|
|
|
t.test('default --depth value should now be 0', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
all: false,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json containing only top-level dependencies'
|
|
)
|
|
})
|
|
|
|
t.test('--depth=0', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
all: false,
|
|
depth: 0,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json containing only top-level dependencies'
|
|
)
|
|
})
|
|
|
|
t.test('--depth=1', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
all: false,
|
|
depth: 1,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json containing top-level deps and their deps only'
|
|
)
|
|
})
|
|
|
|
t.test('missing/invalid/extraneous', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^2.0.0',
|
|
ipsum: '^1.0.0',
|
|
},
|
|
}),
|
|
...simpleNmFixture,
|
|
},
|
|
})
|
|
await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems')
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
problems: [
|
|
'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai',
|
|
'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo',
|
|
'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0',
|
|
],
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
invalid: '"^2.0.0" from the root project',
|
|
overridden: false,
|
|
problems: [
|
|
'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo',
|
|
],
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
extraneous: true,
|
|
overridden: false,
|
|
problems: [
|
|
'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai',
|
|
],
|
|
},
|
|
ipsum: {
|
|
required: '^1.0.0',
|
|
missing: true,
|
|
problems: ['missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0'],
|
|
},
|
|
},
|
|
error: {
|
|
code: 'ELSPROBLEMS',
|
|
summary: [
|
|
'extraneous: chai@1.0.0 {CWD}/prefix/node_modules/chai',
|
|
'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo',
|
|
'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0',
|
|
].join('\n'),
|
|
detail: '',
|
|
},
|
|
},
|
|
'should output json containing top-level deps and their deps only'
|
|
)
|
|
})
|
|
|
|
t.test('--dev', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
omit: ['prod', 'optional', 'peer'],
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'dev-dep': {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'should output json containing dev deps'
|
|
)
|
|
})
|
|
|
|
t.test('--link', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
link: true,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
'linked-dep': '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
'linked-dep': {
|
|
'package.json': JSON.stringify({
|
|
name: 'linked-dep',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
node_modules: {
|
|
'linked-dep': t.fixture('symlink', '../linked-dep'),
|
|
...diffDepTypesNmFixture.node_modules,
|
|
},
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'linked-dep': {
|
|
version: '1.0.0',
|
|
resolved: 'file:../linked-dep',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json containing linked deps'
|
|
)
|
|
})
|
|
|
|
t.test('--production', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
omit: ['dev', 'peer'],
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
'optional-dep': {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
'prod-dep': {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '2.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'should output json containing production deps'
|
|
)
|
|
})
|
|
|
|
t.test('from lockfile', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
node_modules: {
|
|
'@isaacs': {
|
|
'dedupe-tests-a': {
|
|
'package.json': JSON.stringify({
|
|
name: '@isaacs/dedupe-tests-a',
|
|
version: '1.0.1',
|
|
}),
|
|
node_modules: {
|
|
'@isaacs': {
|
|
'dedupe-tests-b': {
|
|
name: '@isaacs/dedupe-tests-b',
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'dedupe-tests-b': {
|
|
'package.json': JSON.stringify({
|
|
name: '@isaacs/dedupe-tests-b',
|
|
version: '2.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
'package-lock.json': JSON.stringify({
|
|
name: 'dedupe-lockfile',
|
|
version: '1.0.0',
|
|
lockfileVersion: 2,
|
|
requires: true,
|
|
packages: {
|
|
'': {
|
|
name: 'dedupe-lockfile',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-a': '1.0.1',
|
|
'@isaacs/dedupe-tests-b': '1||2',
|
|
},
|
|
},
|
|
'node_modules/@isaacs/dedupe-tests-a': {
|
|
name: '@isaacs/dedupe-tests-a',
|
|
version: '1.0.1',
|
|
resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz',
|
|
integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==',
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-b': '1',
|
|
},
|
|
},
|
|
'node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b': {
|
|
name: '@isaacs/dedupe-tests-b',
|
|
version: '1.0.0',
|
|
resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz',
|
|
integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==',
|
|
},
|
|
'node_modules/@isaacs/dedupe-tests-b': {
|
|
name: '@isaacs/dedupe-tests-b',
|
|
version: '2.0.0',
|
|
resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz',
|
|
integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==',
|
|
},
|
|
},
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-a': {
|
|
version: '1.0.1',
|
|
resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz',
|
|
integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==',
|
|
requires: {
|
|
'@isaacs/dedupe-tests-b': '1',
|
|
},
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-b': {
|
|
version: '1.0.0',
|
|
resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz',
|
|
integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==',
|
|
},
|
|
},
|
|
},
|
|
'@isaacs/dedupe-tests-b': {
|
|
version: '2.0.0',
|
|
resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz',
|
|
integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==',
|
|
},
|
|
},
|
|
}),
|
|
'package.json': JSON.stringify({
|
|
name: 'dedupe-lockfile',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-a': '1.0.1',
|
|
'@isaacs/dedupe-tests-b': '1||2',
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
version: '1.0.0',
|
|
name: 'dedupe-lockfile',
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-a': {
|
|
version: '1.0.1',
|
|
overridden: false,
|
|
resolved:
|
|
'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz',
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-b': {
|
|
resolved:
|
|
'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz',
|
|
extraneous: true,
|
|
overridden: false,
|
|
problems: [
|
|
'extraneous: @isaacs/dedupe-tests-b@ {CWD}/prefix/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b',
|
|
],
|
|
},
|
|
},
|
|
},
|
|
'@isaacs/dedupe-tests-b': {
|
|
version: '2.0.0',
|
|
overridden: false,
|
|
resolved:
|
|
'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz',
|
|
},
|
|
},
|
|
problems: [
|
|
'extraneous: @isaacs/dedupe-tests-b@ {CWD}/prefix/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b',
|
|
],
|
|
},
|
|
'should output json containing only prod deps'
|
|
)
|
|
})
|
|
|
|
t.test('--long', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
long: true,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'peer-dep': {
|
|
name: 'peer-dep',
|
|
overridden: false,
|
|
description: 'Peer-dep description here',
|
|
version: '1.0.0',
|
|
_id: 'peer-dep@1.0.0',
|
|
devDependencies: {},
|
|
peerDependencies: {},
|
|
_dependencies: {},
|
|
path: '{CWD}/prefix/node_modules/peer-dep',
|
|
extraneous: false,
|
|
},
|
|
'dev-dep': {
|
|
name: 'dev-dep',
|
|
overridden: false,
|
|
description: 'A DEV dep kind of dep',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: {
|
|
name: 'foo',
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
name: 'dog',
|
|
overridden: false,
|
|
version: '1.0.0',
|
|
_id: 'dog@1.0.0',
|
|
devDependencies: {},
|
|
peerDependencies: {},
|
|
_dependencies: {},
|
|
path: '{CWD}/prefix/node_modules/dog',
|
|
extraneous: false,
|
|
},
|
|
},
|
|
_id: 'foo@1.0.0',
|
|
devDependencies: {},
|
|
peerDependencies: {},
|
|
_dependencies: { dog: '^1.0.0' },
|
|
path: '{CWD}/prefix/node_modules/foo',
|
|
extraneous: false,
|
|
},
|
|
},
|
|
_id: 'dev-dep@1.0.0',
|
|
devDependencies: {},
|
|
peerDependencies: {},
|
|
_dependencies: { foo: '^1.0.0' },
|
|
path: '{CWD}/prefix/node_modules/dev-dep',
|
|
extraneous: false,
|
|
},
|
|
chai: {
|
|
name: 'chai',
|
|
overridden: false,
|
|
version: '1.0.0',
|
|
_id: 'chai@1.0.0',
|
|
devDependencies: {},
|
|
peerDependencies: {},
|
|
_dependencies: {},
|
|
path: '{CWD}/prefix/node_modules/chai',
|
|
extraneous: false,
|
|
},
|
|
'optional-dep': {
|
|
name: 'optional-dep',
|
|
overridden: false,
|
|
description: 'Maybe a dep?',
|
|
version: '1.0.0',
|
|
_id: 'optional-dep@1.0.0',
|
|
devDependencies: {},
|
|
peerDependencies: {},
|
|
_dependencies: {},
|
|
path: '{CWD}/prefix/node_modules/optional-dep',
|
|
extraneous: false,
|
|
},
|
|
'prod-dep': {
|
|
name: 'prod-dep',
|
|
overridden: false,
|
|
description: 'A PROD dep kind of dep',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
dog: {
|
|
name: 'dog',
|
|
overridden: false,
|
|
description: 'A dep that bars',
|
|
version: '2.0.0',
|
|
_id: 'dog@2.0.0',
|
|
devDependencies: {},
|
|
peerDependencies: {},
|
|
_dependencies: {},
|
|
path: '{CWD}/prefix/node_modules/prod-dep/node_modules/dog',
|
|
extraneous: false,
|
|
},
|
|
},
|
|
_id: 'prod-dep@1.0.0',
|
|
devDependencies: {},
|
|
peerDependencies: {},
|
|
_dependencies: { dog: '^2.0.0' },
|
|
path: '{CWD}/prefix/node_modules/prod-dep',
|
|
extraneous: false,
|
|
},
|
|
},
|
|
devDependencies: { 'dev-dep': '^1.0.0' },
|
|
optionalDependencies: { 'optional-dep': '^1.0.0' },
|
|
peerDependencies: { 'peer-dep': '^1.0.0' },
|
|
_id: 'test-npm-ls@1.0.0',
|
|
_dependencies: { 'prod-dep': '^1.0.0', chai: '^1.0.0', 'optional-dep': '^1.0.0' },
|
|
path: '{CWD}/prefix',
|
|
extraneous: false,
|
|
},
|
|
'should output long json info'
|
|
)
|
|
})
|
|
|
|
t.test('--long --depth=0', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
all: false,
|
|
depth: 0,
|
|
long: true,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'peer-dep': {
|
|
name: 'peer-dep',
|
|
overridden: false,
|
|
description: 'Peer-dep description here',
|
|
version: '1.0.0',
|
|
_id: 'peer-dep@1.0.0',
|
|
devDependencies: {},
|
|
peerDependencies: {},
|
|
_dependencies: {},
|
|
path: '{CWD}/prefix/node_modules/peer-dep',
|
|
extraneous: false,
|
|
},
|
|
'dev-dep': {
|
|
name: 'dev-dep',
|
|
overridden: false,
|
|
description: 'A DEV dep kind of dep',
|
|
version: '1.0.0',
|
|
_id: 'dev-dep@1.0.0',
|
|
devDependencies: {},
|
|
peerDependencies: {},
|
|
_dependencies: { foo: '^1.0.0' },
|
|
path: '{CWD}/prefix/node_modules/dev-dep',
|
|
extraneous: false,
|
|
},
|
|
chai: {
|
|
name: 'chai',
|
|
overridden: false,
|
|
version: '1.0.0',
|
|
_id: 'chai@1.0.0',
|
|
devDependencies: {},
|
|
peerDependencies: {},
|
|
_dependencies: {},
|
|
path: '{CWD}/prefix/node_modules/chai',
|
|
extraneous: false,
|
|
},
|
|
'optional-dep': {
|
|
name: 'optional-dep',
|
|
overridden: false,
|
|
description: 'Maybe a dep?',
|
|
version: '1.0.0',
|
|
_id: 'optional-dep@1.0.0',
|
|
devDependencies: {},
|
|
peerDependencies: {},
|
|
_dependencies: {},
|
|
path: '{CWD}/prefix/node_modules/optional-dep',
|
|
extraneous: false,
|
|
},
|
|
'prod-dep': {
|
|
name: 'prod-dep',
|
|
overridden: false,
|
|
description: 'A PROD dep kind of dep',
|
|
version: '1.0.0',
|
|
_id: 'prod-dep@1.0.0',
|
|
devDependencies: {},
|
|
peerDependencies: {},
|
|
_dependencies: { dog: '^2.0.0' },
|
|
path: '{CWD}/prefix/node_modules/prod-dep',
|
|
extraneous: false,
|
|
},
|
|
},
|
|
devDependencies: { 'dev-dep': '^1.0.0' },
|
|
optionalDependencies: { 'optional-dep': '^1.0.0' },
|
|
peerDependencies: { 'peer-dep': '^1.0.0' },
|
|
_id: 'test-npm-ls@1.0.0',
|
|
_dependencies: { 'prod-dep': '^1.0.0', chai: '^1.0.0', 'optional-dep': '^1.0.0' },
|
|
path: '{CWD}/prefix',
|
|
extraneous: false,
|
|
},
|
|
'should output json containing top-level deps in long format'
|
|
)
|
|
})
|
|
|
|
t.test('json read problems', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': '{broken json',
|
|
},
|
|
})
|
|
await t.rejects(
|
|
ls.exec([]),
|
|
{ code: 'EJSONPARSE', message: 'Failed to parse root package.json' },
|
|
'should have missin root package.json msg'
|
|
)
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
invalid: true,
|
|
problems: [
|
|
'error in {CWD}/prefix: Failed to parse root package.json',
|
|
],
|
|
error: {
|
|
code: 'EJSONPARSE',
|
|
summary: 'Failed to parse root package.json',
|
|
detail: [
|
|
'Failed to parse JSON data.',
|
|
'Note: package.json must be actual JSON, not just JavaScript.',
|
|
].join('\n'),
|
|
},
|
|
},
|
|
'should print empty json result'
|
|
)
|
|
})
|
|
|
|
t.test('empty location', async t => {
|
|
const { ls, result } = await mockLs(t, { config: json })
|
|
await ls.exec([])
|
|
t.same(jsonParse(result()), {}, 'should print empty json result')
|
|
})
|
|
|
|
t.test('unmet peer dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'optional-dep': '^1.0.0',
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^2.0.0', // mismatching version #
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'Should have ELSPROBLEMS error code')
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
problems: [
|
|
'invalid: peer-dep@1.0.0 {CWD}/prefix/node_modules/peer-dep',
|
|
],
|
|
dependencies: {
|
|
'peer-dep': {
|
|
version: '1.0.0',
|
|
invalid: '"^2.0.0" from the root project',
|
|
overridden: false,
|
|
problems: [
|
|
'invalid: peer-dep@1.0.0 {CWD}/prefix/node_modules/peer-dep',
|
|
],
|
|
},
|
|
'dev-dep': {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
'optional-dep': {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
'prod-dep': {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '2.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
error: {
|
|
code: 'ELSPROBLEMS',
|
|
summary: 'invalid: peer-dep@1.0.0 {CWD}/prefix/node_modules/peer-dep',
|
|
detail: '',
|
|
},
|
|
},
|
|
'should output json signaling missing peer dep in problems'
|
|
)
|
|
})
|
|
|
|
t.test('unmet optional dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'prod-dep': '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
devDependencies: {
|
|
'dev-dep': '^1.0.0',
|
|
},
|
|
optionalDependencies: {
|
|
'missing-optional-dep': '^1.0.0',
|
|
'optional-dep': '^2.0.0', // mismatching version #
|
|
},
|
|
peerDependencies: {
|
|
'peer-dep': '^1.0.0',
|
|
},
|
|
}),
|
|
...diffDepTypesNmFixture,
|
|
},
|
|
})
|
|
await t.rejects(
|
|
ls.exec([]),
|
|
{ code: 'ELSPROBLEMS', message: /invalid: optional-dep@1.0.0/ },
|
|
'should have invalid dep error msg'
|
|
)
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
problems: [
|
|
// mismatching optional deps get flagged in problems
|
|
'invalid: optional-dep@1.0.0 {CWD}/prefix/node_modules/optional-dep',
|
|
],
|
|
dependencies: {
|
|
'optional-dep': {
|
|
version: '1.0.0',
|
|
invalid: '"^2.0.0" from the root project',
|
|
overridden: false,
|
|
problems: [
|
|
'invalid: optional-dep@1.0.0 {CWD}/prefix/node_modules/optional-dep',
|
|
],
|
|
},
|
|
'peer-dep': {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
'dev-dep': {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
'prod-dep': {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '2.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'missing-optional-dep': {}, // missing optional dep has an empty entry in json output
|
|
},
|
|
error: {
|
|
code: 'ELSPROBLEMS',
|
|
summary: 'invalid: optional-dep@1.0.0 {CWD}/prefix/node_modules/optional-dep',
|
|
detail: '',
|
|
},
|
|
},
|
|
'should output json with empty entry for missing optional deps'
|
|
)
|
|
})
|
|
|
|
t.test('cycle deps', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
b: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: '^1.0.0',
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
b: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
a: {
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'should print json output containing deduped ref'
|
|
)
|
|
})
|
|
|
|
t.test('using aliases', async t => {
|
|
const { npm, result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: 'npm:b@1.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'.package-lock.json': JSON.stringify({
|
|
packages: {
|
|
'node_modules/a': {
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
from: 'a@npm:b',
|
|
resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz',
|
|
requested: {
|
|
type: 'alias',
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
touchHiddenPackageLock(npm.prefix)
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz',
|
|
},
|
|
},
|
|
},
|
|
'should output json containing aliases'
|
|
)
|
|
})
|
|
|
|
t.test('resolved points to git ref', async t => {
|
|
const { npm, result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
abbrev: 'git+https://github.com/isaacs/abbrev-js.git',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'.package-lock.json': JSON.stringify({
|
|
packages: {
|
|
'node_modules/abbrev': {
|
|
name: 'abbrev',
|
|
version: '1.1.1',
|
|
id: 'abbrev@1.1.1',
|
|
from: 'git+https://github.com/isaacs/abbrev-js.git',
|
|
resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c',
|
|
},
|
|
},
|
|
}),
|
|
abbrev: {
|
|
'package.json': JSON.stringify({
|
|
name: 'abbrev',
|
|
version: '1.1.1',
|
|
_id: 'abbrev@1.1.1',
|
|
_from: 'git+https://github.com/isaacs/abbrev-js.git',
|
|
_resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c',
|
|
_requested: {
|
|
type: 'git',
|
|
raw: 'git+https:github.com/isaacs/abbrev-js.git',
|
|
rawSpec: 'git+https:github.com/isaacs/abbrev-js.git',
|
|
saveSpec: 'git+https://github.com/isaacs/abbrev-js.git',
|
|
fetchSpec: 'https://github.com/isaacs/abbrev-js.git',
|
|
gitCommittish: null,
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
touchHiddenPackageLock(npm.prefix)
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
abbrev: {
|
|
version: '1.1.1',
|
|
overridden: false,
|
|
resolved: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c',
|
|
},
|
|
},
|
|
},
|
|
'should output json containing git refs'
|
|
)
|
|
})
|
|
|
|
t.test('from and resolved properties', async t => {
|
|
const { npm, result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'simple-output': '^2.0.0',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
'.package-lock.json': JSON.stringify({
|
|
packages: {
|
|
'node_modules/simple-output': {
|
|
name: 'simple-output',
|
|
version: '2.1.1',
|
|
_from: 'simple-output',
|
|
_id: 'simple-output@2.1.1',
|
|
_resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz',
|
|
_requested: {
|
|
type: 'tag',
|
|
registry: true,
|
|
raw: 'simple-output',
|
|
name: 'simple-output',
|
|
escapedName: 'simple-output',
|
|
rawSpec: '',
|
|
saveSpec: null,
|
|
fetchSpec: 'latest',
|
|
},
|
|
_requiredBy: ['#USER', '/'],
|
|
_shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc',
|
|
_spec: 'simple-output',
|
|
},
|
|
},
|
|
}),
|
|
'simple-output': {
|
|
'package.json': JSON.stringify({
|
|
name: 'simple-output',
|
|
version: '2.1.1',
|
|
_from: 'simple-output',
|
|
_id: 'simple-output@2.1.1',
|
|
_resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz',
|
|
_requested: {
|
|
type: 'tag',
|
|
registry: true,
|
|
raw: 'simple-output',
|
|
name: 'simple-output',
|
|
escapedName: 'simple-output',
|
|
rawSpec: '',
|
|
saveSpec: null,
|
|
fetchSpec: 'latest',
|
|
},
|
|
_requiredBy: ['#USER', '/'],
|
|
_shasum: '3c07708ec9ef3e3c985cf0ddd67df09ab8ec2abc',
|
|
_spec: 'simple-output',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
touchHiddenPackageLock(npm.prefix)
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'simple-output': {
|
|
version: '2.1.1',
|
|
overridden: false,
|
|
resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz',
|
|
},
|
|
},
|
|
},
|
|
'should be printed in json output'
|
|
)
|
|
})
|
|
|
|
t.test('node.name fallback if missing root package name', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
version: '1.0.0',
|
|
name: 'prefix',
|
|
},
|
|
'should use node.name as key in json result obj'
|
|
)
|
|
})
|
|
|
|
t.test('global', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...json,
|
|
global: true,
|
|
},
|
|
globalPrefixDir: {
|
|
node_modules: {
|
|
a: {
|
|
'package.json': JSON.stringify({
|
|
name: 'a',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
b: {
|
|
'package.json': JSON.stringify({
|
|
name: 'b',
|
|
version: '1.0.0',
|
|
}),
|
|
node_modules: {
|
|
c: {
|
|
'package.json': JSON.stringify({
|
|
name: 'c',
|
|
version: '1.0.0',
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: process.platform === 'win32' ? 'global' : 'lib',
|
|
dependencies: {
|
|
a: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
b: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
c: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'should print json output for global deps'
|
|
)
|
|
})
|
|
})
|
|
|
|
t.test('show multiple invalid reasons', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
cat: '^2.0.0',
|
|
dog: '^1.2.3',
|
|
},
|
|
}),
|
|
node_modules: {
|
|
cat: {
|
|
'package.json': JSON.stringify({
|
|
name: 'cat',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
dog: '^2.0.0',
|
|
},
|
|
}),
|
|
},
|
|
dog: {
|
|
'package.json': JSON.stringify({
|
|
name: 'dog',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
cat: '',
|
|
},
|
|
}),
|
|
},
|
|
chai: {
|
|
'package.json': JSON.stringify({
|
|
name: 'chai',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
dog: '2.x',
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems')
|
|
t.matchSnapshot(cleanCwd(result()), 'ls result')
|
|
})
|
|
|
|
t.test('ls --package-lock-only', async t => {
|
|
const lock = { 'package-lock-only': true }
|
|
|
|
t.test('ls --package-lock-only --json', async t => {
|
|
const json = { json: true }
|
|
|
|
t.test('no args', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
'package-lock.json': JSON.stringify({
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
requires: {
|
|
dog: '^1.0.0',
|
|
},
|
|
},
|
|
dog: {
|
|
version: '1.0.0',
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json representation of dependencies structure'
|
|
)
|
|
})
|
|
|
|
t.test('extraneous deps', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
},
|
|
}),
|
|
'package-lock.json': JSON.stringify({
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
requires: {
|
|
dog: '^1.0.0',
|
|
},
|
|
},
|
|
dog: {
|
|
version: '1.0.0',
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'should output json containing no problem info'
|
|
)
|
|
})
|
|
|
|
t.test('missing deps --long', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
long: true,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
dog: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
ipsum: '^1.0.0',
|
|
},
|
|
}),
|
|
'package-lock.json': JSON.stringify({
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
requires: {
|
|
dog: '^1.0.0',
|
|
},
|
|
},
|
|
dog: {
|
|
version: '1.0.0',
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
},
|
|
ipsum: {
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.match(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
},
|
|
'should output json containing no problems info'
|
|
)
|
|
})
|
|
|
|
t.test('with filter arg', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
'package-lock.json': JSON.stringify({
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
requires: {
|
|
dog: '^1.0.0',
|
|
},
|
|
},
|
|
dog: {
|
|
version: '1.0.0',
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
},
|
|
ipsum: {
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec(['chai'])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json contaning only occurrences of filtered by package'
|
|
)
|
|
t.notOk(process.exitCode, 'should not set exit code')
|
|
})
|
|
|
|
t.test('with filter arg nested dep', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
'package-lock.json': JSON.stringify({
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
requires: {
|
|
dog: '^1.0.0',
|
|
},
|
|
},
|
|
dog: {
|
|
version: '1.0.0',
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
},
|
|
ipsum: {
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec(['dog'])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'should output json contaning only occurrences of filtered by package'
|
|
)
|
|
})
|
|
|
|
t.test('with multiple filter args', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
ipsum: '^1.0.0',
|
|
},
|
|
}),
|
|
'package-lock.json': JSON.stringify({
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
requires: {
|
|
dog: '^1.0.0',
|
|
},
|
|
},
|
|
dog: {
|
|
version: '1.0.0',
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
},
|
|
ipsum: {
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec(['dog@*', 'chai@1.0.0'])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
version: '1.0.0',
|
|
name: 'test-npm-ls',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json contaning only occurrences of multiple filtered packages and their ancestors'
|
|
)
|
|
})
|
|
|
|
t.test('with missing filter arg', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
'package-lock.json': JSON.stringify({
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
requires: {
|
|
dog: '^1.0.0',
|
|
},
|
|
},
|
|
dog: {
|
|
version: '1.0.0',
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec(['notadep'])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
},
|
|
'should output json containing no dependencies info'
|
|
)
|
|
t.equal(process.exitCode, 1, 'should exit with error code 1')
|
|
})
|
|
|
|
t.test('default --depth value should now be 0', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
all: false,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
'package-lock.json': JSON.stringify({
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
requires: {
|
|
dog: '^1.0.0',
|
|
},
|
|
},
|
|
dog: {
|
|
version: '1.0.0',
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json containing only top-level dependencies'
|
|
)
|
|
})
|
|
|
|
t.test('--depth=0', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
depth: 0,
|
|
all: false,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
'package-lock.json': JSON.stringify({
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
requires: {
|
|
dog: '^1.0.0',
|
|
},
|
|
},
|
|
dog: {
|
|
version: '1.0.0',
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json containing only top-level dependencies'
|
|
)
|
|
})
|
|
|
|
t.test('--depth=1', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
all: false,
|
|
depth: 1,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^1.0.0',
|
|
chai: '^1.0.0',
|
|
},
|
|
}),
|
|
'package-lock.json': JSON.stringify({
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
requires: {
|
|
dog: '^1.0.0',
|
|
},
|
|
},
|
|
dog: {
|
|
version: '1.0.0',
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json containing top-level deps and their deps only'
|
|
)
|
|
})
|
|
|
|
t.test('missing/invalid/extraneous', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
foo: '^2.0.0',
|
|
ipsum: '^1.0.0',
|
|
},
|
|
}),
|
|
'package-lock.json': JSON.stringify({
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
requires: {
|
|
dog: '^1.0.0',
|
|
},
|
|
},
|
|
dog: {
|
|
version: '1.0.0',
|
|
},
|
|
chai: {
|
|
version: '1.0.0',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await t.rejects(ls.exec([]), { code: 'ELSPROBLEMS' }, 'should list dep problems')
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
problems: [
|
|
'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo',
|
|
'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0',
|
|
],
|
|
dependencies: {
|
|
foo: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
invalid: '"^2.0.0" from the root project',
|
|
problems: [
|
|
'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo',
|
|
],
|
|
dependencies: {
|
|
dog: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
ipsum: {
|
|
required: '^1.0.0',
|
|
missing: true,
|
|
problems: ['missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0'],
|
|
},
|
|
},
|
|
error: {
|
|
code: 'ELSPROBLEMS',
|
|
summary: [
|
|
'invalid: foo@1.0.0 {CWD}/prefix/node_modules/foo',
|
|
'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0',
|
|
].join('\n'),
|
|
detail: '',
|
|
},
|
|
},
|
|
'should output json containing top-level deps and their deps only'
|
|
)
|
|
})
|
|
|
|
t.test('from lockfile', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package-lock.json': JSON.stringify({
|
|
name: 'dedupe-lockfile',
|
|
version: '1.0.0',
|
|
lockfileVersion: 2,
|
|
requires: true,
|
|
packages: {
|
|
'': {
|
|
name: 'dedupe-lockfile',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-a': '1.0.1',
|
|
'@isaacs/dedupe-tests-b': '1||2',
|
|
},
|
|
},
|
|
'node_modules/@isaacs/dedupe-tests-a': {
|
|
name: '@isaacs/dedupe-tests-a',
|
|
version: '1.0.1',
|
|
resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz',
|
|
integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==',
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-b': '1',
|
|
},
|
|
},
|
|
'node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b': {
|
|
name: '@isaacs/dedupe-tests-b',
|
|
version: '1.0.0',
|
|
resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz',
|
|
integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==',
|
|
},
|
|
'node_modules/@isaacs/dedupe-tests-b': {
|
|
name: '@isaacs/dedupe-tests-b',
|
|
version: '2.0.0',
|
|
resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz',
|
|
integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==',
|
|
},
|
|
},
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-a': {
|
|
version: '1.0.1',
|
|
resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz',
|
|
integrity: 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==',
|
|
requires: {
|
|
'@isaacs/dedupe-tests-b': '1',
|
|
},
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-b': {
|
|
version: '1.0.0',
|
|
resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz',
|
|
integrity: 'sha512-3nmvzIb8QL8OXODzipwoV3U8h9OQD9g9RwOPuSBQqjqSg9JZR1CCFOWNsDUtOfmwY8HFUJV9EAZ124uhqVxq+w==',
|
|
},
|
|
},
|
|
},
|
|
'@isaacs/dedupe-tests-b': {
|
|
version: '2.0.0',
|
|
resolved: 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz',
|
|
integrity: 'sha512-KTYkpRv9EzlmCg4Gsm/jpclWmRYFCXow8GZKJXjK08sIZBlElTZEa5Bw/UQxIvEfcKmWXczSqItD49Kr8Ax4UA==',
|
|
},
|
|
},
|
|
}),
|
|
'package.json': JSON.stringify({
|
|
name: 'dedupe-lockfile',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-a': '1.0.1',
|
|
'@isaacs/dedupe-tests-b': '1||2',
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
version: '1.0.0',
|
|
name: 'dedupe-lockfile',
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-a': {
|
|
version: '1.0.1',
|
|
overridden: false,
|
|
resolved:
|
|
'https://registry.npmjs.org/@isaacs/dedupe-tests-a/-/dedupe-tests-a-1.0.1.tgz',
|
|
dependencies: {
|
|
'@isaacs/dedupe-tests-b': {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
resolved:
|
|
'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz',
|
|
},
|
|
},
|
|
},
|
|
'@isaacs/dedupe-tests-b': {
|
|
version: '2.0.0',
|
|
overridden: false,
|
|
resolved:
|
|
'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz',
|
|
},
|
|
},
|
|
},
|
|
'should output json containing only prod deps'
|
|
)
|
|
})
|
|
|
|
t.test('using aliases', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: 'npm:b@1.0.0',
|
|
},
|
|
}),
|
|
'package-lock.json': JSON.stringify({
|
|
dependencies: {
|
|
a: {
|
|
version: 'npm:b@1.0.0',
|
|
resolved: 'https://localhost:8080/abbrev/-/abbrev-1.0.0.tgz',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
a: {
|
|
version: '1.0.0',
|
|
overridden: false,
|
|
resolved: 'https://localhost:8080/abbrev/-/abbrev-1.0.0.tgz',
|
|
},
|
|
},
|
|
},
|
|
'should output json containing aliases'
|
|
)
|
|
})
|
|
|
|
t.test('resolved points to git ref', async t => {
|
|
const { result, ls } = await mockLs(t, {
|
|
config: {
|
|
...lock,
|
|
...json,
|
|
long: false,
|
|
},
|
|
prefixDir: {
|
|
'package.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
abbrev: 'git+https://github.com/isaacs/abbrev-js.git',
|
|
},
|
|
}),
|
|
'package-lock.json': JSON.stringify({
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
lockfileVersion: 2,
|
|
requires: true,
|
|
dependencies: {
|
|
abbrev: {
|
|
version: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c',
|
|
from: 'abbrev@git+https://github.com/isaacs/abbrev-js.git',
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
await ls.exec([])
|
|
t.same(
|
|
jsonParse(result()),
|
|
{
|
|
name: 'test-npm-ls',
|
|
version: '1.0.0',
|
|
dependencies: {
|
|
abbrev: {
|
|
resolved: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c',
|
|
overridden: false,
|
|
},
|
|
},
|
|
},
|
|
'should output json containing git refs'
|
|
)
|
|
})
|
|
})
|
|
})
|