From dc104188a8b252033f7af2649d4a46ee11fd7f22 Mon Sep 17 00:00:00 2001 From: Gar Date: Wed, 2 Mar 2022 20:06:18 -0800 Subject: [PATCH 1/4] chore: mocknpm improvements make tests pass in prefixDir instead of testdir allow for cache and globalPrefix dirs --- .../test/lib/commands/shrinkwrap.js.test.cjs | 50 +++++++++---------- test/fixtures/mock-npm.js | 11 ++-- test/lib/commands/access.js | 16 +++--- test/lib/commands/completion.js | 2 +- test/lib/commands/pack.js | 14 +++--- test/lib/commands/repo.js | 4 +- test/lib/commands/restart.js | 2 +- test/lib/commands/shrinkwrap.js | 8 +-- test/lib/commands/start.js | 2 +- test/lib/commands/stop.js | 2 +- test/lib/commands/test.js | 2 +- test/lib/npm.js | 16 +++--- test/lib/utils/error-message.js | 16 +++--- 13 files changed, 75 insertions(+), 70 deletions(-) diff --git a/tap-snapshots/test/lib/commands/shrinkwrap.js.test.cjs b/tap-snapshots/test/lib/commands/shrinkwrap.js.test.cjs index ddc80a9350f0a..dee5f8af83b0f 100644 --- a/tap-snapshots/test/lib/commands/shrinkwrap.js.test.cjs +++ b/tap-snapshots/test/lib/commands/shrinkwrap.js.test.cjs @@ -16,7 +16,7 @@ exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile ancient > must }, "config": {}, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 1, "requires": true }, @@ -39,7 +39,7 @@ exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile ancient upgrad "lockfile-version": 3 }, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 3, "requires": true, "packages": {} @@ -61,7 +61,7 @@ exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile existing > mus }, "config": {}, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 2, "requires": true, "packages": {} @@ -85,7 +85,7 @@ exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile existing downg "lockfile-version": 1 }, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 1, "requires": true }, @@ -108,7 +108,7 @@ exports[`test/lib/commands/shrinkwrap.js TAP with hidden lockfile existing upgra "lockfile-version": 3 }, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 3, "requires": true, "packages": {} @@ -124,7 +124,7 @@ exports[`test/lib/commands/shrinkwrap.js TAP with nothing ancient > must match s "localPrefix": {}, "config": {}, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 2, "requires": true, "packages": {} @@ -142,7 +142,7 @@ exports[`test/lib/commands/shrinkwrap.js TAP with nothing ancient upgrade > must "lockfile-version": 3 }, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 3, "requires": true, "packages": {} @@ -162,12 +162,12 @@ exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json ancient > }, "config": {}, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "root" + "name": "prefix" } } }, @@ -188,12 +188,12 @@ exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json ancient up "lockfile-version": 3 }, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "root" + "name": "prefix" } } }, @@ -212,12 +212,12 @@ exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json existing > }, "config": {}, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "root" + "name": "prefix" } } }, @@ -238,7 +238,7 @@ exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json existing d "lockfile-version": 1 }, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 1, "requires": true }, @@ -259,12 +259,12 @@ exports[`test/lib/commands/shrinkwrap.js TAP with npm-shrinkwrap.json existing u "lockfile-version": 3 }, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "root" + "name": "prefix" } } }, @@ -283,12 +283,12 @@ exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json ancient > mu }, "config": {}, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "root" + "name": "prefix" } } }, @@ -309,12 +309,12 @@ exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json ancient upgr "lockfile-version": 3 }, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "root" + "name": "prefix" } } }, @@ -333,12 +333,12 @@ exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json existing > m }, "config": {}, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "root" + "name": "prefix" } } }, @@ -359,7 +359,7 @@ exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json existing dow "lockfile-version": 1 }, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 1, "requires": true }, @@ -380,12 +380,12 @@ exports[`test/lib/commands/shrinkwrap.js TAP with package-lock.json existing upg "lockfile-version": 3 }, "shrinkwrap": { - "name": "root", + "name": "prefix", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "root" + "name": "prefix" } } }, diff --git a/test/fixtures/mock-npm.js b/test/fixtures/mock-npm.js index 4846d9a485841..b00f072dc5df3 100644 --- a/test/fixtures/mock-npm.js +++ b/test/fixtures/mock-npm.js @@ -49,7 +49,9 @@ const result = (fn, ...args) => typeof fn === 'function' ? fn(...args) : fn const LoadMockNpm = async (t, { init = true, load = init, - testdir = {}, + prefixDir = {}, + cacheDir = {}, + globalDir = {}, config = {}, mocks = {}, globals = null, @@ -77,9 +79,10 @@ const LoadMockNpm = async (t, { // Set log level as early as possible since setLoglevel(t, config.loglevel) - const dir = t.testdir({ root: testdir, cache: {} }) - const prefix = path.join(dir, 'root') + const dir = t.testdir({ prefix: prefixDir, cache: cacheDir, global: globalDir }) + const prefix = path.join(dir, 'prefix') const cache = path.join(dir, 'cache') + const globalPrefix = path.join(dir, 'global') // Set cache to testdir via env var so it is available when load is run // XXX: remove this for a solution where cache argv is passed in @@ -104,6 +107,7 @@ const LoadMockNpm = async (t, { setLoglevel(t, config.loglevel, false) npm.prefix = prefix npm.cache = cache + npm.globalPrefix = globalPrefix } return { @@ -111,6 +115,7 @@ const LoadMockNpm = async (t, { Npm, npm, prefix, + testdir: dir, cache, debugFile: async () => { const readFiles = npm.logFiles.map(f => fs.readFile(f)) diff --git a/test/lib/commands/access.js b/test/lib/commands/access.js index 298897e4f5ffc..81e29146b6102 100644 --- a/test/lib/commands/access.js +++ b/test/lib/commands/access.js @@ -61,7 +61,7 @@ t.test('edit', async t => { t.test('access public on unscoped package', async t => { const { npm } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name: 'npm-access-public-pkg', }), @@ -91,7 +91,7 @@ t.test('access public on scoped package', async t => { }, }, }, - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name }), }, }) @@ -109,7 +109,7 @@ t.test('access public on missing package.json', async t => { t.test('access public on invalid package.json', async t => { const { npm } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': '{\n', node_modules: {}, }, @@ -123,7 +123,7 @@ t.test('access public on invalid package.json', async t => { t.test('access restricted on unscoped package', async t => { const { npm } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name: 'npm-access-restricted-pkg', }), @@ -153,7 +153,7 @@ t.test('access restricted on scoped package', async t => { }, }, }, - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name }), }, }) @@ -171,7 +171,7 @@ t.test('access restricted on missing package.json', async t => { t.test('access restricted on invalid package.json', async t => { const { npm } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': '{\n', node_modules: {}, }, @@ -240,7 +240,7 @@ t.test('access grant current cwd', async t => { }, }, }, - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name: 'yargs', }), @@ -406,7 +406,7 @@ t.test('access ls-collaborators on current', async t => { }, }, }, - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name: 'yargs', }), diff --git a/test/lib/commands/completion.js b/test/lib/commands/completion.js index dd571baf793a7..045054b74ec7b 100644 --- a/test/lib/commands/completion.js +++ b/test/lib/commands/completion.js @@ -42,7 +42,7 @@ const loadMockCompletionComp = async (t, word, line) => t.test('completion', async t => { t.test('completion completion', async t => { const { outputs, completion, prefix } = await loadMockCompletion(t, { - testdir: { + prefixDir: { '.bashrc': 'aaa', '.zshrc': 'aaa', }, diff --git a/test/lib/commands/pack.js b/test/lib/commands/pack.js index 51453dae9b017..f287d93dc7536 100644 --- a/test/lib/commands/pack.js +++ b/test/lib/commands/pack.js @@ -10,7 +10,7 @@ t.afterEach(t => { t.test('should pack current directory with no arguments', async t => { const { npm, outputs, logs } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name: 'test-package', version: '1.0.0', @@ -27,7 +27,7 @@ t.test('should pack current directory with no arguments', async t => { t.test('follows pack-destination config', async t => { const { npm, outputs } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name: 'test-package', version: '1.0.0', @@ -45,7 +45,7 @@ t.test('follows pack-destination config', async t => { t.test('should pack given directory for scoped package', async t => { const { npm, outputs } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name: '@npm/test-package', version: '1.0.0', @@ -61,7 +61,7 @@ t.test('should pack given directory for scoped package', async t => { t.test('should log output as valid json', async t => { const { npm, outputs, logs } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name: 'test-package', version: '1.0.0', @@ -79,7 +79,7 @@ t.test('should log output as valid json', async t => { t.test('dry run', async t => { const { npm, outputs, logs } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name: 'test-package', version: '1.0.0', @@ -97,7 +97,7 @@ t.test('dry run', async t => { t.test('invalid packument', async t => { const { npm, outputs } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': '{}', }, }) @@ -111,7 +111,7 @@ t.test('invalid packument', async t => { t.test('workspaces', async t => { const loadWorkspaces = (t) => loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': JSON.stringify( { name: 'workspaces-test', diff --git a/test/lib/commands/repo.js b/test/lib/commands/repo.js index 93eb6d0311e1c..e06a2894417bc 100644 --- a/test/lib/commands/repo.js +++ b/test/lib/commands/repo.js @@ -188,10 +188,10 @@ const openUrl = async (npm, url, errMsg) => { } t.afterEach(() => opened = {}) -const loadMockNpm = async (t, prefix) => { +const loadMockNpm = async (t, prefixDir) => { const res = await _loadMockNpm(t, { mocks: { '../../lib/utils/open-url.js': openUrl }, - testdir: prefix, + prefixDir, }) return res } diff --git a/test/lib/commands/restart.js b/test/lib/commands/restart.js index 7730f1a3011f6..83773eae9543b 100644 --- a/test/lib/commands/restart.js +++ b/test/lib/commands/restart.js @@ -14,7 +14,7 @@ const makeSpawnArgs = require('@npmcli/run-script/lib/make-spawn-args.js') t.test('should run restart script from package.json', async t => { const { npm } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name: 'x', version: '1.2.3', diff --git a/test/lib/commands/shrinkwrap.js b/test/lib/commands/shrinkwrap.js index 2b9e46c70c98e..e3fc1f9356705 100644 --- a/test/lib/commands/shrinkwrap.js +++ b/test/lib/commands/shrinkwrap.js @@ -19,14 +19,14 @@ t.formatSnapshot = obj => 2 ) -// Run shrinkwrap against a specified testdir with config items +// Run shrinkwrap against a specified prefixDir with config items // and make some assertions that should always be true. Sets // the results on t.context for use in child tests -const shrinkwrap = async (t, testdir = {}, config = {}, mocks = {}) => { +const shrinkwrap = async (t, prefixDir = {}, config = {}, mocks = {}) => { const { npm, logs } = await loadMockNpm(t, { mocks, config, - testdir, + prefixDir, }) await npm.exec('shrinkwrap', []) @@ -38,7 +38,7 @@ const shrinkwrap = async (t, testdir = {}, config = {}, mocks = {}) => { t.same(logs.warn, [], 'no warnings') t.teardown(() => delete t.context) t.context = { - localPrefix: testdir, + localPrefix: prefixDir, config, shrinkwrap: JSON.parse(fs.readFileSync(newFile)), logs: logs.notice.map(([, m]) => m), diff --git a/test/lib/commands/start.js b/test/lib/commands/start.js index 4f7dc366dbc19..c9312c8e2adc7 100644 --- a/test/lib/commands/start.js +++ b/test/lib/commands/start.js @@ -15,7 +15,7 @@ const makeSpawnArgs = require('@npmcli/run-script/lib/make-spawn-args.js') t.test('should run start script from package.json', async t => { t.plan(2) const { npm } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name: 'x', version: '1.2.3', diff --git a/test/lib/commands/stop.js b/test/lib/commands/stop.js index 53d057b711306..f5db4a047d3f7 100644 --- a/test/lib/commands/stop.js +++ b/test/lib/commands/stop.js @@ -14,7 +14,7 @@ const makeSpawnArgs = require('@npmcli/run-script/lib/make-spawn-args.js') t.test('should run stop script from package.json', async t => { const { npm } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name: 'x', version: '1.2.3', diff --git a/test/lib/commands/test.js b/test/lib/commands/test.js index a3dbd3ff4cffb..665df7148a0e5 100644 --- a/test/lib/commands/test.js +++ b/test/lib/commands/test.js @@ -14,7 +14,7 @@ const makeSpawnArgs = require('@npmcli/run-script/lib/make-spawn-args.js') t.test('should run test script from package.json', async t => { const { npm } = await loadMockNpm(t, { - testdir: { + prefixDir: { 'package.json': JSON.stringify({ name: 'x', version: '1.2.3', diff --git a/test/lib/npm.js b/test/lib/npm.js index b2eedde72bc9d..3ae2af35c287d 100644 --- a/test/lib/npm.js +++ b/test/lib/npm.js @@ -77,7 +77,7 @@ t.test('npm.load', async t => { t.test('basic loading', async t => { const { npm, logs, prefix: dir, cache } = await loadMockNpm(t, { - testdir: { node_modules: {} }, + prefixDir: { node_modules: {} }, }) t.equal(npm.loaded, true) @@ -165,7 +165,7 @@ t.test('npm.load', async t => { ], }) const { npm, logs, outputs, prefix } = await loadMockNpm(t, { - testdir: { + prefixDir: { bin: t.fixture('symlink', dirname(process.execPath)), }, globals: ({ prefix }) => ({ @@ -237,7 +237,7 @@ t.test('npm.load', async t => { }) const { npm } = await loadMockNpm(t, { load: false, - testdir: { + prefixDir: { packages: { a: { 'package.json': JSON.stringify({ @@ -270,7 +270,7 @@ t.test('npm.load', async t => { ], }) const { npm, outputs } = await loadMockNpm(t, { - testdir: { + prefixDir: { packages: { a: { 'package.json': JSON.stringify({ @@ -329,7 +329,7 @@ t.test('npm.load', async t => { ], }) const { npm } = await loadMockNpm(t, { - testdir: { + prefixDir: { packages: { a: { 'package.json': JSON.stringify({ @@ -531,7 +531,7 @@ t.test('explicit workspace rejection', async t => { ], }) const mock = await loadMockNpm(t, { - testdir: { + prefixDir: { packages: { a: { 'package.json': JSON.stringify({ @@ -556,7 +556,7 @@ t.test('explicit workspace rejection', async t => { t.test('implicit workspace rejection', async t => { const mock = await loadMockNpm(t, { - testdir: { + prefixDir: { packages: { a: { 'package.json': JSON.stringify({ @@ -590,7 +590,7 @@ t.test('implicit workspace rejection', async t => { t.test('implicit workspace accept', async t => { const mock = await loadMockNpm(t, { - testdir: { + prefixDir: { packages: { a: { 'package.json': JSON.stringify({ diff --git a/test/lib/utils/error-message.js b/test/lib/utils/error-message.js index ddc88c1d990b0..3fec501ef9ff7 100644 --- a/test/lib/utils/error-message.js +++ b/test/lib/utils/error-message.js @@ -16,10 +16,10 @@ mockGlobals(t, { }, }) -const loadMockNpm = async (t, { load, command, testdir, config } = {}) => { +const loadMockNpm = async (t, { load, command, prefixDir, config } = {}) => { const { npm, ...rest } = await _loadMockNpm(t, { load, - testdir, + prefixDir, config, mocks: { '../../package.json': { @@ -210,7 +210,7 @@ t.test('json parse', t => { mockGlobals(t, { 'process.argv': ['arg', 'v'] }) t.test('merge conflict in package.json', async t => { - const testdir = { + const prefixDir = { 'package.json': ` { "array": [ @@ -250,7 +250,7 @@ t.test('json parse', t => { } `, } - const npm = await loadMockNpm(t, { testdir }) + const npm = await loadMockNpm(t, { prefixDir }) t.matchSnapshot(errorMessage(Object.assign(new Error('conflicted'), { code: 'EJSONPARSE', path: path.resolve(npm.prefix, 'package.json'), @@ -259,10 +259,10 @@ t.test('json parse', t => { }) t.test('just regular bad json in package.json', async t => { - const testdir = { + const prefixDir = { 'package.json': 'not even slightly json', } - const npm = await loadMockNpm(t, { testdir }) + const npm = await loadMockNpm(t, { prefixDir }) t.matchSnapshot(errorMessage(Object.assign(new Error('not json'), { code: 'EJSONPARSE', path: path.resolve(npm.prefix, 'package.json'), @@ -271,10 +271,10 @@ t.test('json parse', t => { }) t.test('json somewhere else', async t => { - const testdir = { + const prefixDir = { 'blerg.json': 'not even slightly json', } - const npm = await loadMockNpm(t, { testdir }) + const npm = await loadMockNpm(t, { prefixDir }) t.matchSnapshot(errorMessage(Object.assign(new Error('not json'), { code: 'EJSONPARSE', path: path.resolve(npm.prefix, 'blerg.json'), From 5f90d9251c66694941774d310b44e2a24eb69e7b Mon Sep 17 00:00:00 2001 From: Gar Date: Wed, 2 Mar 2022 20:41:38 -0800 Subject: [PATCH 2/4] chore: rewrite doctor tests --- lib/commands/doctor.js | 1 + package-lock.json | 191 ++- package.json | 1 + .../test/lib/commands/doctor.js.test.cjs | 1333 ++++++++++++++++ test/fixtures/clean-snapshot.js | 2 +- test/fixtures/mock-logs.js | 22 +- test/fixtures/mock-npm.js | 4 +- test/fixtures/tnock.js | 15 + test/lib/commands/doctor.js | 1379 +++++------------ 9 files changed, 1909 insertions(+), 1039 deletions(-) create mode 100644 tap-snapshots/test/lib/commands/doctor.js.test.cjs create mode 100644 test/fixtures/tnock.js diff --git a/lib/commands/doctor.js b/lib/commands/doctor.js index 9af4c4cd6ffbf..14fda024b9069 100644 --- a/lib/commands/doctor.js +++ b/lib/commands/doctor.js @@ -129,6 +129,7 @@ class Doctor extends BaseCommand { if (!this.npm.silent) { this.npm.output(table(outTable, tableOpts)) if (!allOk) { + // TODO is this really needed? console.error('') } } diff --git a/package-lock.json b/package-lock.json index 2f5c31379eace..a39870423146d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -167,6 +167,7 @@ "@npmcli/template-oss": "^2.9.2", "eslint": "^8.3.0", "licensee": "^8.2.0", + "nock": "^13.2.4", "spawk": "^1.7.1", "tap": "^15.1.6" }, @@ -5331,14 +5332,14 @@ } }, "node_modules/nock": { - "version": "12.0.3", - "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", - "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.4.tgz", + "integrity": "sha512-8GPznwxcPNCH/h8B+XZcKjYPXnUV5clOKCjAqyjsiqA++MpNx9E9+t8YPp0MbThO+KauRo7aZJ1WuIZmOrT2Ug==", "dev": true, "dependencies": { "debug": "^4.1.0", "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.13", + "lodash.set": "^4.3.2", "propagate": "^2.0.0" }, "engines": { @@ -10435,21 +10436,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16" } }, - "workspaces/arborist/node_modules/nock": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.1.tgz", - "integrity": "sha512-CoHAabbqq/xZEknubuyQMjq6Lfi5b7RtK6SoNK6m40lebGp3yiMagWtIoYaw2s9sISD7wPuCfwFpivVHX/35RA==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "json-stringify-safe": "^5.0.1", - "lodash.set": "^4.3.2", - "propagate": "^2.0.0" - }, - "engines": { - "node": ">= 10.13" - } - }, "workspaces/libnpmaccess": { "version": "6.0.0", "license": "ISC", @@ -10468,6 +10454,21 @@ "node": "^12.13.0 || ^14.15.0 || >=16" } }, + "workspaces/libnpmaccess/node_modules/nock": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", + "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.13", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">= 10.13" + } + }, "workspaces/libnpmdiff": { "version": "4.0.0", "license": "ISC", @@ -10622,6 +10623,21 @@ "node": "^12.13.0 || ^14.15.0 || >=16" } }, + "workspaces/libnpmorg/node_modules/nock": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", + "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.13", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">= 10.13" + } + }, "workspaces/libnpmpack": { "version": "4.0.0", "license": "ISC", @@ -10639,21 +10655,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16" } }, - "workspaces/libnpmpack/node_modules/nock": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.1.tgz", - "integrity": "sha512-CoHAabbqq/xZEknubuyQMjq6Lfi5b7RtK6SoNK6m40lebGp3yiMagWtIoYaw2s9sISD7wPuCfwFpivVHX/35RA==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "json-stringify-safe": "^5.0.1", - "lodash.set": "^4.3.2", - "propagate": "^2.0.0" - }, - "engines": { - "node": ">= 10.13" - } - }, "workspaces/libnpmpublish": { "version": "6.0.0", "license": "ISC", @@ -10675,6 +10676,21 @@ "node": "^12.13.0 || ^14.15.0 || >=16" } }, + "workspaces/libnpmpublish/node_modules/nock": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", + "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.13", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">= 10.13" + } + }, "workspaces/libnpmsearch": { "version": "5.0.0", "license": "ISC", @@ -10765,6 +10781,21 @@ "node": "^12.13.0 || ^14.15.0 || >=16" } }, + "workspaces/libnpmteam/node_modules/nock": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", + "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.13", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">= 10.13" + } + }, "workspaces/libnpmversion": { "version": "3.0.0", "license": "ISC", @@ -11340,20 +11371,6 @@ "tcompare": "^5.0.6", "treeverse": "^1.0.4", "walk-up-path": "^1.0.0" - }, - "dependencies": { - "nock": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.1.tgz", - "integrity": "sha512-CoHAabbqq/xZEknubuyQMjq6Lfi5b7RtK6SoNK6m40lebGp3yiMagWtIoYaw2s9sISD7wPuCfwFpivVHX/35RA==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "json-stringify-safe": "^5.0.1", - "lodash.set": "^4.3.2", - "propagate": "^2.0.0" - } - } } }, "@npmcli/ci-detect": { @@ -14285,6 +14302,20 @@ "npm-package-arg": "^9.0.0", "npm-registry-fetch": "^13.0.0", "tap": "^15.1.0" + }, + "dependencies": { + "nock": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", + "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.13", + "propagate": "^2.0.0" + } + } } }, "libnpmdiff": { @@ -14399,6 +14430,20 @@ "nock": "^12.0.1", "npm-registry-fetch": "^13.0.0", "tap": "^15.0.0" + }, + "dependencies": { + "nock": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", + "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.13", + "propagate": "^2.0.0" + } + } } }, "libnpmpack": { @@ -14410,20 +14455,6 @@ "npm-package-arg": "^9.0.0", "pacote": "^13.0.2", "tap": "^15.0.0" - }, - "dependencies": { - "nock": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.1.tgz", - "integrity": "sha512-CoHAabbqq/xZEknubuyQMjq6Lfi5b7RtK6SoNK6m40lebGp3yiMagWtIoYaw2s9sISD7wPuCfwFpivVHX/35RA==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "json-stringify-safe": "^5.0.1", - "lodash.set": "^4.3.2", - "propagate": "^2.0.0" - } - } } }, "libnpmpublish": { @@ -14439,6 +14470,20 @@ "semver": "^7.1.3", "ssri": "^8.0.1", "tap": "^15" + }, + "dependencies": { + "nock": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", + "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.13", + "propagate": "^2.0.0" + } + } } }, "libnpmsearch": { @@ -14507,6 +14552,20 @@ "nock": "^12.0.1", "npm-registry-fetch": "^13.0.0", "tap": "^15" + }, + "dependencies": { + "nock": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", + "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.13", + "propagate": "^2.0.0" + } + } } }, "libnpmversion": { @@ -14908,14 +14967,14 @@ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "nock": { - "version": "12.0.3", - "resolved": "https://registry.npmjs.org/nock/-/nock-12.0.3.tgz", - "integrity": "sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw==", + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.4.tgz", + "integrity": "sha512-8GPznwxcPNCH/h8B+XZcKjYPXnUV5clOKCjAqyjsiqA++MpNx9E9+t8YPp0MbThO+KauRo7aZJ1WuIZmOrT2Ug==", "dev": true, "requires": { "debug": "^4.1.0", "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.13", + "lodash.set": "^4.3.2", "propagate": "^2.0.0" } }, diff --git a/package.json b/package.json index 1d535ac05cd56..6712e6f3a191c 100644 --- a/package.json +++ b/package.json @@ -204,6 +204,7 @@ "@npmcli/template-oss": "^2.9.2", "eslint": "^8.3.0", "licensee": "^8.2.0", + "nock": "^13.2.4", "spawk": "^1.7.1", "tap": "^15.1.6" }, diff --git a/tap-snapshots/test/lib/commands/doctor.js.test.cjs b/tap-snapshots/test/lib/commands/doctor.js.test.cjs new file mode 100644 index 0000000000000..89599185d5dce --- /dev/null +++ b/tap-snapshots/test/lib/commands/doctor.js.test.cjs @@ -0,0 +1,1333 @@ +/* IMPORTANT + * This snapshot file is auto-generated, but designed for humans. + * It should be checked into source control and tracked carefully. + * Re-generate by setting TAP_SNAPSHOT=1 and running tests. + * Make sure to inspect the output below. Do not ignore changes! + */ +'use strict' +exports[`test/lib/commands/doctor.js TAP all clear > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP all clear > output 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP all clear in color > everything is ok in color 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP all clear in color > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP cacache badContent > corrupted cache content 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 2 tarballs +` + +exports[`test/lib/commands/doctor.js TAP cacache badContent > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 1, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 2 + } + ), + ], + ], + "warn": Array [ + Array [ + "verifyCachedFiles", + "Corrupted content removed: 1", + ], + Array [ + "verifyCachedFiles", + "Cache issues have been fixed", + ], + ], +} +` + +exports[`test/lib/commands/doctor.js TAP cacache missingContent > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 1, + "verifiedContent": 2 + } + ), + ], + ], + "warn": Array [ + Array [ + "verifyCachedFiles", + "Missing content: 1", + ], + Array [ + "verifyCachedFiles", + "Cache issues have been fixed", + ], + ], +} +` + +exports[`test/lib/commands/doctor.js TAP cacache missingContent > missing content 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 2 tarballs +` + +exports[`test/lib/commands/doctor.js TAP cacache reclaimedCount > content garbage collected 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 2 tarballs +` + +exports[`test/lib/commands/doctor.js TAP cacache reclaimedCount > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 1, + "missingContent": 0, + "verifiedContent": 2 + } + ), + ], + ], + "warn": Array [ + Array [ + "verifyCachedFiles", + "Content garbage-collected: 1 (undefined bytes)", + ], + Array [ + "verifyCachedFiles", + "Cache issues have been fixed", + ], + ], +} +` + +exports[`test/lib/commands/doctor.js TAP error reading directory > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [ + Array [ + "checkFilesPermission", + "error reading directory {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/cache", + ], + Array [ + "checkFilesPermission", + "error reading directory {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/prefix/node_modules", + ], + Array [ + "checkFilesPermission", + "error reading directory {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/global/lib/node_modules", + ], + Array [ + "checkFilesPermission", + "error reading directory {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/prefix/node_modules/.bin", + ], + Array [ + "checkFilesPermission", + "error reading directory {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/global/bin", + ], + ], +} +` + +exports[`test/lib/commands/doctor.js TAP error reading directory > readdir error 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/cache (should be owned by current user) +Perms check on local node_modules not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/prefix/node_modules (should be owned by current user) +Perms check on global node_modules not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/global/lib/node_modules +Perms check on local bin folder not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/prefix/node_modules/.bin +Perms check on global bin folder not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-error-reading-directory/global/bin +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP incorrect owner > incorrect owner 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache (should be owned by current user) +Perms check on local node_modules not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/prefix/node_modules (should be owned by current user) +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP incorrect owner > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [ + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_logs", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/content-v2", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/index-v5", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/tmp", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_logs/{DATE}-debug-0.log", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/content-v2/sha512", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/index-v5/5e", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/index-v5/af", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/content-v2/sha512/{sha}", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/content-v2/sha512/{sha}", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/index-v5/5e/be", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/index-v5/af/03", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/content-v2/sha512/{sha}", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/content-v2/sha512/{sha}", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/index-v5/5e/be/ccdeeea0a01ebb0e365e566161f7c68ddcbbe04206d8542742d98875f03f", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/index-v5/af/03/5c781820370e585dc2323edbbc80669bf714da5b47d56510c7d0bd7521ee", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/content-v2/sha512/{sha}", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/cache/_cacache/content-v2/sha512/{sha}", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/prefix/node_modules", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/prefix/node_modules/.bin", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/prefix/node_modules/testDir", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/prefix/node_modules/testLink", + ], + Array [ + "checkFilesPermission", + "should be owner of {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-owner/prefix/node_modules/testDir/testFile", + ], + ], +} +` + +exports[`test/lib/commands/doctor.js TAP incorrect permissions > incorrect owner 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/cache (should be owned by current user) +Perms check on local node_modules not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/prefix/node_modules (should be owned by current user) +Perms check on global node_modules not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/global/lib/node_modules +Perms check on local bin folder not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/prefix/node_modules/.bin +Perms check on global bin folder not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/global/bin +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP incorrect permissions > logs 1`] = ` +Object { + "error": Array [ + Array [ + "checkFilesPermission", + "Missing permissions on {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/cache (expect: readable)", + ], + Array [ + "checkFilesPermission", + "Missing permissions on {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/prefix/node_modules (expect: readable, writable)", + ], + Array [ + "checkFilesPermission", + "Missing permissions on {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/global/lib/node_modules (expect: readable)", + ], + Array [ + "checkFilesPermission", + "Missing permissions on {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/prefix/node_modules/.bin (expect: readable, writable, executable)", + ], + Array [ + "checkFilesPermission", + "Missing permissions on {CWD}/test/lib/commands/tap-testdir-doctor-incorrect-permissions/global/bin (expect: executable)", + ], + ], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP missing git > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [ + Array [ + Error: test error, + ], + ], +} +` + +exports[`test/lib/commands/doctor.js TAP missing git > missing git 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git not ok Install git and ensure it's in your PATH. +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP missing global directories > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [ + Array [ + "checkFilesPermission", + "error getting info for {CWD}/test/lib/commands/tap-testdir-doctor-missing-global-directories/global/lib/node_modules", + ], + Array [ + "checkFilesPermission", + "error getting info for {CWD}/test/lib/commands/tap-testdir-doctor-missing-global-directories/global/bin", + ], + ], +} +` + +exports[`test/lib/commands/doctor.js TAP missing global directories > missing global directories 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-missing-global-directories/global/lib/node_modules +Perms check on local bin folder ok +Perms check on global bin folder not ok Check the permissions of files in {CWD}/test/lib/commands/tap-testdir-doctor-missing-global-directories/global/bin +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP node out of date - current > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP node out of date - current > node is out of date 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v not ok Use node v2.0.1 (current: v2.0.0) +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP node out of date - lts > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP node out of date - lts > node is out of date 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v not ok Use node v1.0.0 (current: v0.0.1) +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP non-default registry > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP non-default registry > non default registry 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry not ok Try \`npm config set registry=https://registry.npmjs.org/\` +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP npm out of date > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP npm out of date > npm is out of date 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v not ok Use npm v2.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP ping 404 > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP ping 404 > ping 404 1`] = ` +Check Value Recommendation/Notes +npm ping not ok 404 404 Not Found - GET https://registry.npmjs.org/-/ping?write=true +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP ping 404 in color > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP ping 404 in color > ping 404 in color 1`] = ` +Check Value Recommendation/Notes +npm ping not ok 404 404 Not Found - GET https://registry.npmjs.org/-/ping?write=true +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP ping exception with code > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP ping exception with code > ping failure 1`] = ` +Check Value Recommendation/Notes +npm ping not ok request to https://registry.npmjs.org/-/ping?write=true failed, reason: Test Error +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP ping exception without code > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP ping exception without code > ping failure 1`] = ` +Check Value Recommendation/Notes +npm ping not ok request to https://registry.npmjs.org/-/ping?write=true failed, reason: Test Error +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + +exports[`test/lib/commands/doctor.js TAP silent > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP silent > output 1`] = ` + +` + +exports[`test/lib/commands/doctor.js TAP windows skips permissions checks > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP windows skips permissions checks > no permissions checks 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Verify cache contents ok verified 0 tarballs +` diff --git a/test/fixtures/clean-snapshot.js b/test/fixtures/clean-snapshot.js index 037155eea186d..b0ea28cee4d81 100644 --- a/test/fixtures/clean-snapshot.js +++ b/test/fixtures/clean-snapshot.js @@ -10,7 +10,7 @@ const cleanCwd = (path) => normalizePath(path) .replace(new RegExp(normalizePath(process.cwd()), 'g'), '{CWD}') const cleanDate = (str) => - str.replace(/\d{4}-\d{2}-\d{2}T\d{2}[_:]\d{2}[_:]\d{2}[_:]\d{3}Z/g, '{DATE}') + str.replace(/\d{4}-\d{2}-\d{2}T\d{2}[_:]\d{2}[_:]\d{2}[_:.]\d{3}Z/g, '{DATE}') module.exports = { normalizePath, diff --git a/test/fixtures/mock-logs.js b/test/fixtures/mock-logs.js index 80037c6ffa88d..706c9a3050ac4 100644 --- a/test/fixtures/mock-logs.js +++ b/test/fixtures/mock-logs.js @@ -60,7 +60,27 @@ const mockLogs = (otherMocks = {}) => { return acc }, {}), // except collect timing logs - { timing: (...args) => logs.push(['timing', ...args]) }, + { + timing: (...args) => logs.push(['timing', ...args]), + newItem: () => { + return { + info: (...p) => { + logs.push(['info', ...p]) + }, + warn: (...p) => { + logs.push(['warn', ...p]) + }, + error: (...p) => { + logs.push(['error', ...p]) + }, + silly: (...p) => { + logs.push(['silly', ...p]) + }, + completeWork: () => {}, + finish: () => {}, + } + }, + }, otherMocks.npmlog )), } diff --git a/test/fixtures/mock-npm.js b/test/fixtures/mock-npm.js index b00f072dc5df3..ea608d6644446 100644 --- a/test/fixtures/mock-npm.js +++ b/test/fixtures/mock-npm.js @@ -51,7 +51,7 @@ const LoadMockNpm = async (t, { load = init, prefixDir = {}, cacheDir = {}, - globalDir = {}, + globalPrefixDir = {}, config = {}, mocks = {}, globals = null, @@ -79,7 +79,7 @@ const LoadMockNpm = async (t, { // Set log level as early as possible since setLoglevel(t, config.loglevel) - const dir = t.testdir({ prefix: prefixDir, cache: cacheDir, global: globalDir }) + const dir = t.testdir({ prefix: prefixDir, cache: cacheDir, global: globalPrefixDir }) const prefix = path.join(dir, 'prefix') const cache = path.join(dir, 'cache') const globalPrefix = path.join(dir, 'global') diff --git a/test/fixtures/tnock.js b/test/fixtures/tnock.js new file mode 100644 index 0000000000000..c5acec510543d --- /dev/null +++ b/test/fixtures/tnock.js @@ -0,0 +1,15 @@ +'use strict' + +const nock = require('nock') + +// TODO (other tests actually make network calls today, which is bad) +// nock.disableNetConnect() + +module.exports = tnock +function tnock (t, host) { + const server = nock(host) + t.teardown(function () { + server.done() + }) + return server +} diff --git a/test/lib/commands/doctor.js b/test/lib/commands/doctor.js index dee2110ff3c89..25c3bea0d3ce2 100644 --- a/test/lib/commands/doctor.js +++ b/test/lib/commands/doctor.js @@ -1,1022 +1,463 @@ const t = require('tap') - -const { join } = require('path') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') +const tnock = require('../../fixtures/tnock.js') const fs = require('fs') -const ansiTrim = require('../../../lib/utils/ansi-trim.js') + +const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot.js') + +const cleanCacheSha = (str) => + str.replace(/content-v2\/sha512\/[^"]+/g, 'content-v2/sha512/{sha}') + +t.cleanSnapshot = p => cleanCacheSha(cleanDate(cleanCwd(p))) + +// TODO mockglobals! const isWindows = require('../../../lib/utils/is-windows.js') -const { fake: mockNpm } = require('../../fixtures/mock-npm') + +const processVersion = process.version +// TODO mockglobals! +t.beforeEach(() => { + Object.defineProperty(process, 'version', { value: 'v1.0.0' }) +}) + +const consoleErrorFn = console.error +let consoleError = false +console.error = () => { + consoleError = true +} +t.teardown(() => { + Object.defineProperty(process, 'version', { value: processVersion }) + console.error = consoleErrorFn +}) + +t.afterEach(() => { + consoleError = false +}) // getuid and getgid do not exist in windows, so we shim them // to return 0, as that is the value that lstat will assign the // gid and uid properties for fs.Stats objects +// TODO mockglobals! if (isWindows) { process.getuid = () => 0 process.getgid = () => 0 } -const output = [] - -let pingError -const ping = async () => { - if (pingError) { - throw pingError - } -} - -let whichError = null -const which = async () => { - if (whichError) { - throw whichError +const npmManifest = (version) => { + return { + name: 'npm', + versions: { + [version]: { + name: 'npm', + version: version, + }, + }, + time: { + [version]: new Date(), + }, + 'dist-tags': { latest: version }, } - return '/path/to/git' } const nodeVersions = [ - { version: 'v14.0.0', lts: false }, - { version: 'v13.0.0', lts: false }, - // it's necessary to allow tests in node 10.x to not mark 12.x as lts - { version: 'v12.0.0', lts: false }, - { version: 'v10.13.0', lts: 'Dubnium' }, + { version: 'v2.0.1', lts: false }, + { version: 'v2.0.0', lts: false }, + { version: 'v1.0.0', lts: 'NpmTestium' }, ] -const fetch = async () => { - return { - json: async () => { - return nodeVersions +const dirs = { + prefixDir: { + node_modules: { + testLink: t.fixture('symlink', './testDir'), + testDir: { + testFile: 'test contents', + }, + '.bin': {}, }, - } -} - -const logs = { - info: [], -} - -const clearLogs = () => { - output.length = 0 - for (const key in logs) { - if (Array.isArray(logs[key])) { - logs[key].length = 0 - } else { - delete logs[key] - } - } -} - -const npm = mockNpm({ - flatOptions: { - registry: 'https://registry.npmjs.org/', - }, - config: { - loglevel: 'info', }, - version: '7.1.0', - output: data => { - output.push(data) - }, -}) - -let latestNpm = npm.version -const pacote = { - manifest: async () => { - return { version: latestNpm } - }, -} - -let verifyResponse = { verifiedCount: 1, verifiedContent: 1 } -const cacache = { - verify: async () => { - return verifyResponse + globalPrefixDir: { + bin: {}, + lib: { + node_modules: { + }, + }, }, } const mocks = { - '../../../lib/utils/is-windows.js': false, - '../../../lib/utils/ping.js': ping, - cacache, - pacote, - 'make-fetch-happen': fetch, - which, - 'proc-log': { - info: msg => { - logs.info.push(msg) - }, - }, - npmlog: { - newItem: name => { - logs[name] = {} - return { - info: (_, msg) => { - if (!logs[name].info) { - logs[name].info = [] - } - logs[name].info.push(msg) - }, - warn: (_, msg) => { - if (!logs[name].warn) { - logs[name].warn = [] - } - logs[name].warn.push(msg) - }, - error: (_, msg) => { - if (!logs[name].error) { - logs[name].error = [] - } - logs[name].error.push(msg) - }, - silly: (_, msg) => { - if (!logs[name].silly) { - logs[name].silly = [] - } - logs[name].silly.push(msg) - }, - completeWork: () => {}, - finish: () => { - logs[name].finished = true - }, - } - }, - level: 'error', - levels: { - info: 1, - error: 0, + '../../package.json': { version: '1.0.0' }, + '../../lib/utils/is-windows.js': false, + which: async () => '/path/to/git', + cacache: { + verify: () => { + return { badContentCount: 0, reclaimedCount: 0, missingContent: 0, verifiedContent: 0 } }, }, - } -const Doctor = t.mock('../../../lib/commands/doctor.js', { - ...mocks, +t.test('all clear', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await npm.exec('doctor', []) + t.matchSnapshot(joinedOutput(), 'output') + t.notOk(consoleError, 'console.error not called') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') }) -const doctor = new Doctor(npm) - -const origVersion = process.version -t.test('node versions', t => { - t.plan(nodeVersions.length) - - nodeVersions.forEach(({ version }) => { - t.test(`${version}:`, vt => { - Object.defineProperty(process, 'version', { value: version }) - vt.teardown(() => { - Object.defineProperty(process, 'version', { value: origVersion }) - }) - - vt.test(`${version}: npm doctor checks ok`, async st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - clearLogs() - }) - - await doctor.exec([]) - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, - 'trackers all finished' - ) - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match( - output, - /npm config get registry\s*ok\s*using default/, - 'npm config get registry output is ok' - ) - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - }) - - vt.test('npm doctor supports silent', async st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - npm.config.set('loglevel', 'silent') - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - npm.config.set('loglevel', 'info') - clearLogs() - }) - - await doctor.exec([]) - - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, - 'trackers all finished' - ) - st.strictSame(output, [], 'did not print output') - }) - - vt.test('npm doctor supports color', async st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - npm.color = true - pingError = { message: 'generic error' } - const _consoleError = console.error - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - delete npm.color - pingError = null - console.error = _consoleError - clearLogs() - }) - - await st.rejects(doctor.exec([]), /Some problems found/, 'detected the ping error') - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, - 'trackers all finished' - ) - st.match(output, /npm ping.*not ok/, 'ping output is ok') - st.match(output, /npm -v.*ok/, 'npm -v output is ok') - st.match(output, /node -v.*ok/, 'node -v output is ok') - st.match( - output, - /npm config get registry.*ok.*using default/, - 'npm config get registry output is ok' - ) - st.match(output, /which git.*ok/, 'which git output is ok') - st.match(output, /cached files.*ok/, 'cached files are ok') - st.match(output, /local node_modules.*ok/, 'local node_modules are ok') - st.match(output, /global node_modules.*ok/, 'global node_modules are ok') - st.match(output, /local bin folder.*ok/, 'local bin is ok') - st.match(output, /global bin folder.*ok/, 'global bin is ok') - st.match(output, /cache contents.*ok/, 'cache contents is ok') - st.not(output[0], ansiTrim(output[0]), 'output should contain color codes') - }) - - vt.test('npm doctor skips some tests in windows', async st => { - const WinDoctor = t.mock('../../../lib/commands/doctor.js', { - ...mocks, - '../../../lib/utils/is-windows.js': true, - }) - const winDoctor = new WinDoctor(npm) - - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - clearLogs() - }) - - await winDoctor.exec([]) - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: undefined, - verifyCachedFiles: { finished: true }, - }, - 'trackers all finished' - ) - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match( - output, - /npm config get registry\s*ok\s*using default/, - 'npm config get registry output is ok' - ) - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - }) - - vt.test('npm doctor ping error E{3}', async st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - pingError = { code: 'E111', message: 'this error is 111' } - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - pingError = null - console.error = consoleError - clearLogs() - }) - - await st.rejects(doctor.exec([]), /Some problems found/, 'detected the ping error') - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, - 'trackers all finished' - ) - st.match( - output, - /npm ping\s*not ok\s*111 this error is 111/, - 'ping output contains trimmed error' - ) - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match( - output, - /npm config get registry\s*ok\s*using default/, - 'npm config get registry output is ok' - ) - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - }) - - vt.test('npm doctor generic ping error', async st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - pingError = { message: 'generic error' } - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - pingError = null - console.error = consoleError - clearLogs() - }) - - await st.rejects(doctor.exec([]), /Some problems found/, 'detected the ping error') - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, - 'trackers all finished' - ) - st.match(output, /npm ping\s*not ok\s*generic error/, 'ping output contains trimmed error') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match( - output, - /npm config get registry\s*ok\s*using default/, - 'npm config get registry output is ok' - ) - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - }) - - vt.test('npm doctor outdated npm version', async st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - latestNpm = '7.1.1' - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - latestNpm = npm.version - console.error = consoleError - clearLogs() - }) - await st.rejects(doctor.exec([]), /Some problems found/, 'detected the out of date npm') - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, - 'trackers all finished' - ) - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*not ok/, 'npm -v output is not ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match( - output, - /npm config get registry\s*ok\s*using default/, - 'npm config get registry output is ok' - ) - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - }) - - vt.test('npm doctor file permission checks', async st => { - const dir = st.testdir({ - cache: { - one: 'one', - link: st.fixture('symlink', './baddir'), - unreadable: 'unreadable', - baddir: {}, - }, - local: { - two: 'two', - notmine: 'notmine', - }, - global: { - three: 'three', - broken: 'broken', - }, - localBin: { - four: 'four', - five: 'five', - }, - globalBin: { - six: 'six', - seven: 'seven', - }, - }) - - const _fsLstat = fs.lstat - fs.lstat = (p, cb) => { - let err = null - let stat = null - - try { - stat = fs.lstatSync(p) - } catch (err) { - return cb(err) - } - - switch (p) { - case join(dir, 'local', 'notmine'): - stat.uid += 1 - stat.gid += 1 - break - case join(dir, 'global', 'broken'): - err = new Error('broken') - break - } - - return cb(err, stat) - } - - const _fsReaddir = fs.readdir - fs.readdir = (p, cb) => { - let err = null - let result = null - - try { - result = fs.readdirSync(p) - } catch (err) { - return cb(err) - } - - if (p === join(dir, 'cache', 'baddir')) { - err = new Error('broken') - } - - return cb(err, result) - } - - const _fsAccess = fs.access - fs.access = (p, mask, cb) => { - const err = new Error('failed') - switch (p) { - case join(dir, 'cache', 'unreadable'): - case join(dir, 'localBin', 'four'): - case join(dir, 'globalBin', 'six'): - return cb(err) - default: - return cb(null) - } - } - - const Doctor = t.mock('../../../lib/commands/doctor.js', { - ...mocks, - fs, - }) - const doctor = new Doctor(npm) - // it's necessary to allow tests in node 10.x to not mark 12.x as lted - - npm.cache = npm.flatOptions.cache = join(dir, 'cache') - npm.localDir = join(dir, 'local') - npm.globalDir = join(dir, 'global') - npm.localBin = join(dir, 'localBin') - npm.globalBin = join(dir, 'globalBin') - const _consoleError = console.error - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - console.error = _consoleError - fs.lstat = _fsLstat - fs.readdir = _fsReaddir - fs.access = _fsAccess - clearLogs() - }) - - await st.rejects(doctor.exec([]), /Some problems found/, 'identified problems') - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [join(dir, 'cache')]: { finished: true }, - [join(dir, 'local')]: { finished: true }, - [join(dir, 'global')]: { finished: true }, - [join(dir, 'localBin')]: { finished: true }, - [join(dir, 'globalBin')]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, - 'trackers all finished' - ) - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match( - output, - /npm config get registry\s*ok\s*using default/, - 'npm config get registry output is ok' - ) - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*not ok/, 'cached files are not ok') - st.match(output, /local node_modules\s*not ok/, 'local node_modules are not ok') - st.match(output, /global node_modules\s*not ok/, 'global node_modules are not ok') - st.match(output, /local bin folder\s*not ok/, 'local bin is not ok') - st.match(output, /global bin folder\s*not ok/, 'global bin is not ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - }) - - vt.test('npm doctor missing git', async st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - whichError = new Error('boom') - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - whichError = null - console.error = consoleError - clearLogs() - }) - - await st.rejects(doctor.exec([]), /Some problems found/, 'detected the missing git') - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, - 'trackers all finished' - ) - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match( - output, - /npm config get registry\s*ok\s*using default/, - 'npm config get registry output is ok' - ) - st.match(output, /which git\s*not ok/, 'which git output is not ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - }) - - vt.test('npm doctor cache verification showed bad content', async st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - const _verifyResponse = verifyResponse - verifyResponse = { - ...verifyResponse, - badContentCount: 1, - } - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} - - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - verifyResponse = _verifyResponse - console.error = consoleError - clearLogs() - }) +t.test('all clear in color', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + npm.config.set('color', 'always') + await npm.exec('doctor', []) + t.matchSnapshot(joinedOutput(), 'everything is ok in color') + t.notOk(consoleError, 'console.error not called') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - // cache verification problems get fixed and so do not throw an error - await doctor.exec([]) - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, - 'trackers all finished' - ) - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match( - output, - /npm config get registry\s*ok\s*using default/, - 'npm config get registry output is ok' - ) - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is not ok') - }) +t.test('silent', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + config: { + loglevel: 'silent', + }, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await npm.exec('doctor', []) + t.matchSnapshot(joinedOutput(), 'output') + t.notOk(consoleError, 'console.error not called') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) +t.test('ping 404', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(404, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'ping 404') + t.ok(consoleError, 'console.error called') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - vt.test('npm doctor cache verification showed reclaimed content', async st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - const _verifyResponse = verifyResponse - verifyResponse = { - ...verifyResponse, - reclaimedCount: 1, - reclaimedSize: 100, - } - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} +t.test('ping 404 in color', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(404, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + npm.config.set('color', 'always') + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'ping 404 in color') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - verifyResponse = _verifyResponse - console.error = consoleError - clearLogs() - }) +t.test('ping exception with code', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').replyWithError({ message: 'Test Error', code: 'TEST' }) + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'ping failure') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - // cache verification problems get fixed and so do not throw an error - await doctor.exec([]) +t.test('ping exception without code', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').replyWithError({ message: 'Test Error', code: false }) + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'ping failure') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, - 'trackers all finished' - ) - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match( - output, - /npm config get registry\s*ok\s*using default/, - 'npm config get registry output is ok' - ) - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is not ok') - }) +t.test('npm out of date', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest('2.0.0')) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'npm is out of date') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - vt.test('npm doctor cache verification showed missing content', async st => { - const dir = t.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - const _verifyResponse = verifyResponse - verifyResponse = { - ...verifyResponse, - missingContent: 1, - } - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} +t.test('node out of date - lts', async t => { + Object.defineProperty(process, 'version', { value: 'v0.0.1' }) + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'node is out of date') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - verifyResponse = _verifyResponse - console.error = consoleError - clearLogs() - }) +t.test('node out of date - current', async t => { + Object.defineProperty(process, 'version', { value: 'v2.0.0' }) + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'node is out of date') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - // cache verification problems get fixed and so do not throw an error - await doctor.exec([]) - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, - 'trackers all finished' - ) - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match( - output, - /npm config get registry\s*ok\s*using default/, - 'npm config get registry output is ok' - ) - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is not ok') - }) +t.test('non-default registry', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + config: { registry: 'http://some-other-url.npmjs.org' }, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'non default registry') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - vt.test('npm doctor not using default registry', async st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - const _currentRegistry = npm.flatOptions.registry - npm.flatOptions.registry = 'https://google.com' - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} +t.test('missing git', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks: { + ...mocks, + which: async () => { + throw new Error('test error') + }, + }, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'missing git') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - npm.flatOptions.registry = _currentRegistry - console.error = consoleError - clearLogs() - }) +t.test('windows skips permissions checks', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks: { + ...mocks, + '../../lib/utils/is-windows.js': true, + }, + prefixDir: {}, + globalPrefixDir: {}, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await npm.exec('doctor', []) + t.matchSnapshot(joinedOutput(), 'no permissions checks') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - await st.rejects( - doctor.exec([]), - /Some problems found/, - 'detected the non-default registry' - ) - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, - }, - 'trackers all finished' - ) - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*ok/, 'node -v output is ok') - st.match( - output, - /npm config get registry\s*not ok/, - 'npm config get registry output is not ok' - ) - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') - }) +t.test('missing global directories', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + prefixDir: dirs.prefixDir, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'missing global directories') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - vt.end() - }) +t.test('incorrect owner', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks: { + ...mocks, + fs: { + ...fs, + lstat: (p, cb) => { + const stat = fs.lstatSync(p) + stat.uid += 1 + stat.gid += 1 + return cb(null, stat) + }, + }, + }, + ...dirs, }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'incorrect owner') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') }) -t.test('outdated node version', vt => { - vt.plan(1) - const version = 'v10.0.0' +t.test('incorrect permissions', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks: { + ...mocks, + fs: { + ...fs, + access: () => { + throw new Error('Test Error') + }, + }, + }, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'incorrect owner') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - Object.defineProperty(process, 'version', { value: version }) - vt.teardown(() => { - Object.defineProperty(process, 'version', { value: origVersion }) +t.test('error reading directory', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks: { + ...mocks, + fs: { + ...fs, + readdir: () => { + throw new Error('Test Error') + }, + }, + }, + ...dirs, }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'readdir error') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - vt.test('npm doctor outdated nodejs version', async st => { - const dir = st.testdir() - npm.cache = npm.flatOptions.cache = dir - npm.localDir = dir - npm.globalDir = dir - npm.localBin = dir - npm.globalBin = dir - nodeVersions.push({ version: process.version.replace(/\d+(-.*)?$/, '999'), lts: false }) - const consoleError = console.error - // we just print an empty line here, so swallow it and ignore - console.error = () => {} +t.test('cacache badContent', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks: { + ...mocks, + cacache: { + verify: async () => { + return { badContentCount: 1, reclaimedCount: 0, missingContent: 0, verifiedContent: 2 } + }, + }, + }, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await npm.exec('doctor', []) + t.matchSnapshot(joinedOutput(), 'corrupted cache content') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - st.teardown(() => { - delete npm.cache - delete npm.flatOptions.cache - delete npm.localDir - delete npm.globalDir - delete npm.localBin - delete npm.globalBin - nodeVersions.pop() - console.error = consoleError - clearLogs() - }) +t.test('cacache reclaimedCount', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks: { + ...mocks, + cacache: { + verify: async () => { + return { badContentCount: 0, reclaimedCount: 1, missingContent: 0, verifiedContent: 2 } + }, + }, + }, + ...dirs, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await npm.exec('doctor', []) + t.matchSnapshot(joinedOutput(), 'content garbage collected') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) - await st.rejects(doctor.exec([]), /Some problems found/, 'detected the out of date nodejs') - st.match( - logs, - { - checkPing: { finished: true }, - getLatestNpmVersion: { finished: true }, - getLatestNodejsVersion: { finished: true }, - getGitPath: { finished: true }, - [dir]: { finished: true }, - verifyCachedFiles: { finished: true }, +t.test('cacache missingContent', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks: { + ...mocks, + cacache: { + verify: async () => { + return { badContentCount: 0, reclaimedCount: 0, missingContent: 1, verifiedContent: 2 } + }, }, - 'trackers all finished' - ) - st.match(output, /npm ping\s*ok/, 'ping output is ok') - st.match(output, /npm -v\s*ok/, 'npm -v output is ok') - st.match(output, /node -v\s*not ok/, 'node -v output is not ok') - st.match( - output, - /npm config get registry\s*ok\s*using default/, - 'npm config get registry output is ok' - ) - st.match(output, /which git\s*ok/, 'which git output is ok') - st.match(output, /cached files\s*ok/, 'cached files are ok') - st.match(output, /local node_modules\s*ok/, 'local node_modules are ok') - st.match(output, /global node_modules\s*ok/, 'global node_modules are ok') - st.match(output, /local bin folder\s*ok/, 'local bin is ok') - st.match(output, /global bin folder\s*ok/, 'global bin is ok') - st.match(output, /cache contents\s*ok/, 'cache contents is ok') + }, + ...dirs, }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await npm.exec('doctor', []) + t.matchSnapshot(joinedOutput(), 'missing content') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') }) From d4ff4fb419ffb55af8ea5742c74221d694ab2266 Mon Sep 17 00:00:00 2001 From: Gar Date: Thu, 3 Mar 2022 10:03:09 -0800 Subject: [PATCH 3/4] fix(doctor): don't retry ping --- lib/commands/doctor.js | 2 +- .../test/lib/commands/doctor.js.test.cjs | 58 +++++++++++++++++++ test/lib/commands/doctor.js | 14 +++++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/lib/commands/doctor.js b/lib/commands/doctor.js index 14fda024b9069..552fe5d517341 100644 --- a/lib/commands/doctor.js +++ b/lib/commands/doctor.js @@ -142,7 +142,7 @@ class Doctor extends BaseCommand { const tracker = log.newItem('checkPing', 1) tracker.info('checkPing', 'Pinging registry') try { - await ping(this.npm.flatOptions) + await ping({ ...this.npm.flatOptions, retry: false }) return '' } catch (er) { if (/^E\d{3}$/.test(er.code || '')) { diff --git a/tap-snapshots/test/lib/commands/doctor.js.test.cjs b/tap-snapshots/test/lib/commands/doctor.js.test.cjs index 89599185d5dce..057b6f2e46c2b 100644 --- a/tap-snapshots/test/lib/commands/doctor.js.test.cjs +++ b/tap-snapshots/test/lib/commands/doctor.js.test.cjs @@ -121,6 +121,64 @@ Object { } ` +exports[`test/lib/commands/doctor.js TAP bad proxy > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP bad proxy > output 1`] = ` +Check Value Recommendation/Notes +npm ping not ok unsupported proxy protocol: 'ssh:' +npm -v not ok Error: unsupported proxy protocol: 'ssh:' +node -v not ok Error: unsupported proxy protocol: 'ssh:' +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + exports[`test/lib/commands/doctor.js TAP cacache badContent > corrupted cache content 1`] = ` Check Value Recommendation/Notes npm ping ok diff --git a/test/lib/commands/doctor.js b/test/lib/commands/doctor.js index 25c3bea0d3ce2..9445db8a6fa05 100644 --- a/test/lib/commands/doctor.js +++ b/test/lib/commands/doctor.js @@ -461,3 +461,17 @@ t.test('cacache missingContent', async t => { t.matchSnapshot(joinedOutput(), 'missing content') t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') }) + +t.test('bad proxy', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + config: { + proxy: 'ssh://npmjs.org' + }, + ...dirs, + }) + await t.rejects(npm.exec('doctor', [])) + t.matchSnapshot(joinedOutput(), 'output') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) + From 53a18f1016e222680e46ea84f8c53363c808e057 Mon Sep 17 00:00:00 2001 From: Gar Date: Thu, 24 Feb 2022 10:29:16 -0800 Subject: [PATCH 4/4] fix(doctor): allow for missing local bin and node_modules --- lib/commands/doctor.js | 42 +++--- .../test/lib/commands/doctor.js.test.cjs | 58 ++++++++ test/lib/commands/doctor.js | 131 ++++++++++++------ 3 files changed, 169 insertions(+), 62 deletions(-) diff --git a/lib/commands/doctor.js b/lib/commands/doctor.js index 552fe5d517341..630150c0886fe 100644 --- a/lib/commands/doctor.js +++ b/lib/commands/doctor.js @@ -10,7 +10,6 @@ const semver = require('semver') const { promisify } = require('util') const log = require('../utils/log-shim.js') const ansiTrim = require('../utils/ansi-trim.js') -const isWindows = require('../utils/is-windows.js') const ping = require('../utils/ping.js') const { registry: { default: defaultRegistry }, @@ -55,32 +54,36 @@ class Doctor extends BaseCommand { ['node -v', 'getLatestNodejsVersion', []], ['npm config get registry', 'checkNpmRegistry', []], ['which git', 'getGitPath', []], - ...(isWindows + ...(process.platform === 'win32' ? [] : [ - ['Perms check on cached files', 'checkFilesPermission', [this.npm.cache, true, R_OK]], [ + 'Perms check on cached files', + 'checkFilesPermission', + [this.npm.cache, true, R_OK], + ], [ 'Perms check on local node_modules', 'checkFilesPermission', - [this.npm.localDir, true], - ], - [ + [this.npm.localDir, true, R_OK | W_OK, true], + ], [ 'Perms check on global node_modules', 'checkFilesPermission', - [this.npm.globalDir, false], - ], - [ + [this.npm.globalDir, false, R_OK], + ], [ 'Perms check on local bin folder', 'checkFilesPermission', - [this.npm.localBin, false, R_OK | W_OK | X_OK], - ], - [ + [this.npm.localBin, false, R_OK | W_OK | X_OK, true], + ], [ 'Perms check on global bin folder', 'checkFilesPermission', [this.npm.globalBin, false, X_OK], ], ]), - ['Verify cache contents', 'verifyCachedFiles', [this.npm.flatOptions.cache]], + [ + 'Verify cache contents', + 'verifyCachedFiles', + [this.npm.flatOptions.cache], + ], // TODO: // - ensure arborist.loadActual() runs without errors and no invalid edges // - ensure package-lock.json matches loadActual() @@ -202,11 +205,7 @@ class Doctor extends BaseCommand { } } - async checkFilesPermission (root, shouldOwn, mask = null) { - if (mask === null) { - mask = shouldOwn ? R_OK | W_OK : R_OK - } - + async checkFilesPermission (root, shouldOwn, mask, missingOk) { let ok = true const tracker = log.newItem(root, 1) @@ -218,8 +217,11 @@ class Doctor extends BaseCommand { for (const f of files) { tracker.silly('checkFilesPermission', f.substr(root.length + 1)) const st = await lstat(f).catch(er => { - ok = false - tracker.warn('checkFilesPermission', 'error getting info for ' + f) + // if it can't be missing, or if it can and the error wasn't that it was missing + if (!missingOk || er.code !== 'ENOENT') { + ok = false + tracker.warn('checkFilesPermission', 'error getting info for ' + f) + } }) tracker.completeWork(1) diff --git a/tap-snapshots/test/lib/commands/doctor.js.test.cjs b/tap-snapshots/test/lib/commands/doctor.js.test.cjs index 057b6f2e46c2b..a28654e5d9b29 100644 --- a/tap-snapshots/test/lib/commands/doctor.js.test.cjs +++ b/tap-snapshots/test/lib/commands/doctor.js.test.cjs @@ -826,6 +826,64 @@ Perms check on global bin folder not ok Check the permissions of files in {C Verify cache contents ok verified 0 tarballs ` +exports[`test/lib/commands/doctor.js TAP missing local node_modules > logs 1`] = ` +Object { + "error": Array [], + "info": Array [ + Array [ + "Running checkup", + ], + Array [ + "checkPing", + "Pinging registry", + ], + Array [ + "getLatestNpmVersion", + "Getting npm package information", + ], + Array [ + "getLatestNodejsVersion", + "Getting Node.js release information", + ], + Array [ + "getGitPath", + "Finding git in your PATH", + ], + Array [ + "verifyCachedFiles", + "Verifying the npm cache", + ], + Array [ + "verifyCachedFiles", + String( + Verification complete. Stats: { + "badContentCount": 0, + "reclaimedCount": 0, + "missingContent": 0, + "verifiedContent": 0 + } + ), + ], + ], + "warn": Array [], +} +` + +exports[`test/lib/commands/doctor.js TAP missing local node_modules > missing local node_modules 1`] = ` +Check Value Recommendation/Notes +npm ping ok +npm -v ok current: v1.0.0, latest: v1.0.0 +node -v ok current: v1.0.0, recommended: v1.0.0 +npm config get registry ok using default registry (https://registry.npmjs.org/) +which git ok /path/to/git +Perms check on cached files ok +Perms check on local node_modules ok +Perms check on global node_modules ok +Perms check on local bin folder ok +Perms check on global bin folder ok +Verify cache contents ok verified 0 tarballs +` + exports[`test/lib/commands/doctor.js TAP node out of date - current > logs 1`] = ` Object { "error": Array [], diff --git a/test/lib/commands/doctor.js b/test/lib/commands/doctor.js index 9445db8a6fa05..5badab99a1d56 100644 --- a/test/lib/commands/doctor.js +++ b/test/lib/commands/doctor.js @@ -1,8 +1,9 @@ const t = require('tap') -const { load: loadMockNpm } = require('../../fixtures/mock-npm') -const tnock = require('../../fixtures/tnock.js') const fs = require('fs') +const { load: loadMockNpm } = require('../../fixtures/mock-npm') +const tnock = require('../../fixtures/tnock.js') +const mockGlobals = require('../../fixtures/mock-globals') const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot.js') const cleanCacheSha = (str) => @@ -10,38 +11,6 @@ const cleanCacheSha = (str) => t.cleanSnapshot = p => cleanCacheSha(cleanDate(cleanCwd(p))) -// TODO mockglobals! -const isWindows = require('../../../lib/utils/is-windows.js') - -const processVersion = process.version -// TODO mockglobals! -t.beforeEach(() => { - Object.defineProperty(process, 'version', { value: 'v1.0.0' }) -}) - -const consoleErrorFn = console.error -let consoleError = false -console.error = () => { - consoleError = true -} -t.teardown(() => { - Object.defineProperty(process, 'version', { value: processVersion }) - console.error = consoleErrorFn -}) - -t.afterEach(() => { - consoleError = false -}) - -// getuid and getgid do not exist in windows, so we shim them -// to return 0, as that is the value that lstat will assign the -// gid and uid properties for fs.Stats objects -// TODO mockglobals! -if (isWindows) { - process.getuid = () => 0 - process.getgid = () => 0 -} - const npmManifest = (version) => { return { name: 'npm', @@ -83,9 +52,37 @@ const dirs = { }, } +let consoleError = false +t.afterEach(() => { + consoleError = false +}) + +const globals = { + console: { + error: () => { + consoleError = true + }, + }, + process: { + platform: 'test-not-windows', + version: 'v1.0.0', + }, +} + +// getuid and getgid do not exist in windows, so we shim them +// to return 0, as that is the value that lstat will assign the +// gid and uid properties for fs.Stats objects +if (process.platform === 'win32') { + mockGlobals(t, { + process: { + getuid: () => 0, + getgid: () => 0, + }, + }) +} + const mocks = { '../../package.json': { version: '1.0.0' }, - '../../lib/utils/is-windows.js': false, which: async () => '/path/to/git', cacache: { verify: () => { @@ -97,6 +94,7 @@ const mocks = { t.test('all clear', async t => { const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -113,6 +111,7 @@ t.test('all clear', async t => { t.test('all clear in color', async t => { const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -130,6 +129,7 @@ t.test('all clear in color', async t => { t.test('silent', async t => { const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks, + globals, config: { loglevel: 'silent', }, @@ -145,9 +145,11 @@ t.test('silent', async t => { t.notOk(consoleError, 'console.error not called') t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') }) + t.test('ping 404', async t => { const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -164,6 +166,7 @@ t.test('ping 404', async t => { t.test('ping 404 in color', async t => { const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -180,6 +183,7 @@ t.test('ping 404 in color', async t => { t.test('ping exception with code', async t => { const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -195,6 +199,7 @@ t.test('ping exception with code', async t => { t.test('ping exception without code', async t => { const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -210,6 +215,7 @@ t.test('ping exception without code', async t => { t.test('npm out of date', async t => { const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -223,9 +229,15 @@ t.test('npm out of date', async t => { }) t.test('node out of date - lts', async t => { - Object.defineProperty(process, 'version', { value: 'v0.0.1' }) const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks, + globals: { + ...globals, + process: { + platform: 'test-not-windows', + version: 'v0.0.1', + }, + }, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -239,9 +251,15 @@ t.test('node out of date - lts', async t => { }) t.test('node out of date - current', async t => { - Object.defineProperty(process, 'version', { value: 'v2.0.0' }) const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks, + globals: { + ...globals, + process: { + ...globals.process, + version: 'v2.0.0', + }, + }, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -257,6 +275,7 @@ t.test('node out of date - current', async t => { t.test('non-default registry', async t => { const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks, + globals, config: { registry: 'http://some-other-url.npmjs.org' }, ...dirs, }) @@ -278,6 +297,7 @@ t.test('missing git', async t => { throw new Error('test error') }, }, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -292,9 +312,13 @@ t.test('missing git', async t => { t.test('windows skips permissions checks', async t => { const { joinedOutput, logs, npm } = await loadMockNpm(t, { - mocks: { - ...mocks, - '../../lib/utils/is-windows.js': true, + mocks, + globals: { + ...globals, + process: { + ...globals.process, + platform: 'win32', + }, }, prefixDir: {}, globalPrefixDir: {}, @@ -312,6 +336,7 @@ t.test('windows skips permissions checks', async t => { t.test('missing global directories', async t => { const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks, + globals, prefixDir: dirs.prefixDir, }) tnock(t, npm.config.get('registry')) @@ -324,6 +349,22 @@ t.test('missing global directories', async t => { t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') }) +t.test('missing local node_modules', async t => { + const { joinedOutput, logs, npm } = await loadMockNpm(t, { + mocks, + globals, + globalPrefixDir: dirs.globalPrefixDir, + }) + tnock(t, npm.config.get('registry')) + .get('/-/ping?write=true').reply(200, '{}') + .get('/npm').reply(200, npmManifest(npm.version)) + tnock(t, 'https://nodejs.org') + .get('/dist/index.json').reply(200, nodeVersions) + await npm.exec('doctor', []) + t.matchSnapshot(joinedOutput(), 'missing local node_modules') + t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') +}) + t.test('incorrect owner', async t => { const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks: { @@ -338,6 +379,7 @@ t.test('incorrect owner', async t => { }, }, }, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -361,6 +403,7 @@ t.test('incorrect permissions', async t => { }, }, }, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -384,6 +427,7 @@ t.test('error reading directory', async t => { }, }, }, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -406,6 +450,7 @@ t.test('cacache badContent', async t => { }, }, }, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -428,6 +473,7 @@ t.test('cacache reclaimedCount', async t => { }, }, }, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -450,6 +496,7 @@ t.test('cacache missingContent', async t => { }, }, }, + globals, ...dirs, }) tnock(t, npm.config.get('registry')) @@ -465,8 +512,9 @@ t.test('cacache missingContent', async t => { t.test('bad proxy', async t => { const { joinedOutput, logs, npm } = await loadMockNpm(t, { mocks, + globals, config: { - proxy: 'ssh://npmjs.org' + proxy: 'ssh://npmjs.org', }, ...dirs, }) @@ -474,4 +522,3 @@ t.test('bad proxy', async t => { t.matchSnapshot(joinedOutput(), 'output') t.matchSnapshot({ info: logs.info, warn: logs.warn, error: logs.error }, 'logs') }) -