diff options
author | Ruy Adorno <ruyadorno@hotmail.com> | 2020-07-15 22:38:23 +0300 |
---|---|---|
committer | Ruy Adorno <ruyadorno@hotmail.com> | 2020-07-21 06:03:34 +0300 |
commit | 433c5e5822d13251a5a26e7252707d34f55702fd (patch) | |
tree | 3ae8a1f50cbfce0e20b4443e5a7df0b9bed3a31f /test/lib/ls.js | |
parent | 7fbd867f6bae059a24ad6c80989ad8cf1fa5be72 (diff) |
BREAKING: rewrite npm ls
- Rewrites lib/ls.js command to use @npmcli/arborist
- Updates unit tests
- Breaking changes:
- added error codes: ELSPROBLEMS, EJSONPARSE to callback errors
- extraneous deps depth will match current location in nm folder
- mark top-level deps as extraneous when missing root package.json
- don't mark deps as extraneous if they're valid deps of invalid deps
- peer deps are now listed as regular deps, removed oddities such as
peerinvalid label and stops labeling peer deps extraneous
- might print diff git resolved values,
see: https://github.com/npm/hosted-git-info
- Parseable (--parseable) output:
- possible order of printed elements changed
- fixed consistency problems in which it would print root folder
name if using a filter argument that could not match against
any of the deps in the current installed tree
- fixed printing non-existing paths for missing dependencies
- fixed undefined symlink output when using --long output
- JSON (--json) output:
- removed: `from` property from --json output
- removed: "[Circular]" references
- added "missing" to list of peer-dep problems listed
- added peerDependencies ref when using --long output
- removed readme properties using --long output
- Renamed error msg:
`Failed to parse json` -> `Failed to parse root package.json`
refs:
- https://github.com/npm/statusboard/issues/99
- https://github.com/npm/statusboard/issues/103
Diffstat (limited to 'test/lib/ls.js')
-rw-r--r-- | test/lib/ls.js | 801 |
1 files changed, 664 insertions, 137 deletions
diff --git a/test/lib/ls.js b/test/lib/ls.js index ae9aabaee..db19c33e9 100644 --- a/test/lib/ls.js +++ b/test/lib/ls.js @@ -78,7 +78,10 @@ const diffDepTypesNmFixture = { let prefix let result = '' +// note this _flatOptions representations is for tests-only and does not +// represent exactly the properties found in the actual flatOptions obj const _flatOptions = { + color: false, dev: false, depth: Infinity, json: false, @@ -93,7 +96,7 @@ const ls = requireInject('../../lib/ls.js', { limit: { fetch: 3 }, - get dir () { return prefix + '/node_modules/' }, + get prefix () { return prefix }, globalDir: '/foo', config: { get (key) { @@ -105,12 +108,18 @@ const ls = requireInject('../../lib/ls.js', { }) const redactCwd = res => - res.replace(/\\/g, '/').replace(new RegExp(__dirname.replace(/\\/g, '/'), 'gi'), '{CWD}') + res && res.replace(/\\/g, '/').replace(new RegExp(__dirname.replace(/\\/g, '/'), 'gi'), '{CWD}') const jsonParse = res => JSON.parse(redactCwd(res)) +const cleanUpResult = (done, t) => { + result = '' + done() +} + test('ls', (t) => { + t.beforeEach(cleanUpResult) _flatOptions.json = false _flatOptions.unicode = false t.test('no args', (t) => { @@ -137,8 +146,12 @@ test('ls', (t) => { ...simpleNmFixture }) ls([], (err) => { - t.ifError(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output json missing name/version of top-level package') + t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') + t.matchSnapshot( + redactCwd(err.message), + 'should log all extraneous deps on error msg' + ) + t.matchSnapshot(redactCwd(result), 'should output tree missing name/version of top-level package') t.end() }) }) @@ -155,8 +168,9 @@ test('ls', (t) => { ...simpleNmFixture }) ls([], (err) => { + t.equal(err.code, 'ELSPROBLEMS', 'should have error code') t.equal( - redactCwd(err), + redactCwd(err.message), 'extraneous: lorem@1.0.0 {CWD}/ls-ls-extraneous-deps/node_modules/lorem', 'should log extraneous dep as error' ) @@ -184,6 +198,53 @@ test('ls', (t) => { }) }) + t.test('with filter arg nested dep', (t) => { + prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + lorem: '^1.0.0' + } + }), + ...simpleNmFixture + }) + ls(['bar'], (err) => { + t.ifError(err, 'npm ls') + t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurences of filtered package and its ancestors') + t.end() + }) + }) + + t.test('with multiple filter args', (t) => { + prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + lorem: '^1.0.0', + ipsum: '^1.0.0' + } + }), + node_modules: { + ...simpleNmFixture.node_modules, + ipsum: { + 'package.json': JSON.stringify({ + name: 'ipsum', + version: '1.0.0' + }) + } + } + }) + ls(['bar@*', 'lorem@1.0.0'], (err) => { + t.ifError(err, 'npm ls') + t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurences of multiple filtered packages and their ancestors') + t.end() + }) + }) + t.test('with missing filter arg', (t) => { prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -237,11 +298,49 @@ test('ls', (t) => { name: 'test-npm-ls', version: '1.0.0', dependencies: { - foo: '^1.0.0', - lorem: '^1.0.0' + a: '^1.0.0', + e: '^1.0.0' } }), - ...simpleNmFixture + 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' + }) + } + } }) ls([], (err) => { t.ifError(err, 'npm ls') @@ -264,13 +363,42 @@ test('ls', (t) => { }), ...simpleNmFixture }) - ls([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps and their deps only') + ls([], (err) => { + t.equal(err.code, 'ELSPROBLEMS', 'should have error code') + t.equal( + redactCwd(err.message), + 'invalid: foo@1.0.0 {CWD}/ls-ls-missing-invalid-extraneous/node_modules/foo\n' + + 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0\n' + + 'extraneous: lorem@1.0.0 {CWD}/ls-ls-missing-invalid-extraneous/node_modules/lorem', + 'should log missing/invalid/extraneous errors' + ) + t.matchSnapshot(redactCwd(result), 'should output tree containing missing, invalid, extraneous labels') _flatOptions.depth = Infinity t.end() }) }) + t.test('coloured output', (t) => { + _flatOptions.color = true + prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^2.0.0', + ipsum: '^1.0.0' + } + }), + ...simpleNmFixture + }) + ls([], (err) => { + t.equal(err.code, 'ELSPROBLEMS', 'should have error code') + t.matchSnapshot(redactCwd(result), 'should output tree containing color info') + _flatOptions.color = false + t.end() + }) + }) + t.test('--dev', (t) => { _flatOptions.dev = true prefix = t.testdir({ @@ -491,7 +619,7 @@ test('ls', (t) => { 'package.json': '{broken json' }) ls([], (err) => { - t.match(err, /Failed to parse json/) + t.match(err, { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error') t.matchSnapshot(redactCwd(result), 'should print empty result') t.end() }) @@ -506,7 +634,7 @@ test('ls', (t) => { }) }) - t.test('unmet peer dep', (t) => { + t.test('invalid peer dep', (t) => { prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -528,12 +656,31 @@ test('ls', (t) => { ...diffDepTypesNmFixture }) ls([], () => { + t.matchSnapshot(redactCwd(result), 'should output tree signaling mismatching peer dep in problems') + t.end() + }) + }) + + t.test('unmet peer dep', (t) => { + prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + peerDependencies: { + 'peer-dep': '*' + } + }) + }) + ls([], (err) => { + t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') + t.match(err.message, 'missing: peer-dep@*, required by test-npm-ls@1.0.0', 'should have missing peer-dep error msg') t.matchSnapshot(redactCwd(result), 'should output tree signaling missing peer dep in problems') t.end() }) }) t.test('unmet optional dep', (t) => { + _flatOptions.color = true prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -555,8 +702,11 @@ test('ls', (t) => { }), ...diffDepTypesNmFixture }) - ls([], () => { + ls([], (err) => { + t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') + t.match(err.message, /invalid: optional-dep@1.0.0/, 'should have invalid dep error msg') t.matchSnapshot(redactCwd(result), 'should output tree with empty entry for missing optional deps') + _flatOptions.color = false t.end() }) }) @@ -591,7 +741,8 @@ test('ls', (t) => { } } }) - ls([], () => { + ls([], (err) => { + t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should print tree output containing deduped ref') t.end() }) @@ -655,12 +806,57 @@ test('ls', (t) => { } } }) - ls([], () => { + ls([], (err) => { + t.ifError(err, 'npm ls') t.matchSnapshot(redactCwd(result), 'should output tree containing git refs') t.end() }) }) + t.test('broken resolved field', (t) => { + prefix = t.testdir({ + 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@bar://b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c', + 'integrity': 'sha512-8AN9lNCcBt5Xeje7fMEEpp5K3rgcAzIpTtAjYb/YMUYu8SbIVF6wz0WqACDVKvpQOUcSfNHZQNLNmue0QSwXOQ==' + } + } + }), + 'package.json': JSON.stringify({ + 'name': 'npm-broken-resolved-field-test', + 'version': '1.0.0', + 'dependencies': { + 'a': '^1.0.1' + } + }) + }) + ls([], (err) => { + t.ifError(err, 'npm ls') + t.matchSnapshot(redactCwd(result), 'should NOT print git refs in output tree') + t.end() + }) + }) + t.test('from and resolved properties', (t) => { prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -708,6 +904,7 @@ test('ls', (t) => { }) test('ls --parseable', (t) => { + t.beforeEach(cleanUpResult) _flatOptions.json = false _flatOptions.unicode = false _flatOptions.parseable = true @@ -725,7 +922,7 @@ test('ls --parseable', (t) => { }) ls([], (err) => { t.ifError(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output tree representation of dependencies structure') + t.matchSnapshot(redactCwd(result), 'should output parseable representation of dependencies structure') t.end() }) }) @@ -735,8 +932,12 @@ test('ls --parseable', (t) => { ...simpleNmFixture }) ls([], (err) => { - t.ifError(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output json missing name/version of top-level package') + t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') + t.matchSnapshot( + redactCwd(err.message), + 'should log all extraneous deps on error msg' + ) + t.matchSnapshot(redactCwd(result), 'should output parseable missing name/version of top-level package') t.end() }) }) @@ -753,11 +954,7 @@ test('ls --parseable', (t) => { ...simpleNmFixture }) ls([], (err) => { - t.equal( - redactCwd(err), - 'extraneous: lorem@1.0.0 {CWD}/ls-ls-parseable-extraneous-deps/node_modules/lorem', - 'should log extraneous dep as error' - ) + t.equal(err.code, 'ELSPROBLEMS', 'should have error code') t.matchSnapshot(redactCwd(result), 'should output containing problems info') t.end() }) @@ -777,7 +974,54 @@ test('ls --parseable', (t) => { }) ls(['lorem'], (err) => { t.ifError(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output tree contaning only occurences of filtered by package') + t.matchSnapshot(redactCwd(result), 'should output parseable contaning only occurences of filtered by package') + t.end() + }) + }) + + t.test('with filter arg nested dep', (t) => { + prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + lorem: '^1.0.0' + } + }), + ...simpleNmFixture + }) + ls(['bar'], (err) => { + t.ifError(err, 'npm ls') + t.matchSnapshot(redactCwd(result), 'should output parseable contaning only occurences of filtered package') + t.end() + }) + }) + + t.test('with multiple filter args', (t) => { + prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + lorem: '^1.0.0', + ipsum: '^1.0.0' + } + }), + node_modules: { + ...simpleNmFixture.node_modules, + ipsum: { + 'package.json': JSON.stringify({ + name: 'ipsum', + version: '1.0.0' + }) + } + } + }) + ls(['bar@*', 'lorem@1.0.0'], (err) => { + t.ifError(err, 'npm ls') + t.matchSnapshot(redactCwd(result), 'should output parseable contaning only occurences of multiple filtered packages and their ancestors') t.end() }) }) @@ -843,14 +1087,13 @@ test('ls --parseable', (t) => { }) ls([], (err) => { t.ifError(err, 'npm ls') - t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps and their deps only') + t.matchSnapshot(redactCwd(result), 'should output parseable containing top-level deps and their deps only') _flatOptions.depth = Infinity t.end() }) }) t.test('missing/invalid/extraneous', (t) => { - _flatOptions.depth = 1 prefix = t.testdir({ 'package.json': JSON.stringify({ name: 'test-npm-ls', @@ -862,9 +1105,9 @@ test('ls --parseable', (t) => { }), ...simpleNmFixture }) - ls([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree containing top-level deps and their deps only') - _flatOptions.depth = Infinity + ls([], (err) => { + t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems') + t.matchSnapshot(redactCwd(result), 'should output parseable containing top-level deps and their deps only') t.end() }) }) @@ -1053,6 +1296,86 @@ test('ls --parseable', (t) => { }) }) + t.test('--long with extraneous deps', (t) => { + prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0' + } + }), + ...simpleNmFixture + }) + ls([], (err) => { + t.equal(err.code, 'ELSPROBLEMS', 'should have error code') + t.match(err.message, 'extraneous: lorem@1.0.0 /Users/ruyadorno/Documents/workspace/cli/test/lib/ls-ls-parseable--long-with-extraneous-deps/node_modules/lorem', 'should have error code') + t.matchSnapshot(redactCwd(result), 'should output long parseable output with extraneous info') + t.end() + }) + }) + + t.test('--long missing/invalid/extraneous', (t) => { + _flatOptions.long = true + prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^2.0.0', + ipsum: '^1.0.0' + } + }), + ...simpleNmFixture + }) + ls([], (err) => { + t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems') + t.matchSnapshot(redactCwd(result), 'should output parseable result containing EXTRANEOUS/INVALID labels') + _flatOptions.long = false + t.end() + }) + }) + + t.test('--long print symlink target location', (t) => { + _flatOptions.long = true + prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + 'prod-dep': '^1.0.0', + 'lorem': '^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 + } + }) + ls([], (err) => { + t.ifError(err, 'npm ls') + t.matchSnapshot(redactCwd(result), 'should output parseable results with symlink targets') + _flatOptions.long = false + t.end() + }) + }) + t.test('--long --depth=0', (t) => { _flatOptions.depth = 0 _flatOptions.long = true @@ -1089,7 +1412,7 @@ test('ls --parseable', (t) => { 'package.json': '{broken json' }) ls([], (err) => { - t.match(err, /Failed to parse json/) + t.match(err, { code: 'EJSONPARSE' }, 'should throw EJSONPARSE error') t.matchSnapshot(redactCwd(result), 'should print empty result') t.end() }) @@ -1126,7 +1449,7 @@ test('ls --parseable', (t) => { ...diffDepTypesNmFixture }) ls([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree signaling missing peer dep in problems') + t.matchSnapshot(redactCwd(result), 'should output parseable signaling missing peer dep in problems') t.end() }) }) @@ -1153,8 +1476,10 @@ test('ls --parseable', (t) => { }), ...diffDepTypesNmFixture }) - ls([], () => { - t.matchSnapshot(redactCwd(result), 'should output tree with empty entry for missing optional deps') + ls([], (err) => { + t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') + t.match(err.message, /invalid: optional-dep@1.0.0/, 'should have invalid dep error msg') + t.matchSnapshot(redactCwd(result), 'should output parseable with empty entry for missing optional deps') t.end() }) }) @@ -1306,6 +1631,7 @@ test('ls --parseable', (t) => { }) test('ls --json', (t) => { + t.beforeEach(cleanUpResult) _flatOptions.json = true _flatOptions.parseable = false t.test('no args', (t) => { @@ -1352,13 +1678,29 @@ test('ls --json', (t) => { ...simpleNmFixture }) ls([], (err) => { - t.ifError(err, 'npm ls') + t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems') t.deepEqual( jsonParse(result), { + 'problems': [ + 'extraneous: bar@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/bar', + 'extraneous: foo@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/foo', + 'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/lorem' + ], 'dependencies': { + 'bar': { + 'version': '1.0.0', + 'extraneous': true, + 'problems': [ + 'extraneous: bar@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/bar' + ] + }, 'foo': { 'version': '1.0.0', + 'extraneous': true, + 'problems': [ + 'extraneous: foo@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/foo' + ], 'dependencies': { 'bar': { 'version': '1.0.0' @@ -1366,7 +1708,11 @@ test('ls --json', (t) => { } }, 'lorem': { - 'version': '1.0.0' + 'version': '1.0.0', + 'extraneous': true, + 'problems': [ + 'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-missing-package-json/node_modules/lorem' + ] } } }, @@ -1389,10 +1735,15 @@ test('ls --json', (t) => { }) ls([], (err) => { t.equal( - redactCwd(err), + redactCwd(err.message), 'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-extraneous-deps/node_modules/lorem', 'should log extraneous dep as error' ) + t.equal( + err.code, + 'ELSPROBLEMS', + 'should have ELSPROBLEMS error code' + ) t.deepEqual( jsonParse(result), { @@ -1456,6 +1807,90 @@ test('ls --json', (t) => { }) }) + t.test('with filter arg nested dep', (t) => { + prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + lorem: '^1.0.0' + } + }), + ...simpleNmFixture + }) + ls(['bar'], (err) => { + t.ifError(err, 'npm ls') + t.deepEqual( + jsonParse(result), + { + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: { + version: '1.0.0', + dependencies: { + bar: { + version: '1.0.0' + } + } + } + } + }, + 'should output json contaning only occurences of filtered by package' + ) + t.end() + }) + }) + + t.test('with multiple filter args', (t) => { + prefix = t.testdir({ + 'package.json': JSON.stringify({ + name: 'test-npm-ls', + version: '1.0.0', + dependencies: { + foo: '^1.0.0', + lorem: '^1.0.0', + ipsum: '^1.0.0' + } + }), + node_modules: { + ...simpleNmFixture.node_modules, + ipsum: { + 'package.json': JSON.stringify({ + name: 'ipsum', + version: '1.0.0' + }) + } + } + }) + ls(['bar@*', 'lorem@1.0.0'], (err) => { + t.ifError(err, 'npm ls') + t.deepEqual( + jsonParse(result), + { + 'version': '1.0.0', + 'name': 'test-npm-ls', + 'dependencies': { + 'foo': { + 'version': '1.0.0', + 'dependencies': { + 'bar': { + 'version': '1.0.0' + } + } + }, + 'lorem': { + 'version': '1.0.0' + } + } + }, + 'should output json contaning only occurences of multiple filtered packages and their ancestors' + ) + t.end() + }) + }) + t.test('with missing filter arg', (t) => { prefix = t.testdir({ 'package.json': JSON.stringify({ @@ -1578,16 +2013,16 @@ test('ls --json', (t) => { }), ...simpleNmFixture }) - ls([], () => { + ls([], (err) => { + t.match(err, { code: 'ELSPROBLEMS' }, 'should list dep problems') t.deepEqual( jsonParse(result), { 'name': 'test-npm-ls', 'version': '1.0.0', 'problems': [ - 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', 'invalid: foo@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/foo', - 'extraneous: bar@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/bar', + 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0', 'extraneous: lorem@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/lorem' ], 'dependencies': { @@ -1595,16 +2030,11 @@ test('ls --json', (t) => { 'version': '1.0.0', 'invalid': true, 'problems': [ - 'invalid: foo@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/foo', - 'extraneous: bar@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/bar' + 'invalid: foo@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/foo' ], 'dependencies': { 'bar': { - 'version': '1.0.0', - 'extraneous': true, - 'problems': [ - 'extraneous: bar@1.0.0 {CWD}/ls-ls-json-missing-invalid-extraneous/node_modules/bar' - ] + 'version': '1.0.0' } } }, @@ -1617,7 +2047,10 @@ test('ls --json', (t) => { }, 'ipsum': { 'required': '^1.0.0', - 'missing': true + 'missing': true, + 'problems': [ + 'missing: ipsum@^1.0.0, required by test-npm-ls@1.0.0' + ] } } }, @@ -1761,7 +2194,10 @@ test('ls --json', (t) => { name: 'test-npm-ls', version: '1.0.0', dependencies: { - 'linked-dep': { version: '1.0.0' } + 'linked-dep': { + version: '1.0.0', + resolved: 'file:../linked-dep' + } } }, 'should output json containing linked deps' @@ -1853,6 +2289,135 @@ test('ls --json', (t) => { }) }) + t.test('from lockfile', (t) => { + prefix = t.testdir({ + 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' + } + }) + }) + ls([], () => { + t.deepEqual( + jsonParse(result), + { + 'version': '1.0.0', + 'name': 'dedupe-lockfile', + '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', + 'dependencies': { + '@isaacs/dedupe-tests-b': { + 'resolved': 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-1.0.0.tgz', + 'extraneous': true, + 'problems': [ + 'extraneous: @isaacs/dedupe-tests-b@ {CWD}/ls-ls-json-from-lockfile/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b' + ] + } + } + }, + '@isaacs/dedupe-tests-b': { + 'version': '2.0.0', + 'resolved': 'https://registry.npmjs.org/@isaacs/dedupe-tests-b/-/dedupe-tests-b-2.0.0.tgz' + } + }, + 'problems': [ + 'extraneous: @isaacs/dedupe-tests-b@ {CWD}/ls-ls-json-from-lockfile/node_modules/@isaacs/dedupe-tests-a/node_modules/@isaacs/dedupe-tests-b' + ] + }, + 'should output json containing only prod deps' + ) + t.end() + }) + }) + t.test('--long', (t) => { _flatOptions.long = true prefix = t.testdir({ @@ -1886,15 +2451,12 @@ test('ls --json', (t) => { name: 'peer-dep', description: 'Peer-dep description here', version: '1.0.0', - readme: 'ERROR: No README data found!', _id: 'peer-dep@1.0.0', - dependencies: {}, devDependencies: {}, - optionalDependencies: {}, + peerDependencies: {}, _dependencies: {}, path: '{CWD}/ls-ls-json--long/node_modules/peer-dep', - error: null, - extraneous: true + extraneous: false }, 'dev-dep': { name: 'dev-dep', @@ -1908,61 +2470,48 @@ test('ls --json', (t) => { bar: { name: 'bar', version: '1.0.0', - readme: 'ERROR: No README data found!', _id: 'bar@1.0.0', - dependencies: {}, devDependencies: {}, - optionalDependencies: {}, + peerDependencies: {}, _dependencies: {}, path: '{CWD}/ls-ls-json--long/node_modules/bar', - error: '[Circular]', extraneous: false } }, - readme: 'ERROR: No README data found!', _id: 'foo@1.0.0', devDependencies: {}, - optionalDependencies: {}, + peerDependencies: {}, _dependencies: { bar: '^1.0.0' }, path: '{CWD}/ls-ls-json--long/node_modules/foo', - error: '[Circular]', extraneous: false } }, - readme: 'ERROR: No README data found!', _id: 'dev-dep@1.0.0', devDependencies: {}, - optionalDependencies: {}, + peerDependencies: {}, _dependencies: { foo: '^1.0.0' }, path: '{CWD}/ls-ls-json--long/node_modules/dev-dep', - error: '[Circular]', extraneous: false }, lorem: { name: 'lorem', version: '1.0.0', - readme: 'ERROR: No README data found!', _id: 'lorem@1.0.0', - dependencies: {}, devDependencies: {}, - optionalDependencies: {}, + peerDependencies: {}, _dependencies: {}, path: '{CWD}/ls-ls-json--long/node_modules/lorem', - error: '[Circular]', extraneous: false }, 'optional-dep': { name: 'optional-dep', description: 'Maybe a dep?', version: '1.0.0', - readme: 'ERROR: No README data found!', _id: 'optional-dep@1.0.0', - dependencies: {}, devDependencies: {}, - optionalDependencies: {}, + peerDependencies: {}, _dependencies: {}, path: '{CWD}/ls-ls-json--long/node_modules/optional-dep', - error: '[Circular]', extraneous: false }, 'prod-dep': { @@ -1974,36 +2523,28 @@ test('ls --json', (t) => { name: 'bar', description: 'A dep that bars', version: '2.0.0', - readme: 'ERROR: No README data found!', _id: 'bar@2.0.0', - dependencies: {}, devDependencies: {}, - optionalDependencies: {}, + peerDependencies: {}, _dependencies: {}, path: '{CWD}/ls-ls-json--long/node_modules/prod-dep/node_modules/bar', - error: '[Circular]', extraneous: false } }, - readme: 'ERROR: No README data found!', _id: 'prod-dep@1.0.0', devDependencies: {}, - optionalDependencies: {}, + peerDependencies: {}, _dependencies: { bar: '^2.0.0' }, path: '{CWD}/ls-ls-json--long/node_modules/prod-dep', - error: '[Circular]', extraneous: false } }, devDependencies: { 'dev-dep': '^1.0.0' }, optionalDependencies: { 'optional-dep': '^1.0.0' }, peerDependencies: { 'peer-dep': '^1.0.0' }, - readme: 'ERROR: No README data found!', _id: 'test-npm-ls@1.0.0', - _shrinkwrap: '[Circular]', _dependencies: { 'prod-dep': '^1.0.0', lorem: '^1.0.0', 'optional-dep': '^1.0.0' }, path: '{CWD}/ls-ls-json--long', - error: '[Circular]', extraneous: false }, 'should output long json info' @@ -2047,76 +2588,63 @@ test('ls --json', (t) => { name: 'peer-dep', description: 'Peer-dep description here', version: '1.0.0', - readme: 'ERROR: No README data found!', _id: 'peer-dep@1.0.0', devDependencies: {}, - optionalDependencies: {}, + peerDependencies: {}, _dependencies: {}, path: '{CWD}/ls-ls-json--long-depth-0/node_modules/peer-dep', - error: null, - extraneous: true + extraneous: false }, 'dev-dep': { name: 'dev-dep', description: 'A DEV dep kind of dep', version: '1.0.0', - readme: 'ERROR: No README data found!', _id: 'dev-dep@1.0.0', devDependencies: {}, - optionalDependencies: {}, + peerDependencies: {}, _dependencies: { foo: '^1.0.0' }, path: '{CWD}/ls-ls-json--long-depth-0/node_modules/dev-dep', - error: '[Circular]', extraneous: false }, lorem: { name: 'lorem', version: '1.0.0', - readme: 'ERROR: No README data found!', _id: 'lorem@1.0.0', devDependencies: {}, - optionalDependencies: {}, + peerDependencies: {}, _dependencies: {}, path: '{CWD}/ls-ls-json--long-depth-0/node_modules/lorem', - error: '[Circular]', extraneous: false }, 'optional-dep': { name: 'optional-dep', description: 'Maybe a dep?', version: '1.0.0', - readme: 'ERROR: No README data found!', _id: 'optional-dep@1.0.0', devDependencies: {}, - optionalDependencies: {}, + peerDependencies: {}, _dependencies: {}, path: '{CWD}/ls-ls-json--long-depth-0/node_modules/optional-dep', - error: '[Circular]', extraneous: false }, 'prod-dep': { name: 'prod-dep', description: 'A PROD dep kind of dep', version: '1.0.0', - readme: 'ERROR: No README data found!', _id: 'prod-dep@1.0.0', devDependencies: {}, - optionalDependencies: {}, + peerDependencies: {}, _dependencies: { bar: '^2.0.0' }, path: '{CWD}/ls-ls-json--long-depth-0/node_modules/prod-dep', - error: '[Circular]', extraneous: false } }, devDependencies: { 'dev-dep': '^1.0.0' }, optionalDependencies: { 'optional-dep': '^1.0.0' }, peerDependencies: { 'peer-dep': '^1.0.0' }, - readme: 'ERROR: No README data found!', _id: 'test-npm-ls@1.0.0', - _shrinkwrap: '[Circular]', _dependencies: { 'prod-dep': '^1.0.0', lorem: '^1.0.0', 'optional-dep': '^1.0.0' }, path: '{CWD}/ls-ls-json--long-depth-0', - error: '[Circular]', extraneous: false }, 'should output json containing top-level deps in long format' @@ -2132,13 +2660,14 @@ test('ls --json', (t) => { 'package.json': '{broken json' }) ls([], (err) => { - t.match(err, /Failed to parse json/) + t.match(err.message, 'Failed to parse root package.json', 'should have missin root package.json msg') + t.match(err.code, 'EJSONPARSE', 'should have EJSONPARSE error code') t.deepEqual( jsonParse(result), { invalid: true, problems: [ - "error in {CWD}/ls-ls-json-json-read-problems: Failed to parse json/nUnexpected token b in JSON at position 1 while parsing near '{broken json'" + 'error in {CWD}/ls-ls-json-json-read-problems: Failed to parse root package.json' ] }, 'should print empty json result' @@ -2181,38 +2710,23 @@ test('ls --json', (t) => { }), ...diffDepTypesNmFixture }) - ls([], () => { + ls([], (err) => { + t.match(err.code, 'ELSPROBLEMS', 'Should have ELSPROBLEMS error code') t.deepEqual( jsonParse(result), { name: 'test-npm-ls', version: '1.0.0', problems: [ - 'peer dep missing: peer-dep@^2.0.0, required by test-npm-ls@1.0.0' + 'invalid: peer-dep@1.0.0 {CWD}/ls-ls-json-unmet-peer-dep/node_modules/peer-dep' ], dependencies: { 'peer-dep': { - required: { - name: 'peer-dep', - description: 'Peer-dep description here', - version: '1.0.0', - readme: 'ERROR: No README data found!', - _id: 'peer-dep@1.0.0', - dependencies: {}, - devDependencies: {}, - optionalDependencies: {}, - _dependencies: {}, - path: '{CWD}/ls-ls-json-unmet-peer-dep/node_modules/peer-dep', - error: null, - extraneous: true, - peerMissing: [ - { - requiredBy: 'test-npm-ls@1.0.0', - requires: 'peer-dep@^2.0.0' - } - ] - }, - peerMissing: true + version: '1.0.0', + invalid: true, + problems: [ + 'invalid: peer-dep@1.0.0 {CWD}/ls-ls-json-unmet-peer-dep/node_modules/peer-dep' + ] }, 'dev-dep': { version: '1.0.0', @@ -2256,15 +2770,16 @@ test('ls --json', (t) => { }), ...diffDepTypesNmFixture }) - ls([], () => { + ls([], (err) => { + t.match(err.code, 'ELSPROBLEMS', 'should have ELSPROBLEMS error code') + t.match(err.message, /invalid: optional-dep@1.0.0/, 'should have invalid dep error msg') t.deepEqual( jsonParse(result), { name: 'test-npm-ls', version: '1.0.0', problems: [ - 'invalid: optional-dep@1.0.0 {CWD}/ls-ls-json-unmet-optional-dep/node_modules/optional-dep', // mismatching optional deps get flagged in problems - 'extraneous: peer-dep@1.0.0 {CWD}/ls-ls-json-unmet-optional-dep/node_modules/peer-dep' + 'invalid: optional-dep@1.0.0 {CWD}/ls-ls-json-unmet-optional-dep/node_modules/optional-dep' // mismatching optional deps get flagged in problems ], dependencies: { 'optional-dep': { @@ -2275,11 +2790,7 @@ test('ls --json', (t) => { ] }, 'peer-dep': { - version: '1.0.0', - extraneous: true, - problems: [ - 'extraneous: peer-dep@1.0.0 {CWD}/ls-ls-json-unmet-optional-dep/node_modules/peer-dep' - ] + version: '1.0.0' }, 'dev-dep': { version: '1.0.0', @@ -2389,7 +2900,6 @@ test('ls --json', (t) => { dependencies: { a: { version: '1.0.0', - from: 'a@npm:b', resolved: 'https://localhost:8080/abbrev/-/abbrev-1.1.1.tgz' } } @@ -2438,8 +2948,7 @@ test('ls --json', (t) => { dependencies: { abbrev: { version: '1.1.1', - from: 'git+https://github.com/isaacs/abbrev-js.git', - resolved: 'git+https://github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c' + resolved: 'git+ssh://git@github.com/isaacs/abbrev-js.git#b8f3a2fc0c3bb8ffd8b0d0072cc6b5a3667e963c' } } }, @@ -2495,7 +3004,6 @@ test('ls --json', (t) => { dependencies: { 'simple-output': { version: '2.1.1', - from: 'simple-output', resolved: 'https://registry.npmjs.org/simple-output/-/simple-output-2.1.1.tgz' } } @@ -2506,5 +3014,24 @@ test('ls --json', (t) => { }) }) + t.test('node.name fallback if missing root package name', (t) => { + prefix = t.testdir({ + 'package.json': JSON.stringify({ + version: '1.0.0' + }) + }) + ls([], () => { + t.deepEqual( + jsonParse(result), + { + 'version': '1.0.0', + 'name': 'ls-ls-json-node-name-fallback-if-missing-root-package-name' + }, + 'should use node.name as key in json result obj' + ) + t.end() + }) + }) + t.end() }) |