diff options
Diffstat (limited to 'deps/npm/test/tap')
90 files changed, 3008 insertions, 423 deletions
diff --git a/deps/npm/test/tap/00-verify-ls-ok.js b/deps/npm/test/tap/00-verify-ls-ok.js index 2d20e500b7..edff251d76 100644 --- a/deps/npm/test/tap/00-verify-ls-ok.js +++ b/deps/npm/test/tap/00-verify-ls-ok.js @@ -9,10 +9,19 @@ test('npm ls in npm', function (t) { var files = fs.readdirSync(cwd) t.notEqual(files.length, 0, 'ensure there are files in the directory we are to ls') - var opt = { cwd: cwd, stdio: [ 'ignore', 'ignore', 2 ] } - common.npm(['ls'], opt, function (err, code) { + var opt = { cwd: cwd, stdio: [ 'ignore', 'pipe', 2 ] } + common.npm(['ls', '--json'], opt, function (err, code, stdout) { t.ifError(err, 'error should not exist') t.equal(code, 0, 'npm ls exited with code') + const tree = JSON.parse(stdout).dependencies + // We need to have a toplevel `node-gyp` available, but we also need to + // make sure npm-lifecycle's version is updated in concert. + // See https://github.com/npm/npm/issues/20163 + t.deepEqual( + tree['npm-lifecycle'].dependencies['node-gyp'].version, + tree['node-gyp'].version, + 'npm-lifecycle and npm using same version of node-gyp' + ) t.end() }) }) diff --git a/deps/npm/test/tap/adduser-always-auth.js b/deps/npm/test/tap/adduser-always-auth.js index 375c3ab262..d327e35a9e 100644 --- a/deps/npm/test/tap/adduser-always-auth.js +++ b/deps/npm/test/tap/adduser-always-auth.js @@ -33,10 +33,13 @@ function verifyStdout (runner, successMessage, t) { function mocks (server) { server.filteringRequestBody(function (r) { - if (r.match(/\"_id\":\"org\.couchdb\.user:u\"/)) { + if (r.match(/"_id":"org\.couchdb\.user:u"/)) { return 'auth' + } else { + return 'invalid' } }) + server.post('/-/v1/login', 'invalid').reply(404, 'not found') server.put('/-/user/org.couchdb.user:u', 'auth') .reply(201, { username: 'u', password: 'p', email: 'u@p.me' }) } @@ -50,18 +53,18 @@ test('npm login', function (t) { '--loglevel', 'silent', '--userconfig', outfile ], - opts, - function (err, code) { - t.notOk(code, 'exited OK') - t.notOk(err, 'no error output') - var config = fs.readFileSync(outfile, 'utf8') - t.like(config, /:always-auth=false/, 'always-auth is scoped and false (by default)') - s.close() - rimraf(outfile, function (err) { - t.ifError(err, 'removed config file OK') - t.end() + opts, + function (err, code) { + t.notOk(code, 'exited OK') + t.notOk(err, 'no error output') + var config = fs.readFileSync(outfile, 'utf8') + t.like(config, /:always-auth=false/, 'always-auth is scoped and false (by default)') + s.close() + rimraf(outfile, function (err) { + t.ifError(err, 'removed config file OK') + t.end() + }) }) - }) var message = 'Logged in as u on ' + common.registry + '/.' runner.stdout.on('data', verifyStdout(runner, message, t)) @@ -80,36 +83,36 @@ test('npm login --scope <scope> uses <scope>:registry as its URI', function (t) scope + ':registry', uri ], - opts, - function (err, code) { - t.notOk(code, 'exited OK') - t.notOk(err, 'no error output') + opts, + function (err, code) { + t.notOk(code, 'exited OK') + t.notOk(err, 'no error output') - mr({ port: port, plugin: mocks }, function (er, s) { - var runner = common.npm( - [ - 'login', - '--loglevel', 'silent', - '--userconfig', outfile, - '--scope', scope - ], - opts, - function (err, code) { - t.notOk(code, 'exited OK') - t.notOk(err, 'no error output') - var config = fs.readFileSync(outfile, 'utf8') - t.like(config, new RegExp(scope + ':registry=' + uri), 'scope:registry is set') - s.close() - rimraf(outfile, function (err) { - t.ifError(err, 'removed config file OK') - t.end() - }) - }) + mr({ port: port, plugin: mocks }, function (er, s) { + var runner = common.npm( + [ + 'login', + '--loglevel', 'silent', + '--userconfig', outfile, + '--scope', scope + ], + opts, + function (err, code) { + t.notOk(code, 'exited OK') + t.notOk(err, 'no error output') + var config = fs.readFileSync(outfile, 'utf8') + t.like(config, new RegExp(scope + ':registry=' + uri), 'scope:registry is set') + s.close() + rimraf(outfile, function (err) { + t.ifError(err, 'removed config file OK') + t.end() + }) + }) - var message = 'Logged in as u to scope ' + scope + ' on ' + uri + '.' - runner.stdout.on('data', verifyStdout(runner, message, t)) + var message = 'Logged in as u to scope ' + scope + ' on ' + uri + '.' + runner.stdout.on('data', verifyStdout(runner, message, t)) + }) }) - }) }) test('npm login --scope <scope> makes sure <scope> is prefixed by an @', function (t) { @@ -125,36 +128,36 @@ test('npm login --scope <scope> makes sure <scope> is prefixed by an @', functio prefixedScope + ':registry', uri ], - opts, - function (err, code) { - t.notOk(code, 'exited OK') - t.notOk(err, 'no error output') + opts, + function (err, code) { + t.notOk(code, 'exited OK') + t.notOk(err, 'no error output') - mr({ port: port, plugin: mocks }, function (er, s) { - var runner = common.npm( - [ - 'login', - '--loglevel', 'silent', - '--userconfig', outfile, - '--scope', scope - ], - opts, - function (err, code) { - t.notOk(code, 'exited OK') - t.notOk(err, 'no error output') - var config = fs.readFileSync(outfile, 'utf8') - t.like(config, new RegExp(prefixedScope + ':registry=' + uri), 'scope:registry is set') - s.close() - rimraf(outfile, function (err) { - t.ifError(err, 'removed config file OK') - t.end() - }) - }) + mr({ port: port, plugin: mocks }, function (er, s) { + var runner = common.npm( + [ + 'login', + '--loglevel', 'silent', + '--userconfig', outfile, + '--scope', scope + ], + opts, + function (err, code) { + t.notOk(code, 'exited OK') + t.notOk(err, 'no error output') + var config = fs.readFileSync(outfile, 'utf8') + t.like(config, new RegExp(prefixedScope + ':registry=' + uri), 'scope:registry is set') + s.close() + rimraf(outfile, function (err) { + t.ifError(err, 'removed config file OK') + t.end() + }) + }) - var message = 'Logged in as u to scope ' + prefixedScope + ' on ' + uri + '.' - runner.stdout.on('data', verifyStdout(runner, message, t)) + var message = 'Logged in as u to scope ' + prefixedScope + ' on ' + uri + '.' + runner.stdout.on('data', verifyStdout(runner, message, t)) + }) }) - }) }) test('npm login --scope <scope> --registry <registry> uses <registry> as its URI', function (t) { @@ -167,37 +170,37 @@ test('npm login --scope <scope> --registry <registry> uses <registry> as its URI scope + ':registry', 'invalidurl' ], - opts, - function (err, code) { - t.notOk(code, 'exited OK') - t.notOk(err, 'no error output') + opts, + function (err, code) { + t.notOk(code, 'exited OK') + t.notOk(err, 'no error output') - mr({ port: common.port, plugin: mocks }, function (er, s) { - var runner = common.npm( - [ - 'login', - '--registry', common.registry, - '--loglevel', 'silent', - '--userconfig', outfile, - '--scope', scope - ], - opts, - function (err, code) { - t.notOk(code, 'exited OK') - t.notOk(err, 'no error output') - var config = fs.readFileSync(outfile, 'utf8') - t.like(config, new RegExp(scope + ':registry=' + common.registry), 'scope:registry is set') - s.close() - rimraf(outfile, function (err) { - t.ifError(err, 'removed config file OK') - t.end() - }) - }) + mr({ port: common.port, plugin: mocks }, function (er, s) { + var runner = common.npm( + [ + 'login', + '--registry', common.registry, + '--loglevel', 'silent', + '--userconfig', outfile, + '--scope', scope + ], + opts, + function (err, code) { + t.notOk(code, 'exited OK') + t.notOk(err, 'no error output') + var config = fs.readFileSync(outfile, 'utf8') + t.like(config, new RegExp(scope + ':registry=' + common.registry), 'scope:registry is set') + s.close() + rimraf(outfile, function (err) { + t.ifError(err, 'removed config file OK') + t.end() + }) + }) - var message = 'Logged in as u to scope ' + scope + ' on ' + common.registry + '/.' - runner.stdout.on('data', verifyStdout(runner, message, t)) + var message = 'Logged in as u to scope ' + scope + ' on ' + common.registry + '/.' + runner.stdout.on('data', verifyStdout(runner, message, t)) + }) }) - }) }) test('npm login --always-auth', function (t) { @@ -210,18 +213,18 @@ test('npm login --always-auth', function (t) { '--userconfig', outfile, '--always-auth' ], - opts, - function (err, code) { - t.notOk(code, 'exited OK') - t.notOk(err, 'no error output') - var config = fs.readFileSync(outfile, 'utf8') - t.like(config, /:always-auth=true/, 'always-auth is scoped and true') - s.close() - rimraf(outfile, function (err) { - t.ifError(err, 'removed config file OK') - t.end() + opts, + function (err, code) { + t.notOk(code, 'exited OK') + t.notOk(err, 'no error output') + var config = fs.readFileSync(outfile, 'utf8') + t.like(config, /:always-auth=true/, 'always-auth is scoped and true') + s.close() + rimraf(outfile, function (err) { + t.ifError(err, 'removed config file OK') + t.end() + }) }) - }) var message = 'Logged in as u on ' + common.registry + '/.' runner.stdout.on('data', verifyStdout(runner, message, t)) @@ -238,18 +241,18 @@ test('npm login --no-always-auth', function (t) { '--userconfig', outfile, '--no-always-auth' ], - opts, - function (err, code) { - t.notOk(code, 'exited OK') - t.notOk(err, 'no error output') - var config = fs.readFileSync(outfile, 'utf8') - t.like(config, /:always-auth=false/, 'always-auth is scoped and false') - s.close() - rimraf(outfile, function (err) { - t.ifError(err, 'removed config file OK') - t.end() + opts, + function (err, code) { + t.notOk(code, 'exited OK') + t.notOk(err, 'no error output') + var config = fs.readFileSync(outfile, 'utf8') + t.like(config, /:always-auth=false/, 'always-auth is scoped and false') + s.close() + rimraf(outfile, function (err) { + t.ifError(err, 'removed config file OK') + t.end() + }) }) - }) var message = 'Logged in as u on ' + common.registry + '/.' runner.stdout.on('data', verifyStdout(runner, message, t)) diff --git a/deps/npm/test/tap/adduser-legacy-auth.js b/deps/npm/test/tap/adduser-legacy-auth.js index 67292cf06a..49015878f7 100644 --- a/deps/npm/test/tap/adduser-legacy-auth.js +++ b/deps/npm/test/tap/adduser-legacy-auth.js @@ -11,7 +11,7 @@ var opts = { cwd: __dirname } var pkg = path.resolve(__dirname, 'adduser-legacy-auth') var outfile = path.resolve(pkg, '_npmrc') -var contents = '_auth=' + new Buffer('u:x').toString('base64') + '\n' + +var contents = '_auth=' + Buffer.from('u:x').toString('base64') + '\n' + 'registry=https://nonexistent.lvh.me/registry\n' + 'email=u@p.me\n' @@ -25,8 +25,11 @@ function mocks (server) { server.filteringRequestBody(function (r) { if (r.match(/"_id":"org\.couchdb\.user:u"/)) { return 'auth' + } else { + return 'invalid' } }) + server.post('/-/v1/login', 'invalid').reply(404, 'not found') server.put('/-/user/org.couchdb.user:u', 'auth') .reply(409, { error: 'user exists' }) server.get('/-/user/org.couchdb.user:u?write=true') @@ -35,7 +38,7 @@ function mocks (server) { '/-/user/org.couchdb.user:u/-rev/3-deadcafebabebeef', 'auth', { authorization: 'Basic dTpw' } - ).reply(201, { username: 'u', password: 'p', email: 'u@p.me' }) + ).reply(201, { username: 'u', password: 'p', email: 'u@p.me' }) } test('setup', function (t) { diff --git a/deps/npm/test/tap/adduser-oauth.js b/deps/npm/test/tap/adduser-oauth.js index dc4ff895e0..04065048c4 100644 --- a/deps/npm/test/tap/adduser-oauth.js +++ b/deps/npm/test/tap/adduser-oauth.js @@ -20,8 +20,11 @@ function mocks (server) { server.filteringRequestBody(function (r) { if (r.match(/"_id":"org\.couchdb\.user:npm_oauth_auth_dummy_user"/)) { return 'auth' + } else { + return 'invalid' } }) + server.post('/-/v1/login', 'invalid').reply(404, 'not found') server.put('/-/user/org.couchdb.user:npm_oauth_auth_dummy_user', 'auth') .reply(201, { token: 'foo', sso: ssoUri }) } @@ -30,7 +33,7 @@ test('setup', function (t) { mkdirp.sync(pkg) fs.writeFileSync(configfile, '') var s = '#!/usr/bin/env bash\n' + - 'echo \"$@\" > ' + outfile + '\n' + 'echo "$@" > ' + outfile + '\n' fs.writeFileSync(fakeBrowser, s, 'ascii') fs.chmodSync(fakeBrowser, '0755') t.pass('made script') @@ -42,7 +45,7 @@ test('npm login', function (t) { s.get( '/-/whoami', { authorization: 'Bearer foo' } ).max(1).reply(401, {}) - var runner = common.npm( + common.npm( [ 'login', '--registry', common.registry, @@ -66,15 +69,9 @@ test('npm login', function (t) { } ) - var buf = '' - runner.stdout.on('data', function (chunk) { - buf += chunk.toString('utf8') - if (buf.match(/complete authentication/)) { - s.get( - '/-/whoami', { authorization: 'Bearer foo' } - ).reply(200, { username: 'igotauthed' }) - } - }) + s.get( + '/-/whoami', { authorization: 'Bearer foo' } + ).reply(200, { username: 'igotauthed' }) }) }) diff --git a/deps/npm/test/tap/adduser-saml.js b/deps/npm/test/tap/adduser-saml.js index 7fd1da2392..530ebb52b3 100644 --- a/deps/npm/test/tap/adduser-saml.js +++ b/deps/npm/test/tap/adduser-saml.js @@ -20,8 +20,11 @@ function mocks (server) { server.filteringRequestBody(function (r) { if (r.match(/"_id":"org\.couchdb\.user:npm_saml_auth_dummy_user"/)) { return 'auth' + } else { + return 'invalid' } }) + server.post('/-/v1/login', 'invalid').reply(404, 'not found') server.put('/-/user/org.couchdb.user:npm_saml_auth_dummy_user', 'auth') .reply(201, { token: 'foo', sso: ssoUri }) } @@ -30,7 +33,7 @@ test('setup', function (t) { mkdirp.sync(pkg) fs.writeFileSync(configfile, '') var s = '#!/usr/bin/env bash\n' + - 'echo \"$@\" > ' + outfile + '\n' + 'echo "$@" > ' + outfile + '\n' fs.writeFileSync(fakeBrowser, s, 'ascii') fs.chmodSync(fakeBrowser, '0755') t.pass('made script') @@ -42,7 +45,7 @@ test('npm login', function (t) { s.get( '/-/whoami', { authorization: 'Bearer foo' } ).max(1).reply(401, {}) - var runner = common.npm( + common.npm( [ 'login', '--registry', common.registry, @@ -66,15 +69,9 @@ test('npm login', function (t) { } ) - var buf = '' - runner.stdout.on('data', function (chunk) { - buf += chunk.toString('utf8') - if (buf.match(/complete authentication/)) { - s.get( - '/-/whoami', { authorization: 'Bearer foo' } - ).reply(200, { username: 'igotauthed' }) - } - }) + s.get( + '/-/whoami', { authorization: 'Bearer foo' } + ).reply(200, { username: 'igotauthed' }) }) }) diff --git a/deps/npm/test/tap/anon-cli-metrics.js b/deps/npm/test/tap/anon-cli-metrics.js index 2ece5a1e6c..100ca526cf 100644 --- a/deps/npm/test/tap/anon-cli-metrics.js +++ b/deps/npm/test/tap/anon-cli-metrics.js @@ -7,7 +7,6 @@ var mr = require('npm-registry-mock') var Tacks = require('tacks') var File = Tacks.File var Dir = Tacks.Dir -var extend = Object.assign || require('util')._extend var common = require('../common-tap.js') var basedir = path.join(__dirname, path.basename(__filename, '.js')) @@ -19,7 +18,7 @@ var metricsFile = path.join(cachedir, 'anonymous-cli-metrics.json') var conf = { cwd: testdir, - env: extend(extend({}, process.env), { + env: Object.assign({}, process.env, { npm_config_cache: cachedir, npm_config_tmp: tmpdir, npm_config_prefix: globaldir, diff --git a/deps/npm/test/tap/audit-fix.js b/deps/npm/test/tap/audit-fix.js new file mode 100644 index 0000000000..579d43a798 --- /dev/null +++ b/deps/npm/test/tap/audit-fix.js @@ -0,0 +1,669 @@ +'use strict' + +const BB = require('bluebird') + +const common = BB.promisifyAll(require('../common-tap.js')) +const fs = require('fs') +const mr = BB.promisify(require('npm-registry-mock')) +const path = require('path') +const rimraf = BB.promisify(require('rimraf')) +const Tacks = require('tacks') +const tap = require('tap') +const test = tap.test + +const Dir = Tacks.Dir +const File = Tacks.File +const testDir = path.join(__dirname, path.basename(__filename, '.js')) + +const EXEC_OPTS = { cwd: testDir } + +tap.tearDown(function () { + process.chdir(__dirname) + try { + rimraf.sync(testDir) + } catch (e) { + if (process.platform !== 'win32') { + throw e + } + } +}) + +function tmock (t) { + return mr({port: common.port}).then(s => { + t.tearDown(function () { + s.done() + s.close() + rimraf.sync(testDir) + }) + return s + }) +} + +test('fixes shallow vulnerabilities', t => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'foo', + version: '1.0.0', + dependencies: { + baddep: '1.0.0' + } + }) + })) + fixture.create(testDir) + return tmock(t).then(srv => { + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits/quick', 'ok').reply(200, 'yeah') + srv.get('/baddep').twice().reply(200, { + name: 'baddep', + 'dist-tags': { + 'latest': '1.2.3' + }, + versions: { + '1.0.0': { + name: 'baddep', + version: '1.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.0.0.tgz' + } + }, + '1.2.3': { + name: 'baddep', + version: '1.2.3', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.2.3.tgz' + } + } + } + }) + return common.npm([ + 'install', + '--audit', + '--json', + '--package-lock-only', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.0.0' + }] + }, 'installed bad version') + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits', 'ok').reply(200, { + actions: [{ + action: 'update', + module: 'baddep', + target: '1.2.3', + resolves: [{path: 'baddep'}] + }], + metadata: { + vulnerabilities: { + critical: 1 + } + } + }) + return common.npm([ + 'audit', 'fix', + '--package-lock-only', + '--json', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.2.3' + }] + }, 'reported dependency update') + t.similar(JSON.parse(fs.readFileSync(path.join(testDir, 'package-lock.json'), 'utf8')), { + dependencies: { + baddep: { + version: '1.2.3', + resolved: common.registry + '/idk/-/idk-1.2.3.tgz', + integrity: 'sha1-3q2+7w==' + } + } + }, 'pkglock updated correctly') + }) + }) + }) +}) + +test('fixes nested dep vulnerabilities', t => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'foo', + version: '1.0.0', + dependencies: { + gooddep: '^1.0.0' + } + }) + })) + fixture.create(testDir) + return tmock(t).then(srv => { + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits/quick', 'ok').reply(200, 'yeah') + srv.get('/baddep').reply(200, { + name: 'baddep', + 'dist-tags': { + 'latest': '1.0.0' + }, + versions: { + '1.0.0': { + name: 'baddep', + version: '1.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'c0ffee', + integrity: 'sha1-c0ffee', + tarball: common.registry + '/baddep/-/baddep-1.0.0.tgz' + } + }, + '1.2.3': { + name: 'baddep', + version: '1.2.3', + _hasShrinkwrap: false, + dist: { + shasum: 'bada55', + integrity: 'sha1-bada55', + tarball: common.registry + '/baddep/-/baddep-1.2.3.tgz' + } + } + } + }) + + srv.get('/gooddep').reply(200, { + name: 'gooddep', + 'dist-tags': { + 'latest': '1.0.0' + }, + versions: { + '1.0.0': { + name: 'gooddep', + version: '1.0.0', + dependencies: { + baddep: '^1.0.0' + }, + _hasShrinkwrap: false, + dist: { + shasum: '1234', + tarball: common.registry + '/gooddep/-/gooddep-1.0.0.tgz' + } + }, + '1.2.3': { + name: 'gooddep', + version: '1.2.3', + _hasShrinkwrap: false, + dependencies: { + baddep: '^1.0.0' + }, + dist: { + shasum: '123456', + tarball: common.registry + '/gooddep/-/gooddep-1.2.3.tgz' + } + } + } + }) + + return common.npm([ + 'install', + '--audit', + '--json', + '--global-style', + '--package-lock-only', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.0.0' + }, { + action: 'add', + name: 'gooddep', + version: '1.0.0' + }] + }, 'installed bad version') + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits', 'ok').reply(200, { + actions: [{ + action: 'update', + module: 'baddep', + target: '1.2.3', + resolves: [{path: 'gooddep>baddep'}] + }], + metadata: { + vulnerabilities: { + critical: 1 + } + } + }) + return common.npm([ + 'audit', 'fix', + '--package-lock-only', + '--offline', + '--json', + '--global-style', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.2.3' + }, { + action: 'add', + name: 'gooddep', + version: '1.0.0' + }] + }, 'reported dependency update') + t.similar(JSON.parse(fs.readFileSync(path.join(testDir, 'package-lock.json'), 'utf8')), { + dependencies: { + gooddep: { + version: '1.0.0', + resolved: common.registry + '/gooddep/-/gooddep-1.0.0.tgz', + integrity: 'sha1-EjQ=', + requires: { + baddep: '^1.0.0' + }, + dependencies: { + baddep: { + version: '1.2.3', + resolved: common.registry + '/baddep/-/baddep-1.2.3.tgz', + integrity: 'sha1-bada55' + } + } + } + } + }, 'pkglock updated correctly') + }) + }) + }) +}) + +test('no semver-major without --force', t => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'foo', + version: '1.0.0', + dependencies: { + baddep: '1.0.0' + } + }) + })) + fixture.create(testDir) + return tmock(t).then(srv => { + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits/quick', 'ok').reply(200, 'yeah') + srv.get('/baddep').twice().reply(200, { + name: 'baddep', + 'dist-tags': { + 'latest': '2.0.0' + }, + versions: { + '1.0.0': { + name: 'baddep', + version: '1.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.0.0.tgz' + } + }, + '2.0.0': { + name: 'baddep', + version: '2.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-2.0.0.tgz' + } + } + } + }) + return common.npm([ + 'install', + '--audit', + '--json', + '--package-lock-only', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.0.0' + }] + }, 'installed bad version') + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits', 'ok').reply(200, { + actions: [{ + action: 'install', + module: 'baddep', + target: '2.0.0', + isMajor: true, + resolves: [{path: 'baddep'}] + }], + metadata: { + vulnerabilities: { + critical: 1 + } + } + }) + return common.npm([ + 'audit', 'fix', + '--package-lock-only', + '--registry', common.registry, + '--loglevel=warn', + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.match(stdout, /breaking changes/, 'informs about semver-major') + t.match(stdout, /npm audit fix --force/, 'recommends --force') + t.similar(JSON.parse(fs.readFileSync(path.join(testDir, 'package-lock.json'), 'utf8')), { + dependencies: { + baddep: { + version: '1.0.0' + } + } + }, 'pkglock not updated') + }) + }) + }) +}) + +test('semver-major when --force', t => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'foo', + version: '1.0.0', + dependencies: { + baddep: '1.0.0' + } + }) + })) + fixture.create(testDir) + return tmock(t).then(srv => { + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits/quick', 'ok').reply(200, 'yeah') + srv.get('/baddep').twice().reply(200, { + name: 'baddep', + 'dist-tags': { + 'latest': '2.0.0' + }, + versions: { + '1.0.0': { + name: 'baddep', + version: '1.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.0.0.tgz' + } + }, + '2.0.0': { + name: 'baddep', + version: '2.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-2.0.0.tgz' + } + } + } + }) + return common.npm([ + 'install', + '--audit', + '--json', + '--package-lock-only', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.0.0' + }] + }, 'installed bad version') + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits', 'ok').reply(200, { + actions: [{ + action: 'install', + module: 'baddep', + target: '2.0.0', + isMajor: true, + resolves: [{path: 'baddep'}] + }], + metadata: { + vulnerabilities: { + critical: 1 + } + } + }) + return common.npm([ + 'audit', 'fix', + '--package-lock-only', + '--registry', common.registry, + '--force', + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.match(stdout, /breaking changes/, 'informs about semver-major') + t.similar(JSON.parse(fs.readFileSync(path.join(testDir, 'package-lock.json'), 'utf8')), { + dependencies: { + baddep: { + version: '2.0.0' + } + } + }, 'pkglock not updated') + }) + }) + }) +}) + +test('no installs for review-requires', t => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'foo', + version: '1.0.0', + dependencies: { + baddep: '1.0.0' + } + }) + })) + fixture.create(testDir) + return tmock(t).then(srv => { + srv.filteringRequestBody(req => 'k') + srv.post('/-/npm/v1/security/audits/quick', 'k').reply(200, 'yeah') + srv.get('/baddep').twice().reply(200, { + name: 'baddep', + 'dist-tags': { + 'latest': '1.2.3' + }, + versions: { + '1.0.0': { + name: 'baddep', + version: '1.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.0.0.tgz' + } + }, + '1.2.3': { + name: 'baddep', + version: '1.2.3', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.2.3.tgz' + } + } + } + }) + return common.npm([ + 'install', + '--audit', + '--json', + '--package-lock-only', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.0.0' + }] + }, 'installed bad version') + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits', 'ok').reply(200, { + actions: [{ + action: 'review', + module: 'baddep', + target: '1.2.3', + resolves: [{path: 'baddep'}] + }], + metadata: { + vulnerabilities: { + critical: 1 + } + } + }) + return common.npm([ + 'audit', 'fix', + '--package-lock-only', + '--json', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'baddep', + version: '1.0.0' + }] + }, 'no update for dependency') + }) + }) + }) +}) + +test('nothing to fix', t => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'foo', + version: '1.0.0', + dependencies: { + gooddep: '1.0.0' + } + }) + })) + fixture.create(testDir) + return tmock(t).then(srv => { + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits/quick', 'ok').reply(200, 'yeah') + srv.get('/gooddep').twice().reply(200, { + name: 'gooddep', + 'dist-tags': { + 'latest': '1.2.3' + }, + versions: { + '1.0.0': { + name: 'gooddep', + version: '1.0.0', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.0.0.tgz' + } + }, + '1.2.3': { + name: 'gooddep', + version: '1.2.3', + _hasShrinkwrap: false, + dist: { + shasum: 'deadbeef', + tarball: common.registry + '/idk/-/idk-1.2.3.tgz' + } + } + } + }) + return common.npm([ + 'install', + '--audit', + '--json', + '--package-lock-only', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'gooddep', + version: '1.0.0' + }] + }, 'installed good version') + srv.filteringRequestBody(req => 'ok') + srv.post('/-/npm/v1/security/audits', 'ok').reply(200, { + actions: [], + metadata: { + vulnerabilities: { } + } + }) + return common.npm([ + 'audit', 'fix', + '--package-lock-only', + '--json', + '--registry', common.registry, + '--cache', path.join(testDir, 'npm-cache') + ], EXEC_OPTS).then(([code, stdout, stderr]) => { + t.equal(code, 0, 'exited OK') + t.comment(stderr) + t.similar(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'gooddep', + version: '1.0.0' + }] + }, 'nothing to update') + }) + }) + }) +}) + +test('cleanup', t => { + return rimraf(testDir) +}) diff --git a/deps/npm/test/tap/auto-prune.js b/deps/npm/test/tap/auto-prune.js new file mode 100644 index 0000000000..3fa5d5d05b --- /dev/null +++ b/deps/npm/test/tap/auto-prune.js @@ -0,0 +1,147 @@ +'use strict' +const path = require('path') +const test = require('tap').test +const mr = require('npm-registry-mock') +const Tacks = require('tacks') +const File = Tacks.File +const Dir = Tacks.Dir +const common = require('../common-tap.js') + +const basedir = path.join(__dirname, path.basename(__filename, '.js')) +const testdir = path.join(basedir, 'testdir') +const cachedir = path.join(basedir, 'cache') +const globaldir = path.join(basedir, 'global') +const tmpdir = path.join(basedir, 'tmp') + +const conf = { + cwd: testdir, + env: Object.assign({}, process.env, { + npm_config_cache: cachedir, + npm_config_tmp: tmpdir, + npm_config_prefix: globaldir, + npm_config_registry: common.registry, + npm_config_loglevel: 'warn' + }) +} + +let server +const fixture = new Tacks(Dir({ + cache: Dir(), + global: Dir(), + tmp: Dir(), + testdir: Dir({ + node_modules: Dir({ + minimist: Dir({ + 'package.json': File({ + _integrity: 'sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=', + _resolved: 'https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz', + name: 'minimist', + version: '0.0.8' + }) + }), + mkdirp: Dir({ + 'package.json': File({ + _integrity: 'sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=', + _resolved: 'https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz', + dependencies: { + minimist: '0.0.8' + }, + name: 'mkdirp', + version: '0.5.1' + }) + }), + null: Dir({ + 'package.json': File({ + _integrity: 'sha1-WoIdUnAxMlyG06AasQFzKgkfoew=', + _resolved: 'https://registry.npmjs.org/null/-/null-1.0.1.tgz', + _spec: 'null', + name: 'null', + version: '1.0.1' + }) + }) + }), + 'package-lock.json': File({ + name: 'with-lock', + version: '1.0.0', + lockfileVersion: 1, + requires: true, + dependencies: { + minimist: { + version: '0.0.8', + resolved: 'https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz', + integrity: 'sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=' + }, + mkdirp: { + version: '0.5.1', + resolved: 'https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz', + integrity: 'sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=', + requires: { + minimist: '0.0.8' + } + } + } + }), + 'package.json': File({ + name: 'with-lock', + version: '1.0.0', + dependencies: { + mkdirp: '^0.5.1' + } + }) + }) +})) + +function setup () { + cleanup() + fixture.create(basedir) +} + +function cleanup () { + fixture.remove(basedir) +} + +test('setup', function (t) { + setup() + mr({port: common.port, throwOnUnmatched: true}, function (err, s) { + if (err) throw err + server = s + t.done() + }) +}) + +test('auto-prune w/ package-lock', function (t) { + common.npm(['install', '--dry-run', '--json'], conf, function (err, code, stdout, stderr) { + if (err) throw err + t.is(code, 0, 'command ran ok') + t.comment(stderr.trim()) + const result = JSON.parse(stdout) + t.is(result.added.length, 0, 'nothing added') + t.is(result.updated.length, 0, 'nothing updated') + t.is(result.moved.length, 0, 'nothing moved') + t.is(result.failed.length, 0, 'nothing failed') + t.is(result.removed.length, 1, 'pruned 1') + t.like(result, {'removed': [{'name': 'null'}]}, 'pruned the right one') + t.done() + }) +}) + +test('auto-prune w/ --no-package-lock', function (t) { + common.npm(['install', '--dry-run', '--json', '--no-package-lock'], conf, function (err, code, stdout, stderr) { + if (err) throw err + t.is(code, 0, 'command ran ok') + t.comment(stderr.trim()) + const result = JSON.parse(stdout) + t.is(result.added.length, 0, 'nothing added') + t.is(result.updated.length, 0, 'nothing updated') + t.is(result.moved.length, 0, 'nothing moved') + t.is(result.failed.length, 0, 'nothing failed') + t.is(result.removed.length, 0, 'nothing pruned') + t.done() + }) +}) + +test('cleanup', function (t) { + server.close() + cleanup() + t.done() +}) diff --git a/deps/npm/test/tap/bugs.js b/deps/npm/test/tap/bugs.js index 8b992fd7be..4d2ee37e13 100644 --- a/deps/npm/test/tap/bugs.js +++ b/deps/npm/test/tap/bugs.js @@ -14,7 +14,7 @@ var opts = { cwd: __dirname } test('setup', function (t) { var s = '#!/usr/bin/env bash\n' + - 'echo \"$@\" > ' + JSON.stringify(__dirname) + '/_output\n' + 'echo "$@" > ' + JSON.stringify(__dirname) + '/_output\n' fs.writeFileSync(join(__dirname, '/_script.sh'), s, 'ascii') fs.chmodSync(join(__dirname, '/_script.sh'), '0755') t.pass('made script') diff --git a/deps/npm/test/tap/builtin-config.js b/deps/npm/test/tap/builtin-config.js index 22a447c9cf..b960ed0383 100644 --- a/deps/npm/test/tap/builtin-config.js +++ b/deps/npm/test/tap/builtin-config.js @@ -31,12 +31,12 @@ test('setup', function (t) { test('install npm into first folder', function (t) { t.plan(1) var args = ['install', npm, '-g', - '--prefix=' + folder + '/first', - '--ignore-scripts', - '--cache=' + folder + '/cache', - '--tmp=' + folder + '/tmp', - '--loglevel=warn', - '--progress'] + '--prefix=' + folder + '/first', + '--ignore-scripts', + '--cache=' + folder + '/cache', + '--tmp=' + folder + '/tmp', + '--loglevel=warn', + '--progress'] common.npm(args, {}, function (er, code) { if (er) throw er t.equal(code, 0) @@ -47,17 +47,17 @@ test('install npm into first folder', function (t) { test('write npmrc file', function (t) { t.plan(1) common.npm(['explore', 'npm', '-g', - '--prefix=' + folder + '/first', - '--cache=' + folder + '/cache', - '--tmp=' + folder + '/tmp', - '--', node, __filename, 'write-builtin', process.pid - ], - {'stdio': 'inherit'}, - function (er, code) { - if (er) throw er - t.equal(code, 0) - t.end() - }) + '--prefix=' + folder + '/first', + '--cache=' + folder + '/cache', + '--tmp=' + folder + '/tmp', + '--', node, __filename, 'write-builtin', process.pid + ], + {'stdio': 'inherit'}, + function (er, code) { + if (er) throw er + t.equal(code, 0) + t.end() + }) }) test('use first npm to install second npm', function (t) { @@ -91,11 +91,11 @@ test('use first npm to install second npm', function (t) { ], {} ) - .on('error', function (er) { throw er }) - .on('close', function (code) { - t.equal(code, 0, 'second npm install') - t.end() - }) + .on('error', function (er) { throw er }) + .on('close', function (code) { + t.equal(code, 0, 'second npm install') + t.end() + }) } ) }) @@ -103,31 +103,31 @@ test('use first npm to install second npm', function (t) { test('verify that the builtin config matches', function (t) { t.plan(3) common.npm([ 'root', '-g', - '--prefix=' + folder + '/first', - '--cache=' + folder + '/cache', - '--tmp=' + folder + '/tmp' - ], {}, - function (er, code, so) { - if (er) throw er - t.equal(code, 0) - var firstRoot = so.trim() - common.npm([ 'root', '-g', - '--prefix=' + folder + '/second', - '--cache=' + folder + '/cache', - '--tmp=' + folder + '/tmp' - ], {}, - function (er, code, so) { - if (er) throw er - t.equal(code, 0) - var secondRoot = so.trim() - var firstRc = path.resolve(firstRoot, 'npm', 'npmrc') - var secondRc = path.resolve(secondRoot, 'npm', 'npmrc') - var firstData = fs.readFileSync(firstRc, 'utf8').split(/\r?\n/) - var secondData = fs.readFileSync(secondRc, 'utf8').split(/\r?\n/) - t.isDeeply(firstData, secondData) - t.end() - }) - }) + '--prefix=' + folder + '/first', + '--cache=' + folder + '/cache', + '--tmp=' + folder + '/tmp' + ], {}, + function (er, code, so) { + if (er) throw er + t.equal(code, 0) + var firstRoot = so.trim() + common.npm([ 'root', '-g', + '--prefix=' + folder + '/second', + '--cache=' + folder + '/cache', + '--tmp=' + folder + '/tmp' + ], {}, + function (er, code, so) { + if (er) throw er + t.equal(code, 0) + var secondRoot = so.trim() + var firstRc = path.resolve(firstRoot, 'npm', 'npmrc') + var secondRc = path.resolve(secondRoot, 'npm', 'npmrc') + var firstData = fs.readFileSync(firstRc, 'utf8').split(/\r?\n/) + var secondData = fs.readFileSync(secondRc, 'utf8').split(/\r?\n/) + t.isDeeply(firstData, secondData) + t.end() + }) + }) }) test('clean', function (t) { diff --git a/deps/npm/test/tap/bundled-dependencies-no-pkgjson.js b/deps/npm/test/tap/bundled-dependencies-no-pkgjson.js deleted file mode 100644 index a7056408a9..0000000000 --- a/deps/npm/test/tap/bundled-dependencies-no-pkgjson.js +++ /dev/null @@ -1,55 +0,0 @@ -var test = require('tap').test -var path = require('path') -var fs = require('graceful-fs') - -var mkdirp = require('mkdirp') -var rimraf = require('rimraf') -var common = require('../common-tap.js') - -var dir = path.resolve(__dirname, 'bundled-dependencies-no-pkgjson') -var pkg = path.resolve(dir, 'pkg-with-bundled-dep') -var dep = path.resolve(pkg, 'node_modules', 'a-bundled-dep') - -var pkgJson = JSON.stringify({ - name: 'pkg-with-bundled-dep', - version: '1.0.0', - dependencies: { - }, - bundledDependencies: [ - 'a-bundled-dep' - ] -}, null, 2) + '\n' -var packed - -test('setup', function (t) { - rimraf.sync(dir) - mkdirp.sync(path.join(dir, 'node_modules')) - mkdirp.sync(dep) - - fs.writeFileSync(path.resolve(pkg, 'package.json'), pkgJson) - fs.writeFileSync(path.resolve(dep, 'index.js'), '') - common.npm(['pack', pkg], {cwd: dir}, function (err, code, stdout, stderr) { - if (err) throw err - t.is(code, 0, 'packed ok') - packed = stdout.trim() - t.comment(stderr) - t.end() - }) -}) - -test('proper error on bundled dep with no package.json', function (t) { - t.plan(2) - var npmArgs = ['install', packed] - - common.npm(npmArgs, { cwd: dir }, function (err, code, stdout, stderr) { - if (err) throw err - t.notEqual(code, 0, 'npm ended in error') - t.like(stderr, /ENOENT/, 'ENOENT should be in stderr') - t.end() - }) -}) - -test('cleanup', function (t) { - rimraf.sync(dir) - t.end() -}) diff --git a/deps/npm/test/tap/cache-add-unpublished.js b/deps/npm/test/tap/cache-add-unpublished.js index 0d39ad815a..8966e43ae4 100644 --- a/deps/npm/test/tap/cache-add-unpublished.js +++ b/deps/npm/test/tap/cache-add-unpublished.js @@ -29,7 +29,7 @@ test('cache add', function (t) { function setup (cb) { var s = require('http').createServer(function (req, res) { res.statusCode = 404 - res.end('{\"error\":\"not_found\"}\n') + res.end('{"error":"not_found"}\n') }) s.listen(1337, function () { cb(null, s) diff --git a/deps/npm/test/tap/ci.js b/deps/npm/test/tap/ci.js new file mode 100644 index 0000000000..a523f87623 --- /dev/null +++ b/deps/npm/test/tap/ci.js @@ -0,0 +1,304 @@ +'use strict' + +const BB = require('bluebird') + +const common = BB.promisifyAll(require('../common-tap.js')) +const fs = BB.promisifyAll(require('fs')) +const mr = BB.promisify(require('npm-registry-mock')) +const path = require('path') +const rimraf = BB.promisify(require('rimraf')) +const Tacks = require('tacks') +const test = require('tap').test + +const Dir = Tacks.Dir +const File = Tacks.File +const testDir = path.join(__dirname, 'ci') + +const EXEC_OPTS = { cwd: testDir } + +const PKG = { + name: 'top', + version: '1.2.3', + dependencies: { + optimist: '0.6.0', + clean: '2.1.6' + } +} +let RAW_LOCKFILE +let SERVER +let TREE + +function scrubFrom (tree) { + // npm ci and npm i write different `from` fields for dependency deps. This + // is fine any ok, but it messes with `t.deepEqual` comparisons. + function _scrubFrom (deps) { + Object.keys(deps).forEach((k) => { + deps[k].from = '' + if (deps[k].dependencies) { _scrubFrom(deps[k].dependencies) } + }) + } + tree.dependencies && _scrubFrom(tree.dependencies) +} + +test('setup', () => { + const fixture = new Tacks(Dir({ + 'package.json': File(PKG) + })) + fixture.create(testDir) + return mr({port: common.port}) + .then((server) => { + SERVER = server + return common.npm([ + 'install', + '--registry', common.registry + ], EXEC_OPTS) + .then(() => fs.readFileAsync( + path.join(testDir, 'package-lock.json'), + 'utf8') + ) + .then((lock) => { + RAW_LOCKFILE = lock + }) + .then(() => common.npm(['ls', '--json'], EXEC_OPTS)) + .then((ret) => { + TREE = scrubFrom(JSON.parse(ret[1])) + }) + }) +}) + +test('basic installation', (t) => { + const fixture = new Tacks(Dir({ + 'package.json': File(PKG), + 'package-lock.json': File(RAW_LOCKFILE) + })) + return rimraf(testDir) + .then(() => fixture.create(testDir)) + .then(() => common.npm([ + 'ci', + '--registry', common.registry, + '--loglevel', 'warn' + ], EXEC_OPTS)) + .then((ret) => { + const code = ret[0] + const stdout = ret[1] + const stderr = ret[2] + t.equal(code, 0, 'command completed without error') + t.equal(stdout.trim(), '', 'no output on stdout') + t.match( + stderr.trim(), + /^added 6 packages in \d+(?:\.\d+)?s$/, + 'no warnings on stderr, and final output has right number of packages' + ) + return fs.readdirAsync(path.join(testDir, 'node_modules')) + }) + .then((modules) => { + t.deepEqual(modules.sort(), [ + 'async', 'checker', 'clean', 'minimist', 'optimist', 'wordwrap' + ], 'packages installed') + return BB.all(modules.map((mod) => { + return fs.readFileAsync( + path.join(testDir, 'node_modules', mod, 'package.json') + ) + .then((f) => JSON.parse(f)) + .then((pkgjson) => { + t.equal(pkgjson.name, mod, `${mod} package name correct`) + t.match( + pkgjson._integrity, + /sha\d+-[a-z0-9=+/]+$/i, + `${mod} pkgjson has _integrity` + ) + t.match( + pkgjson._resolved, + new RegExp(`http.*/-/${mod}-${pkgjson.version}.tgz`), + `${mod} pkgjson has correct _resolved` + ) + t.match( + pkgjson._from, + new RegExp(`${mod}@.*`), + `${mod} pkgjson has _from field` + ) + }) + })) + }) + .then(() => fs.readFileAsync( + path.join(testDir, 'package-lock.json'), + 'utf8') + ) + .then((lock) => t.equal(lock, RAW_LOCKFILE, 'package-lock.json unchanged')) + .then(() => common.npm(['ls', '--json'], EXEC_OPTS)) + .then((ret) => { + const lsResult = JSON.parse(ret[1]) + t.equal(ret[0], 0, 'ls exited successfully') + t.deepEqual(scrubFrom(lsResult), TREE, 'tree matches one from `install`') + }) +}) + +test('supports npm-shrinkwrap.json as well', (t) => { + const fixture = new Tacks(Dir({ + 'package.json': File(PKG), + 'npm-shrinkwrap.json': File(RAW_LOCKFILE) + })) + return rimraf(testDir) + .then(() => fixture.create(testDir)) + .then(() => common.npm([ + 'ci', + '--registry', common.registry, + '--loglevel', 'warn' + ], EXEC_OPTS)) + .then((ret) => { + const code = ret[0] + const stdout = ret[1] + const stderr = ret[2] + t.equal(code, 0, 'command completed without error') + t.equal(stdout.trim(), '', 'no output on stdout') + t.match( + stderr.trim(), + /^added 6 packages in \d+(?:\.\d+)?s$/, + 'no warnings on stderr, and final output has right number of packages' + ) + }) + .then(() => common.npm(['ls', '--json'], EXEC_OPTS)) + .then((ret) => { + t.equal(ret[0], 0, 'ls exited successfully') + t.deepEqual( + scrubFrom(JSON.parse(ret[1])), + TREE, + 'tree matches one from `install`' + ) + }) + .then(() => fs.readFileAsync( + path.join(testDir, 'npm-shrinkwrap.json'), + 'utf8') + ) + .then((lock) => t.equal(lock, RAW_LOCKFILE, 'npm-shrinkwrap.json unchanged')) + .then(() => fs.readdirAsync(path.join(testDir))) + .then((files) => t.notOk( + files.some((f) => f === 'package-lock.json'), + 'no package-lock.json created' + )) +}) + +test('removes existing node_modules/ before installing', (t) => { + const fixture = new Tacks(Dir({ + 'package.json': File(PKG), + 'package-lock.json': File(RAW_LOCKFILE), + 'node_modules': Dir({ + foo: Dir({ + 'index.js': File('"hello world"') + }) + }) + })) + return rimraf(testDir) + .then(() => fixture.create(testDir)) + .then(() => common.npm([ + 'ci', + '--registry', common.registry, + '--loglevel', 'warn' + ], EXEC_OPTS)) + .then((ret) => { + const code = ret[0] + const stdout = ret[1] + const stderr = ret[2] + t.equal(code, 0, 'command completed without error') + t.equal(stdout.trim(), '', 'no output on stdout') + t.match( + stderr.trim(), + /^npm.*WARN.*removing existing node_modules/, + 'user warned that existing node_modules were removed' + ) + return fs.readdirAsync(path.join(testDir, 'node_modules')) + }) + .then((modules) => { + t.deepEqual(modules.sort(), [ + 'async', 'checker', 'clean', 'minimist', 'optimist', 'wordwrap' + ], 'packages installed, with old node_modules dir gone') + }) + .then(() => common.npm(['ls'], EXEC_OPTS)) + .then((ret) => t.equal(ret[0], 0, 'ls exited successfully')) + .then(() => fs.readFileAsync( + path.join(testDir, 'package-lock.json'), + 'utf8') + ) + .then((lock) => t.equal(lock, RAW_LOCKFILE, 'package-lock.json unchanged')) +}) + +test('installs all package types correctly') + +test('errors if package-lock.json missing', (t) => { + const fixture = new Tacks(Dir({ + 'package.json': File(PKG) + })) + return rimraf(testDir) + .then(() => fixture.create(testDir)) + .then(() => common.npm([ + 'ci', + '--registry', common.registry, + '--loglevel', 'warn' + ], EXEC_OPTS)) + .then((ret) => { + const code = ret[0] + const stdout = ret[1] + const stderr = ret[2] + t.equal(code, 1, 'command errored') + t.equal(stdout.trim(), '', 'no output on stdout') + t.match( + stderr.trim(), + /can only install packages with an existing package-lock/i, + 'user informed about the issue' + ) + return fs.readdirAsync(path.join(testDir)) + }) + .then((dir) => { + t.notOk(dir.some((f) => f === 'node_modules'), 'no node_modules installed') + t.notOk( + dir.some((f) => f === 'package-lock.json'), + 'no package-lock.json created' + ) + }) +}) + +test('errors if package-lock.json invalid', (t) => { + const badJson = JSON.parse(RAW_LOCKFILE) + delete badJson.dependencies.optimist + const fixture = new Tacks(Dir({ + 'package.json': File(PKG), + 'package-lock.json': File(badJson) + })) + return rimraf(testDir) + .then(() => fixture.create(testDir)) + .then(() => common.npm([ + 'ci', + '--registry', common.registry, + '--loglevel', 'warn' + ], EXEC_OPTS)) + .then((ret) => { + const code = ret[0] + const stdout = ret[1] + const stderr = ret[2] + t.equal(code, 1, 'command errored') + t.equal(stdout.trim(), '', 'no output on stdout') + t.match( + stderr.trim(), + /can only install packages when your package.json/i, + 'user informed about the issue' + ) + return fs.readdirAsync(path.join(testDir)) + }) + .then((dir) => { + t.notOk(dir.some((f) => f === 'node_modules'), 'no node_modules installed') + }) + .then(() => fs.readFileAsync( + path.join(testDir, 'package-lock.json'), + 'utf8') + ) + .then((lock) => t.deepEqual( + JSON.parse(lock), + badJson, + 'bad package-lock.json left unchanged') + ) +}) + +test('cleanup', () => { + SERVER.close() + return rimraf(testDir) +}) diff --git a/deps/npm/test/tap/config-basic.js b/deps/npm/test/tap/config-basic.js index 2787f81371..139b8e92f8 100644 --- a/deps/npm/test/tap/config-basic.js +++ b/deps/npm/test/tap/config-basic.js @@ -4,7 +4,6 @@ var common = require('./00-config-setup.js') var path = require('path') var projectData = { - 'legacy-bundling': true } var ucData = common.ucData diff --git a/deps/npm/test/tap/config-builtin.js b/deps/npm/test/tap/config-builtin.js index 038f47dd12..885d099a1f 100644 --- a/deps/npm/test/tap/config-builtin.js +++ b/deps/npm/test/tap/config-builtin.js @@ -15,7 +15,6 @@ var biData = { 'builtin-config': true } var cli = { foo: 'bar', heading: 'foo', 'git-tag-version': false } var projectData = { - 'legacy-bundling': true } var expectList = [ diff --git a/deps/npm/test/tap/config-envReplace.js b/deps/npm/test/tap/config-envReplace.js new file mode 100644 index 0000000000..0b4f628d67 --- /dev/null +++ b/deps/npm/test/tap/config-envReplace.js @@ -0,0 +1,57 @@ +/* eslint-disable no-template-curly-in-string */ + +const fs = require('fs') +const mkdirp = require('mkdirp') +const rimraf = require('rimraf') +const path = require('path') +const ini = require('ini') +const test = require('tap').test +const npmconf = require('../../lib/config/core.js') + +const packagePath = path.resolve(__dirname, 'config-envReplace') + +const packageJsonFile = JSON.stringify({ + name: 'config-envReplace' +}) + +const inputConfigFile = [ + 'registry=${NPM_REGISTRY_URL}', + '//${NPM_REGISTRY_HOST}/:_authToken=${NPM_AUTH_TOKEN}', + 'always-auth=true', + '' +].join('\n') + +const expectConfigFile = [ + 'registry=http://my.registry.com/', + '//my.registry.com/:_authToken=xxxxxxxxxxxxxxx', + 'always-auth=true', + '' +].join('\n') + +test('environment variables replacing in configs', function (t) { + process.env = Object.assign(process.env, { + NPM_REGISTRY_URL: 'http://my.registry.com/', + NPM_REGISTRY_HOST: 'my.registry.com', + NPM_AUTH_TOKEN: 'xxxxxxxxxxxxxxx' + }) + mkdirp.sync(packagePath) + const packageJsonPath = path.resolve(packagePath, 'package.json') + const configPath = path.resolve(packagePath, '.npmrc') + fs.writeFileSync(packageJsonPath, packageJsonFile) + fs.writeFileSync(configPath, inputConfigFile) + + const originalCwdPath = process.cwd() + process.chdir(packagePath) + npmconf.load(function (error, conf) { + if (error) throw error + + const foundConfigFile = ini.stringify(conf.sources.project.data) + t.same(ini.parse(foundConfigFile), ini.parse(expectConfigFile)) + + fs.unlinkSync(packageJsonPath) + fs.unlinkSync(configPath) + rimraf.sync(packagePath) + process.chdir(originalCwdPath) + t.end() + }) +}) diff --git a/deps/npm/test/tap/config-list.js b/deps/npm/test/tap/config-list.js index b06dc154b2..05402d4bbe 100644 --- a/deps/npm/test/tap/config-list.js +++ b/deps/npm/test/tap/config-list.js @@ -6,7 +6,7 @@ var mkdirp = require('mkdirp') var common = require('../common-tap.js') var pkg = path.resolve(__dirname, 'config-list') -var opts = { cwd: pkg } +var opts = { cwd: pkg, env: common.emptyEnv() } var npmrc = path.resolve(pkg, '.npmrc') var npmrcContents = ` _private=private; diff --git a/deps/npm/test/tap/config-meta.js b/deps/npm/test/tap/config-meta.js index f667077a1a..527487f201 100644 --- a/deps/npm/test/tap/config-meta.js +++ b/deps/npm/test/tap/config-meta.js @@ -64,7 +64,7 @@ test('get lines', function (t) { var literal = m.match(/^[''].+?['']/) if (literal) { m = literal[0].slice(1, -1) - if (!m.match(/^\_/) && m !== 'argv') { + if (!m.match(/^_/) && m !== 'argv') { CONFS[m] = { file: f, line: i @@ -117,14 +117,14 @@ test('check configs', function (t) { } types.forEach(function (c) { - if (!c.match(/^\_/) && c !== 'argv' && !c.match(/^versions?$/) && c !== 'ham-it-up') { + if (!c.match(/^_/) && c !== 'argv' && !c.match(/^versions?$/) && c !== 'ham-it-up') { t.ok(DOC[c], 'defined type should be documented ' + c) t.ok(CONFS[c], 'defined type should be used ' + c) } }) defaults.forEach(function (c) { - if (!c.match(/^\_/) && c !== 'argv' && !c.match(/^versions?$/) && c !== 'ham-it-up') { + if (!c.match(/^_/) && c !== 'argv' && !c.match(/^versions?$/) && c !== 'ham-it-up') { t.ok(DOC[c], 'defaulted type should be documented ' + c) t.ok(CONFS[c], 'defaulted type should be used ' + c) } diff --git a/deps/npm/test/tap/correct-mkdir.js b/deps/npm/test/tap/correct-mkdir.js index a4f8659873..2c93f943ad 100644 --- a/deps/npm/test/tap/correct-mkdir.js +++ b/deps/npm/test/tap/correct-mkdir.js @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ var test = require('tap').test var assert = require('assert') var path = require('path') @@ -71,7 +72,7 @@ test('correct-mkdir: ignore ENOENTs from chownr', function (t) { } } var mock_chownr = function (path, uid, gid, cb) { - cb({code: 'ENOENT'}) + cb(Object.assign(new Error(), {code: 'ENOENT'})) } var mocks = { 'graceful-fs': mock_fs, @@ -147,7 +148,7 @@ test('correct-mkdir: SUDO_UID and SUDO_GID Windows', function (t) { } var mock_chownr = function (path, uid, gid, cb) { t.fail('chownr should not be called at all on Windows') - cb('nope') + cb(new Error('nope')) } var mocks = { 'graceful-fs': mock_fs, diff --git a/deps/npm/test/tap/debug-logs.js b/deps/npm/test/tap/debug-logs.js index 4884512429..a699735263 100644 --- a/deps/npm/test/tap/debug-logs.js +++ b/deps/npm/test/tap/debug-logs.js @@ -6,7 +6,6 @@ var glob = require('glob') var asyncMap = require('slide').asyncMap var File = Tacks.File var Dir = Tacks.Dir -var extend = Object.assign || require('util')._extend var common = require('../common-tap.js') var basedir = path.join(__dirname, path.basename(__filename, '.js')) @@ -17,7 +16,7 @@ var tmpdir = path.join(basedir, 'tmp') var conf = { cwd: testdir, - env: extend(extend({}, process.env), { + env: Object.assign({}, process.env, { npm_config_cache: cachedir, npm_config_tmp: tmpdir, npm_config_prefix: globaldir, diff --git a/deps/npm/test/tap/dist-tag.js b/deps/npm/test/tap/dist-tag.js index 62ecab2c0a..651639f32a 100644 --- a/deps/npm/test/tap/dist-tag.js +++ b/deps/npm/test/tap/dist-tag.js @@ -27,7 +27,7 @@ function mocks (server) { // add c server.get('/-/package/@scoped%2fanother/dist-tags') .reply(200, { latest: '2.0.0', a: '0.0.2', b: '0.6.0' }) - server.put('/-/package/@scoped%2fanother/dist-tags/c', '\"7.7.7\"') + server.put('/-/package/@scoped%2fanother/dist-tags/c', '"7.7.7"') .reply(200, { latest: '7.7.7', a: '0.0.2', b: '0.6.0', c: '7.7.7' }) // set same version diff --git a/deps/npm/test/tap/doctor.js b/deps/npm/test/tap/doctor.js index fa1a5fad1c..26c74833e2 100644 --- a/deps/npm/test/tap/doctor.js +++ b/deps/npm/test/tap/doctor.js @@ -1,5 +1,5 @@ 'use strict' - +/* eslint-disable camelcase */ const common = require('../common-tap.js') const http = require('http') const mr = require('npm-registry-mock') diff --git a/deps/npm/test/tap/gently-rm-cmdshims.js b/deps/npm/test/tap/gently-rm-cmdshims.js index ea1f47a0dd..304c6956bd 100644 --- a/deps/npm/test/tap/gently-rm-cmdshims.js +++ b/deps/npm/test/tap/gently-rm-cmdshims.js @@ -1,4 +1,5 @@ 'use strict' +/* eslint-disable camelcase */ var path = require('path') var fs = require('graceful-fs') var test = require('tap').test @@ -127,30 +128,30 @@ test('remove-cmd-shims', function (t) { var gentlyRm = require('../../lib/utils/gently-rm.js') runAll([ [gentlyRm, doremove_example_cmd, true, doremove_module], - [gentlyRm, doremove_example_cygwin, true, doremove_module] ], - function () { - fs.stat(doremove_example_cmd, function (er) { - t.is(er && er.code, 'ENOENT', 'cmd-shim was removed') - }) - fs.stat(doremove_example_cygwin, function (er) { - t.is(er && er.code, 'ENOENT', 'cmd-shim cygwin script was removed') - }) - }) + [gentlyRm, doremove_example_cygwin, true, doremove_module] ], + function () { + fs.stat(doremove_example_cmd, function (er) { + t.is(er && er.code, 'ENOENT', 'cmd-shim was removed') + }) + fs.stat(doremove_example_cygwin, function (er) { + t.is(er && er.code, 'ENOENT', 'cmd-shim cygwin script was removed') + }) + }) }) test('dont-remove-cmd-shims', function (t) { t.plan(2) var gentlyRm = require('../../lib/utils/gently-rm.js') runAll([ [gentlyRm, dontremove_example_cmd, true, dontremove_module], - [gentlyRm, dontremove_example_cygwin, true, dontremove_module] ], - function () { - fs.stat(dontremove_example_cmd, function (er) { - t.is(er, null, 'cmd-shim was not removed') - }) - fs.stat(dontremove_example_cygwin, function (er) { - t.is(er, null, 'cmd-shim cygwin script was not removed') - }) - }) + [gentlyRm, dontremove_example_cygwin, true, dontremove_module] ], + function () { + fs.stat(dontremove_example_cmd, function (er) { + t.is(er, null, 'cmd-shim was not removed') + }) + fs.stat(dontremove_example_cygwin, function (er) { + t.is(er, null, 'cmd-shim cygwin script was not removed') + }) + }) }) test('cleanup', function (t) { diff --git a/deps/npm/test/tap/gently-rm-linked-module.js b/deps/npm/test/tap/gently-rm-linked-module.js index a9804cd792..877c683c9f 100644 --- a/deps/npm/test/tap/gently-rm-linked-module.js +++ b/deps/npm/test/tap/gently-rm-linked-module.js @@ -9,7 +9,6 @@ var Tacks = require('tacks') var File = Tacks.File var Dir = Tacks.Dir var Symlink = Tacks.Symlink -var extend = Object.assign || require('util')._extend var isWindows = require('../../lib/utils/is-windows.js') var base = resolve(__dirname, basename(__filename, '.js')) @@ -35,7 +34,7 @@ var workingDir = resolve(base, 'working-dir') var toInstall = resolve(base, 'test-module') var linkedGlobal = resolve(base, 'linked-global-dir') -var env = extend({}, process.env) +var env = Object.assign({}, process.env) // We set the global install location via env var here // instead of passing it in via `--prefix` because diff --git a/deps/npm/test/tap/git-npmignore.js b/deps/npm/test/tap/git-npmignore.js index 1fe2ca24e6..19d014c3d9 100644 --- a/deps/npm/test/tap/git-npmignore.js +++ b/deps/npm/test/tap/git-npmignore.js @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ var child_process = require('child_process') var readdir = require('graceful-fs').readdirSync var path = require('path') diff --git a/deps/npm/test/tap/help.js b/deps/npm/test/tap/help.js index 0b8c22a7b8..bc66a92298 100644 --- a/deps/npm/test/tap/help.js +++ b/deps/npm/test/tap/help.js @@ -2,7 +2,7 @@ var test = require('tap').test var common = require('../common-tap') test('npm food', function (t) { - common.npm('food', {}, function (err, code, stdout, stderr) { + common.npm('docz', {}, function (err, code, stdout, stderr) { if (err) throw err t.equal(code, 1, 'command ran with error') diff --git a/deps/npm/test/tap/hook.js b/deps/npm/test/tap/hook.js new file mode 100644 index 0000000000..d50b7b1221 --- /dev/null +++ b/deps/npm/test/tap/hook.js @@ -0,0 +1,243 @@ +'use strict' + +const common = require('../common-tap.js') +const test = require('tap').test + +test('hook add', (t) => { + let body + return common.withServer(server => { + server.filteringRequestBody(bod => { + body = JSON.parse(bod) + t.deepEqual(body, { + type: 'owner', + name: 'zkat', + endpoint: 'https://example.com', + secret: 'sekrit' + }, 'request sent correct body') + return true + }) + .post('/-/npm/v1/hooks/hook', true) + .reply(201, { + name: 'zkat', + type: 'owner', + endpoint: 'https://example.com' + }) + return common.npm([ + 'hook', 'add', '~zkat', 'https://example.com', 'sekrit', + '--registry', server.registry + ], {}).then(([code, stdout, stderr]) => { + t.comment(stdout) + t.comment(stderr) + t.equal(code, 0, 'exited successfully') + t.match( + stdout.trim(), + /^\+ ~zkat.*https:\/\/example\.com$/, + 'output info about new hook' + ) + }) + }) +}) + +test('hook add --json', (t) => { + return common.withServer(server => { + server + .filteringRequestBody(() => true) + .post('/-/npm/v1/hooks/hook', true) + .reply(201, { + name: 'npm', + type: 'scope', + endpoint: 'https://example.com' + }) + return common.npm([ + 'hook', 'add', '~zkat', 'https://example.com', 'sekrit', + '--json', + '--registry', server.registry + ], {}).then(([code, stdout, stderr]) => { + t.comment(stdout) + t.comment(stderr) + t.equal(code, 0, 'exited successfully') + t.deepEqual(JSON.parse(stdout), { + name: 'npm', + type: 'scope', + endpoint: 'https://example.com' + }, 'json response data returned') + }) + }) +}) + +test('hook rm', t => { + return common.withServer(server => { + server + .delete('/-/npm/v1/hooks/hook/dead%40beef') + .reply(200, { + name: 'zkat', + type: 'owner', + endpoint: 'https://example.com', + secret: 'sekrit' + }) + return common.npm([ + 'hook', 'rm', 'dead@beef', + '--registry', server.registry + ], {}).then(([code, stdout, stderr]) => { + t.comment(stdout) + t.comment(stderr) + t.equal(code, 0, 'exited successfully') + t.match( + stdout.trim(), + /^- ~zkat.*https:\/\/example\.com$/, + 'output info about new hook' + ) + }) + }) +}) + +test('hook rm --json', t => { + return common.withServer(server => { + server + .delete('/-/npm/v1/hooks/hook/dead%40beef') + .reply(200, { + name: 'zkat', + type: 'owner', + endpoint: 'https://example.com', + secret: 'sekrit' + }) + return common.npm([ + 'hook', 'rm', 'dead@beef', + '--json', + '--registry', server.registry + ], {}).then(([code, stdout, stderr]) => { + t.comment(stdout) + t.comment(stderr) + t.equal(code, 0, 'exited successfully') + t.deepEqual(JSON.parse(stdout), { + name: 'zkat', + type: 'owner', + endpoint: 'https://example.com', + secret: 'sekrit' + }, 'json response data returned') + }) + }) +}) + +test('hook ls', t => { + const objects = [ + {id: 'foo', type: 'package', name: '@foo/pkg', endpoint: 'foo.com'}, + {id: 'bar', type: 'owner', name: 'bar', endpoint: 'bar.com'}, + {id: 'baz', type: 'scope', name: 'baz', endpoint: 'baz.com'} + ] + return common.withServer(server => { + server + .get('/-/npm/v1/hooks?package=%40npm%2Fhooks') + .reply(200, {objects}) + return common.npm([ + 'hook', 'ls', '@npm/hooks', + '--registry', server.registry + ], {}).then(([code, stdout, stderr]) => { + t.comment(stdout) + t.comment(stderr) + t.equal(code, 0, 'exited successfully') + t.match( + stdout, + /You have 3 hooks configured/, + 'message about hook count' + ) + t.match( + stdout, + /foo\s+.*\s+@foo\/pkg\s+.*\s+foo\.com/, + 'package displayed as expected' + ) + t.match( + stdout, + /bar\s+.*\s+~bar\s+.*\s+bar\.com/, + 'owner displayed as expected' + ) + t.match( + stdout, + /baz\s+.*\s+@baz\s+.*\s+baz\.com/, + 'scope displayed as expected' + ) + }) + }) +}) + +test('hook ls --json', t => { + const objects = [ + {id: 'foo'}, + {id: 'bar'}, + {id: 'baz'} + ] + return common.withServer(server => { + server + .get('/-/npm/v1/hooks?package=%40npm%2Fhooks') + .reply(200, {objects}) + return common.npm([ + 'hook', 'ls', '@npm/hooks', + '--json', + '--registry', server.registry + ], {}).then(([code, stdout, stderr]) => { + t.comment(stdout) + t.comment(stderr) + t.equal(code, 0, 'exited successfully') + t.deepEqual(JSON.parse(stdout), objects, 'objects output as json') + }) + }) +}) + +test('hook update', t => { + return common.withServer(server => { + server.filteringRequestBody(() => true) + .put('/-/npm/v1/hooks/hook/dead%40beef', true) + .reply(200, { + type: 'scope', + name: 'npm', + endpoint: 'https://example.com', + secret: 'sekrit' + }) + return common.npm([ + 'hook', 'update', 'dead@beef', 'https://example.com', 'sekrit', + '--registry', server.registry + ], {}).then(([code, stdout, stderr]) => { + t.comment(stdout) + t.comment(stderr) + t.equal(code, 0, 'exited successfully') + t.match( + stdout.trim(), + /^\+ @npm\s+.*\s+https:\/\/example\.com$/, + 'output info about updated hook' + ) + }) + }) +}) + +test('hook update --json', t => { + let body + return common.withServer(server => { + server.filteringRequestBody(bod => { + body = JSON.parse(bod) + t.deepEqual(body, { + endpoint: 'https://example.com', + secret: 'sekrit' + }, 'request sent correct body') + return true + }) + .put('/-/npm/v1/hooks/hook/dead%40beef', true) + .reply(200, { + endpoint: 'https://example.com', + secret: 'sekrit' + }) + return common.npm([ + 'hook', 'update', 'dead@beef', 'https://example.com', 'sekrit', + '--json', + '--registry', server.registry + ], {}).then(([code, stdout, stderr]) => { + t.comment(stdout) + t.comment(stderr) + t.equal(code, 0, 'exited successfully') + const json = JSON.parse(stdout) + t.deepEqual(json, { + endpoint: 'https://example.com', + secret: 'sekrit' + }, 'json response data returned') + }) + }) +}) diff --git a/deps/npm/test/tap/init-create.js b/deps/npm/test/tap/init-create.js new file mode 100644 index 0000000000..22d9090a97 --- /dev/null +++ b/deps/npm/test/tap/init-create.js @@ -0,0 +1,171 @@ +/* eslint-disable standard/no-callback-literal */ +var test = require('tap').test +var requireInject = require('require-inject') + +var npm = require('../../lib/npm.js') + +test('npm init <name>', function (t) { + var initJsonMock = function () { + t.ok(false, 'should not run initJson()') + } + initJsonMock.yes = function () { + t.ok(false, 'should not run initJson.yes()') + return false + } + var libnpxMock = function () { + return Promise.resolve() + } + libnpxMock.parseArgs = function (argv, defaultNpm) { + t.ok(argv[0].includes('node'), 'node is the first arg') + t.equals(argv[2], '--always-spawn', 'set npx opts.alwaysSpawn') + t.equals(argv[3], 'create-name', 'expands name') + t.ok(defaultNpm.endsWith('npm-cli.js'), 'passes npm bin path') + } + + npm.load({ loglevel: 'silent' }, function () { + var init = requireInject('../../lib/init', { + 'init-package-json': initJsonMock, + 'libnpx': libnpxMock + }) + + init(['name'], function () {}) + + t.end() + }) +}) + +test('npm init expands scopes', function (t) { + var libnpxMock = function () { + return Promise.resolve() + } + + npm.load({ loglevel: 'silent' }, function () { + var init = requireInject('../../lib/init', { + 'libnpx': libnpxMock + }) + + libnpxMock.parseArgs = function (argv) { + t.equals(argv[3], '@scope/create', 'expands @scope') + } + + init(['@scope'], function () {}) + + libnpxMock.parseArgs = function (argv) { + t.equals(argv[3], '@scope/create-name', 'expands @scope/name') + } + + init(['@scope/name'], function () {}) + + t.end() + }) +}) + +test('npm init expands version names', function (t) { + var libnpxMock = function () { + return Promise.resolve() + } + + npm.load({ loglevel: 'silent' }, function () { + var init = requireInject('../../lib/init', { + 'libnpx': libnpxMock + }) + + libnpxMock.parseArgs = function (argv) { + t.equals(argv[3], 'create-name@1.2.3', 'expands name@1.2.3') + } + + init(['name@1.2.3'], function () {}) + + libnpxMock.parseArgs = function (argv) { + t.equals(argv[3], 'create-name@^1.2.3', 'expands name@^1.2.3') + } + + init(['name@^1.2.3'], function () {}) + + t.end() + }) +}) + +test('npm init expands git names', function (t) { + var libnpxMock = function () { + return Promise.resolve() + } + + npm.load({ loglevel: 'silent' }, function () { + var init = requireInject('../../lib/init', { + 'libnpx': libnpxMock + }) + + libnpxMock.parseArgs = function (argv) { + t.equals(argv[3], 'user/create-foo', 'expands git repo') + } + + init(['user/foo'], function () {}) + + libnpxMock.parseArgs = function (argv) { + t.equals(argv[3], 'git+https://github.com/user/create-foo', 'expands git url') + } + + init(['git+https://github.com/user/foo'], function () {}) + + t.end() + }) +}) + +test('npm init errors on folder and tarballs', function (t) { + npm.load({ loglevel: 'silent' }, function () { + var init = require('../../lib/init') + + try { + init(['../foo/bar/'], function () {}) + } catch (e) { + t.equals(e.code, 'EUNSUPPORTED') + } + + t.throws( + () => init(['../foo/bar/'], function () {}), + /Unrecognized initializer: \.\.\/foo\/bar\// + ) + + t.throws( + () => init(['file:foo.tar.gz'], function () {}), + /Unrecognized initializer: file:foo\.tar\.gz/ + ) + + t.throws( + () => init(['http://x.com/foo.tgz'], function () {}), + /Unrecognized initializer: http:\/\/x\.com\/foo\.tgz/ + ) + + t.end() + }) +}) + +test('npm init forwards arguments', function (t) { + var libnpxMock = function () { + return Promise.resolve() + } + + npm.load({ loglevel: 'silent' }, function () { + var origArgv = process.argv + var init = requireInject('../../lib/init', { + 'libnpx': libnpxMock + }) + + libnpxMock.parseArgs = function (argv) { + process.argv = origArgv + t.same(argv.slice(4), ['a', 'b', 'c']) + } + process.argv = [ + process.argv0, + 'NPM_CLI_PATH', + 'init', + 'name', + 'a', 'b', 'c' + ] + + init(['name'], function () {}) + + t.end() + }) +}) diff --git a/deps/npm/test/tap/init-interrupt.js b/deps/npm/test/tap/init-interrupt.js index 799ff07164..b0c7643ddf 100644 --- a/deps/npm/test/tap/init-interrupt.js +++ b/deps/npm/test/tap/init-interrupt.js @@ -1,3 +1,4 @@ +/* eslint-disable standard/no-callback-literal */ // if 'npm init' is interrupted with ^C, don't report // 'init written successfully' var test = require('tap').test diff --git a/deps/npm/test/tap/install-bad-dep-format.js b/deps/npm/test/tap/install-bad-dep-format.js index 01d253c9e5..94c7d175fd 100644 --- a/deps/npm/test/tap/install-bad-dep-format.js +++ b/deps/npm/test/tap/install-bad-dep-format.js @@ -13,7 +13,7 @@ var json = { name: 'bad-dep-format', version: '0.0.0', dependencies: { - 'not-legit': 'npm:not-legit@1.0' + 'not-legit': 'bad:not-legit@1.0' } } diff --git a/deps/npm/test/tap/install-cli-only-production.js b/deps/npm/test/tap/install-cli-only-production.js index 7f46a23e15..40328d7735 100644 --- a/deps/npm/test/tap/install-cli-only-production.js +++ b/deps/npm/test/tap/install-cli-only-production.js @@ -47,9 +47,9 @@ test('setup', function (t) { JSON.stringify(dependency, null, 2) ) - mkdirp.sync(path.join(pkg, 'devDependency')) + mkdirp.sync(path.join(pkg, 'dev-dependency')) fs.writeFileSync( - path.join(pkg, 'devDependency', 'package.json'), + path.join(pkg, 'dev-dependency', 'package.json'), JSON.stringify(devDependency, null, 2) ) @@ -64,8 +64,10 @@ test('setup', function (t) { }) test('\'npm install --only=production\' should only install dependencies', function (t) { - common.npm(['install', '--only=production'], EXEC_OPTS, function (err, code) { - t.ifError(err, 'install production successful') + common.npm(['install', '--only=production'], EXEC_OPTS, function (err, code, stdout, stderr) { + if (err) throw err + t.comment('1> ' + stdout) + t.comment('2> ' + stderr) t.equal(code, 0, 'npm install did not raise error code') t.ok( JSON.parse(fs.readFileSync( diff --git a/deps/npm/test/tap/install-cli-only-shrinkwrap.js b/deps/npm/test/tap/install-cli-only-shrinkwrap.js index 17ff1ec955..aa731909d3 100644 --- a/deps/npm/test/tap/install-cli-only-shrinkwrap.js +++ b/deps/npm/test/tap/install-cli-only-shrinkwrap.js @@ -29,14 +29,14 @@ var shrinkwrap = { name: 'install-cli-only-shrinkwrap', description: 'fixture', version: '0.0.0', + lockfileVersion: 1, + requires: true, dependencies: { dependency: { - version: '0.0.0', - from: 'file:./dependency' + version: 'file:./dependency' }, 'dev-dependency': { - version: '0.0.0', - from: 'file:./dev-dependency', + version: 'file:./dev-dependency', dev: true } } @@ -55,6 +55,7 @@ var devDependency = { } test('setup', function (t) { + cleanup() setup() t.pass('setup ran') t.end() diff --git a/deps/npm/test/tap/install-contributors-count.js b/deps/npm/test/tap/install-contributors-count.js new file mode 100644 index 0000000000..52fba0fd24 --- /dev/null +++ b/deps/npm/test/tap/install-contributors-count.js @@ -0,0 +1,70 @@ +'use strict' +var path = require('path') +var test = require('tap').test +var Tacks = require('tacks') +var Dir = Tacks.Dir +var File = Tacks.File +var common = require('../common-tap.js') + +var testdir = path.resolve(__dirname, path.basename(__filename, '.js')) +var fixture = new Tacks(Dir({ + node_modules: Dir({ + a: Dir({ + 'package.json': File({ + name: 'a', + version: '1.0.0', + dependencies: { + b: '1.0.0' + } + }), + node_modules: Dir({ + b: Dir({ + 'package.json': File({ + name: 'b', + version: '1.0.0' + }) + }) + }) + }) + }), + 'b-src': Dir({ + 'package.json': File({ + name: 'b', + author: 'Author Contributor', + contributors: [ + {name: 'Author Contributor'}, + 'Another Contributor' + ], + version: '1.0.0' + }) + }) +})) + +function setup () { + cleanup() + fixture.create(testdir) +} + +function cleanup () { + fixture.remove(testdir) +} + +test('setup', function (t) { + setup() + t.end() +}) + +test('install', function (t) { + common.npm(['install', '--no-save', './b-src'], {cwd: testdir}, function (err, code, stdout, stderr) { + if (err) throw err + t.is(code, 0, 'installed successfully') + t.is(stderr, '', 'no warnings') + t.includes(stdout, 'added 1 package from 2 contributors', 'lists number of unique contributors') + t.end() + }) +}) + +test('cleanup', function (t) { + cleanup() + t.end() +}) diff --git a/deps/npm/test/tap/install-duplicate-deps-warning.js b/deps/npm/test/tap/install-duplicate-deps-warning.js index 9206fe253c..017a5cdfe1 100644 --- a/deps/npm/test/tap/install-duplicate-deps-warning.js +++ b/deps/npm/test/tap/install-duplicate-deps-warning.js @@ -8,7 +8,7 @@ var rimraf = require('rimraf') var test = require('tap').test var common = require('../common-tap.js') -var npm = npm = require('../../') +var npm = require('../../') var pkg = path.resolve(__dirname, path.basename(__filename, '.js')) diff --git a/deps/npm/test/tap/install-order.js b/deps/npm/test/tap/install-order.js index 80b3f6f45e..c4a2b1c383 100644 --- a/deps/npm/test/tap/install-order.js +++ b/deps/npm/test/tap/install-order.js @@ -1,4 +1,5 @@ 'use strict' +/* eslint-disable no-use-before-define */ var test = require('tap').test var sortActions = require('../../lib/install/diff-trees.js').sortActions var top = { diff --git a/deps/npm/test/tap/install-package-lock-only.js b/deps/npm/test/tap/install-package-lock-only.js index b117dc97e3..9d8aa8dbec 100644 --- a/deps/npm/test/tap/install-package-lock-only.js +++ b/deps/npm/test/tap/install-package-lock-only.js @@ -6,7 +6,6 @@ var mr = require('npm-registry-mock') var Tacks = require('tacks') var File = Tacks.File var Dir = Tacks.Dir -var extend = Object.assign || require('util')._extend var common = require('../common-tap.js') var basedir = path.join(__dirname, path.basename(__filename, '.js')) @@ -20,7 +19,7 @@ var nodeModulesPath = path.join(testdir, 'node_modules') var conf = { cwd: testdir, - env: extend(extend({}, process.env), { + env: Object.assign({}, process.env, { npm_config_cache: cachedir, npm_config_tmp: tmpdir, npm_config_prefix: globaldir, diff --git a/deps/npm/test/tap/install-parse-error.js b/deps/npm/test/tap/install-parse-error.js index 72d19efc25..1330195ead 100644 --- a/deps/npm/test/tap/install-parse-error.js +++ b/deps/npm/test/tap/install-parse-error.js @@ -39,7 +39,7 @@ test('failing to parse package.json should be error', function (t) { function (err, code, stdout, stderr) { if (err) throw err t.equal(code, 1, 'exit not ok') - t.similar(stderr, /npm ERR! Failed to parse json/) + t.similar(stderr, /npm ERR! JSON.parse Failed to parse json/) t.end() } ) @@ -49,4 +49,3 @@ test('cleanup', function (t) { cleanup() t.end() }) - diff --git a/deps/npm/test/tap/install-save-consistent-newlines.js b/deps/npm/test/tap/install-save-consistent-newlines.js new file mode 100644 index 0000000000..6250377445 --- /dev/null +++ b/deps/npm/test/tap/install-save-consistent-newlines.js @@ -0,0 +1,122 @@ +'use strict' + +const fs = require('graceful-fs') +const path = require('path') + +const mkdirp = require('mkdirp') +const mr = require('npm-registry-mock') +const osenv = require('osenv') +const rimraf = require('rimraf') +const test = require('tap').test + +const common = require('../common-tap.js') + +const pkg = path.join(__dirname, 'install-save-consistent-newlines') + +const EXEC_OPTS = { cwd: pkg } + +const json = { + name: 'install-save-consistent-newlines', + version: '0.0.1', + description: 'fixture' +} + +var server + +test('setup', function (t) { + setup('\n') + mr({ port: common.port }, function (er, s) { + server = s + t.end() + }) +}) + +test('\'npm install --save\' should keep the original package.json line endings (LF)', function (t) { + common.npm( + [ + '--loglevel', 'silent', + '--registry', common.registry, + '--save', + 'install', 'underscore@1.3.1' + ], + EXEC_OPTS, + function (err, code) { + t.ifError(err, 'npm ran without issue') + t.notOk(code, 'npm install exited without raising an error code') + + const pkgPath = path.resolve(pkg, 'package.json') + const pkgStr = fs.readFileSync(pkgPath, 'utf8') + + t.match(pkgStr, '\n') + t.notMatch(pkgStr, '\r') + + const pkgLockPath = path.resolve(pkg, 'package-lock.json') + const pkgLockStr = fs.readFileSync(pkgLockPath, 'utf8') + + t.match(pkgLockStr, '\n') + t.notMatch(pkgLockStr, '\r') + + t.end() + } + ) +}) + +test('\'npm install --save\' should keep the original package.json line endings (CRLF)', function (t) { + setup('\r\n') + + common.npm( + [ + '--loglevel', 'silent', + '--registry', common.registry, + '--save', + 'install', 'underscore@1.3.1' + ], + EXEC_OPTS, + function (err, code) { + t.ifError(err, 'npm ran without issue') + t.notOk(code, 'npm install exited without raising an error code') + + const pkgPath = path.resolve(pkg, 'package.json') + const pkgStr = fs.readFileSync(pkgPath, 'utf8') + + t.match(pkgStr, '\r\n') + t.notMatch(pkgStr, /[^\r]\n/) + + const pkgLockPath = path.resolve(pkg, 'package-lock.json') + const pkgLockStr = fs.readFileSync(pkgLockPath, 'utf8') + + t.match(pkgLockStr, '\r\n') + t.notMatch(pkgLockStr, /[^\r]\n/) + + t.end() + } + ) +}) + +test('cleanup', function (t) { + server.close() + cleanup() + t.end() +}) + +function cleanup () { + process.chdir(osenv.tmpdir()) + rimraf.sync(pkg) +} + +function setup (lineEnding) { + cleanup() + mkdirp.sync(path.resolve(pkg, 'node_modules')) + + var jsonStr = JSON.stringify(json, null, 2) + + if (lineEnding === '\r\n') { + jsonStr = jsonStr.replace(/\n/g, '\r\n') + } + + fs.writeFileSync( + path.join(pkg, 'package.json'), + jsonStr + ) + process.chdir(pkg) +} diff --git a/deps/npm/test/tap/install-scoped-with-bundled-dependency.js b/deps/npm/test/tap/install-scoped-with-bundled-dependency.js index 7a620dfdcd..bd197ae036 100644 --- a/deps/npm/test/tap/install-scoped-with-bundled-dependency.js +++ b/deps/npm/test/tap/install-scoped-with-bundled-dependency.js @@ -4,7 +4,6 @@ var test = require('tap').test var Tacks = require('tacks') var File = Tacks.File var Dir = Tacks.Dir -var extend = Object.assign || require('util')._extend var common = require('../common-tap.js') var basedir = path.join(__dirname, path.basename(__filename, '.js')) @@ -15,7 +14,7 @@ var tmpdir = path.join(basedir, 'tmp') var conf = { cwd: testdir, - env: extend({ + env: Object.assign({ npm_config_cache: cachedir, npm_config_tmp: tmpdir, npm_config_prefix: globaldir, diff --git a/deps/npm/test/tap/install-shrinkwrapped-git.js b/deps/npm/test/tap/install-shrinkwrapped-git.js index db22acc7f6..7bbb4f6e5f 100644 --- a/deps/npm/test/tap/install-shrinkwrapped-git.js +++ b/deps/npm/test/tap/install-shrinkwrapped-git.js @@ -1,3 +1,5 @@ +'use strict' + var fs = require('fs') var path = require('path') var resolve = path.resolve @@ -47,20 +49,30 @@ test('shrinkwrapped git dependency got updated', function (t) { t.comment('test for https://github.com/npm/npm/issues/12718') // Prepare the child package git repo with two commits - prepareChildAndGetRefs(function (refs) { + prepareChildAndGetRefs(function (err, refs) { + if (err) { throw err } chain([ // Install & shrinkwrap child package's first commit [npm.commands.install, ['git://localhost:1234/child.git#' + refs[0]]], // Backup node_modules with the first commit [fs.rename, parentNodeModulesPath, outdatedNodeModulesPath], - // Install & shrinkwrap child package's second commit - [npm.commands.install, ['git://localhost:1234/child.git#' + refs[1]]], + // Install & shrinkwrap child package's latest commit + [npm.commands.install, ['git://localhost:1234/child.git#' + refs[1].substr(0, 8)]], // Restore node_modules with the first commit [rimraf, parentNodeModulesPath], [fs.rename, outdatedNodeModulesPath, parentNodeModulesPath], // Update node_modules [npm.commands.install, []] ], function () { + const pkglock = require(path.join(parentPath, 'package-lock.json')) + t.similar(pkglock, { + dependencies: { + child: { + version: `git://localhost:1234/child.git#${refs[1]}`, + from: `git://localhost:1234/child.git#${refs[1].substr(0, 8)}` + } + } + }, 'version and from fields are correct in git-based pkglock dep') var childPackageJSON = require(path.join(parentNodeModulesPath, 'child', 'package.json')) t.equal( childPackageJSON._resolved, @@ -114,12 +126,13 @@ function prepareChildAndGetRefs (cb) { git.chainableExec(['add', 'README.md'], opts), git.chainableExec(['commit', '-m', 'Add README'], opts), git.chainableExec(['log', '--pretty=format:"%H"', '-2'], opts) - ], function () { + ], function (err) { + if (err) { return cb(err) } var gitLogStdout = arguments[arguments.length - 1] var refs = gitLogStdout[gitLogStdout.length - 1].split('\n').map(function (ref) { return ref.match(/^"(.+)"$/)[1] }).reverse() // Reverse refs order: last, first -> first, last - cb(refs) + cb(null, refs) }) } diff --git a/deps/npm/test/tap/install-test-cli-without-package-lock.js b/deps/npm/test/tap/install-test-cli-without-package-lock.js new file mode 100644 index 0000000000..ea3d75feb6 --- /dev/null +++ b/deps/npm/test/tap/install-test-cli-without-package-lock.js @@ -0,0 +1,83 @@ +var fs = require('graceful-fs') +var path = require('path') + +var mkdirp = require('mkdirp') +var osenv = require('osenv') +var rimraf = require('rimraf') +var test = require('tap').test + +var common = require('../common-tap.js') + +var pkg = path.join(__dirname, path.basename(__filename, '.js')) + +var EXEC_OPTS = { cwd: pkg } + +var json = { + name: 'install-test-cli-without-package-lock', + description: 'fixture', + version: '0.0.0', + dependencies: { + dependency: 'file:./dependency' + } +} + +var dependency = { + name: 'dependency', + description: 'fixture', + version: '0.0.0' +} + +test('setup', function (t) { + setup() + t.pass('setup ran') + t.end() +}) + +test('\'npm install-test\' should not generate package-lock.json.*', function (t) { + common.npm(['install-test'], EXEC_OPTS, function (err, code, stderr, stdout) { + if (err) throw err + t.comment(stdout.trim()) + t.comment(stderr.trim()) + t.is(code, 0, 'npm install did not raise error code') + var files = fs.readdirSync(pkg).filter(function (f) { + return f.indexOf('package-lock.json.') === 0 + }) + t.notOk( + files.length > 0, + 'package-lock.json.* should not be generated: ' + files + ) + t.end() + }) +}) + +test('cleanup', function (t) { + cleanup() + t.pass('cleaned up') + t.end() +}) + +function setup () { + mkdirp.sync(path.join(pkg, 'dependency')) + fs.writeFileSync( + path.join(pkg, 'dependency', 'package.json'), + JSON.stringify(dependency, null, 2) + ) + + mkdirp.sync(path.join(pkg, 'node_modules')) + fs.writeFileSync( + path.join(pkg, 'package.json'), + JSON.stringify(json, null, 2) + ) + + // Disable package-lock + fs.writeFileSync( + path.join(pkg, '.npmrc'), + 'package-lock=false\n' + ) + process.chdir(pkg) +} + +function cleanup () { + process.chdir(osenv.tmpdir()) + rimraf.sync(pkg) +} diff --git a/deps/npm/test/tap/install-windows-newlines.js b/deps/npm/test/tap/install-windows-newlines.js index 56ef172a29..1c69b204ad 100644 --- a/deps/npm/test/tap/install-windows-newlines.js +++ b/deps/npm/test/tap/install-windows-newlines.js @@ -67,7 +67,7 @@ test('setup', function (t) { fs.readFileSync( path.resolve(pkg, 'node_modules/cli-dependency/hashbang.js'), 'utf8' - ).includes('\r\n'), + ).includes('node\r\n'), 'hashbang dependency cli newlines converted' ) t.ok( diff --git a/deps/npm/test/tap/install-with-dev-dep-duplicate.js b/deps/npm/test/tap/install-with-dev-dep-duplicate.js index 41eb823311..2d31b8fad7 100644 --- a/deps/npm/test/tap/install-with-dev-dep-duplicate.js +++ b/deps/npm/test/tap/install-with-dev-dep-duplicate.js @@ -8,7 +8,7 @@ var rimraf = require('rimraf') var test = require('tap').test var common = require('../common-tap.js') -var npm = npm = require('../../') +var npm = require('../../') var pkg = path.resolve(__dirname, 'dev-dep-duplicate') diff --git a/deps/npm/test/tap/invalid-dep-version-filtering.js b/deps/npm/test/tap/invalid-dep-version-filtering.js index a4a872f54e..19ab5d209d 100644 --- a/deps/npm/test/tap/invalid-dep-version-filtering.js +++ b/deps/npm/test/tap/invalid-dep-version-filtering.js @@ -14,7 +14,7 @@ var fixture = new Tacks(Dir({ cache: Dir(), node_modules: Dir(), tarballs: Dir({ - 'pkgA.tgz': File(new Buffer( + 'pkgA.tgz': File(Buffer.from( '1f8b0800000000000003edcfcf0a0221100670cf3ec5e0396cfcb703bd8d' + '842cb5e4ca5a5da2776f5da153b78408fc5d3e6684e133f9e3e4c7b04f35' + 'e539cf9135868883b5509206b725ea3a6f9c01a634598d8e48134365d0e0' + @@ -23,7 +23,7 @@ var fixture = new Tacks(Dir({ '0000', 'hex' )), - 'pkgB1.tgz': File(new Buffer( + 'pkgB1.tgz': File(Buffer.from( '1f8b0800000000000003edcfc10a0221140550d77ec5c375d8d3d111fa1b' + '0b196ac891b16913fd7be308adda2544f0cee6e25d3caec99f463f847daa' + '292f798aac3144ec8d8192aeb75ba2aeef8ded8029ed8c46eb1c1a86aa43' + diff --git a/deps/npm/test/tap/is-fs-access-available.js b/deps/npm/test/tap/is-fs-access-available.js index 3c1b30ed04..2e5c7edc98 100644 --- a/deps/npm/test/tap/is-fs-access-available.js +++ b/deps/npm/test/tap/is-fs-access-available.js @@ -3,13 +3,12 @@ var fs = require('fs') var test = require('tap').test var requireInject = require('require-inject') var semver = require('semver') -var extend = Object.assign || require('util')._extend var globalProcess = global.process function loadIsFsAccessAvailable (newProcess, newFs) { - global.process = extend(extend({}, global.process), newProcess) - var mocks = {fs: extend(extend({}, fs), newFs)} + global.process = Object.assign({}, global.process, newProcess) + var mocks = {fs: Object.assign({}, fs, newFs)} var isFsAccessAvailable = requireInject('../../lib/install/is-fs-access-available.js', mocks) global.process = globalProcess return isFsAccessAvailable diff --git a/deps/npm/test/tap/link.js b/deps/npm/test/tap/link.js index 8a4275e19e..88f3caed79 100644 --- a/deps/npm/test/tap/link.js +++ b/deps/npm/test/tap/link.js @@ -29,7 +29,7 @@ var readJSON = { description: '', main: 'index.js', scripts: { - test: 'echo \"Error: no test specified\" && exit 1' + test: 'echo "Error: no test specified" && exit 1' }, author: '', license: 'ISC' @@ -41,7 +41,7 @@ var readScopedJSON = { description: '', main: 'index.js', scripts: { - test: 'echo \"Error: no test specified\" && exit 1' + test: 'echo "Error: no test specified" && exit 1' }, author: '', license: 'ISC' @@ -53,7 +53,7 @@ var installJSON = { description: '', main: 'index.js', scripts: { - test: 'echo \"Error: no test specified\" && exit 1' + test: 'echo "Error: no test specified" && exit 1' }, author: '', license: 'ISC' @@ -65,7 +65,7 @@ var insideInstallJSON = { description: '', main: 'index.js', scripts: { - test: 'echo \"Error: no test specified\" && exit 1' + test: 'echo "Error: no test specified" && exit 1' }, author: '', license: 'ISC' diff --git a/deps/npm/test/tap/lockfile-http-deps.js b/deps/npm/test/tap/lockfile-http-deps.js index 058525c947..a614daf139 100644 --- a/deps/npm/test/tap/lockfile-http-deps.js +++ b/deps/npm/test/tap/lockfile-http-deps.js @@ -6,7 +6,6 @@ var mr = require('npm-registry-mock') var Tacks = require('tacks') var File = Tacks.File var Dir = Tacks.Dir -var extend = Object.assign || require('util')._extend var common = require('../common-tap.js') var basedir = path.join(__dirname, path.basename(__filename, '.js')) @@ -17,7 +16,7 @@ var tmpdir = path.join(basedir, 'tmp') var conf = { cwd: testdir, - env: extend(extend({}, process.env), { + env: Object.assign({}, process.env, { npm_config_cache: cachedir, npm_config_tmp: tmpdir, npm_config_prefix: globaldir, diff --git a/deps/npm/test/tap/map-to-registry.js b/deps/npm/test/tap/map-to-registry.js index d9677bd7e0..f6fdef5f10 100644 --- a/deps/npm/test/tap/map-to-registry.js +++ b/deps/npm/test/tap/map-to-registry.js @@ -6,7 +6,7 @@ var mapRegistry = require('../../lib/utils/map-to-registry.js') var creds = { '//registry.npmjs.org/:username': 'u', - '//registry.npmjs.org/:_password': new Buffer('p').toString('base64'), + '//registry.npmjs.org/:_password': Buffer.from('p').toString('base64'), '//registry.npmjs.org/:email': 'e', cache: common.npm_config_cache } diff --git a/deps/npm/test/tap/nerf-dart.js b/deps/npm/test/tap/nerf-dart.js index a6df7272c3..d205e527cc 100644 --- a/deps/npm/test/tap/nerf-dart.js +++ b/deps/npm/test/tap/nerf-dart.js @@ -20,13 +20,13 @@ validNerfDart('http://registry.npmjs.org/some-package#random-hash') validNerfDart( 'http://relative.couchapp.npm/design/-/rewrite/', - '//relative.couchapp.npm/design/-/rewrite/' + '//relative.couchapp.npm/design/-/rewrite/' ) validNerfDart( 'http://relative.couchapp.npm:8080/design/-/rewrite/', - '//relative.couchapp.npm:8080/design/-/rewrite/' + '//relative.couchapp.npm:8080/design/-/rewrite/' ) validNerfDart( 'http://relative.couchapp.npm:8080/design/-/rewrite/some-package', - '//relative.couchapp.npm:8080/design/-/rewrite/' + '//relative.couchapp.npm:8080/design/-/rewrite/' ) diff --git a/deps/npm/test/tap/no-global-warns.js b/deps/npm/test/tap/no-global-warns.js index 577b393122..304cf5bf54 100644 --- a/deps/npm/test/tap/no-global-warns.js +++ b/deps/npm/test/tap/no-global-warns.js @@ -31,7 +31,7 @@ var installJSON = { description: '', main: 'index.js', scripts: { - test: 'echo \"Error: no test specified\" && exit 1' + test: 'echo "Error: no test specified" && exit 1' }, author: '', license: 'ISC' diff --git a/deps/npm/test/tap/optional-metadep-rollback-collision.js b/deps/npm/test/tap/optional-metadep-rollback-collision.js index f4ac6bdc79..1c05d1ba58 100644 --- a/deps/npm/test/tap/optional-metadep-rollback-collision.js +++ b/deps/npm/test/tap/optional-metadep-rollback-collision.js @@ -1,4 +1,5 @@ 'use strict' +/* eslint-disable camelcase */ var fs = require('graceful-fs') var path = require('path') @@ -177,11 +178,11 @@ test('go go test racer', function (t) { }, stdio: 'pipe' }).spread((code, stdout, stderr) => { - t.comment(stdout.trim()) - t.comment(stderr.trim()) - t.is(code, 0, 'npm install exited with code 0') - t.notOk(/not ok/.test(stdout), 'should not contain the string \'not ok\'') - }) + t.comment(stdout.trim()) + t.comment(stderr.trim()) + t.is(code, 0, 'npm install exited with code 0') + t.notOk(/not ok/.test(stdout), 'should not contain the string \'not ok\'') + }) }) test('verify results', function (t) { diff --git a/deps/npm/test/tap/outdated-color.js b/deps/npm/test/tap/outdated-color.js index 7fc8c521e5..3a81d05a82 100644 --- a/deps/npm/test/tap/outdated-color.js +++ b/deps/npm/test/tap/outdated-color.js @@ -54,14 +54,14 @@ test('does not use ansi styling', function (t) { '--registry', common.registry, 'outdated', 'underscore' ], - EXEC_OPTS, - function (err, code, stdout) { - t.ifError(err) - t.is(code, 1, 'npm outdated exited with code 1') - t.ok(stdout, stdout.length) - t.ok(!hasControlCodes(stdout)) - s.close() - }) + EXEC_OPTS, + function (err, code, stdout) { + t.ifError(err) + t.is(code, 1, 'npm outdated exited with code 1') + t.ok(stdout, stdout.length) + t.ok(!hasControlCodes(stdout)) + s.close() + }) }) }) diff --git a/deps/npm/test/tap/outdated-latest.js b/deps/npm/test/tap/outdated-latest.js new file mode 100644 index 0000000000..d72fd87176 --- /dev/null +++ b/deps/npm/test/tap/outdated-latest.js @@ -0,0 +1,109 @@ +'use strict' +const path = require('path') +const test = require('tap').test +const mr = require('npm-registry-mock') +const Tacks = require('tacks') +const File = Tacks.File +const Dir = Tacks.Dir +const common = require('../common-tap.js') + +const basedir = path.join(__dirname, path.basename(__filename, '.js')) +const testdir = path.join(basedir, 'testdir') +const cachedir = path.join(basedir, 'cache') +const globaldir = path.join(basedir, 'global') +const tmpdir = path.join(basedir, 'tmp') + +const conf = { + cwd: testdir, + env: Object.assign({}, process.env, { + npm_config_cache: cachedir, + npm_config_tmp: tmpdir, + npm_config_prefix: globaldir, + npm_config_registry: common.registry, + npm_config_loglevel: 'warn' + }) +} + +function exampleManifest (version) { + return { + name: 'example', + version: version + } +} + +const examplePackument = { + 'name': 'example', + 'dist-tags': { + 'latest': '1.2.4', + 'beta': '1.2.6' + }, + 'versions': { + '1.2.0': exampleManifest('1.2.0'), + '1.2.1': exampleManifest('1.2.1'), + '1.2.2': exampleManifest('1.2.2'), + '1.2.3': exampleManifest('1.2.3'), + '1.2.4': exampleManifest('1.2.4'), + '1.2.5': exampleManifest('1.2.5'), + '1.2.6': exampleManifest('1.2.6') + } +} + +const fixture = new Tacks(Dir({ + cache: Dir(), + global: Dir(), + tmp: Dir(), + testdir: Dir({ + node_modules: Dir({ + example: Dir({ + 'package.json': File({ + name: 'example', + version: '1.2.3' + }) + }) + }), + 'package.json': File({ + name: 'outdated-latest', + version: '1.0.0', + dependencies: { + example: '^1.2.0' + } + }) + }) +})) + +function setup () { + cleanup() + fixture.create(basedir) +} + +function cleanup () { + fixture.remove(basedir) +} + +let server + +test('setup', function (t) { + setup() + mr({port: common.port, throwOnUnmatched: true}, function (err, s) { + if (err) throw err + server = s + server.get('/example').reply(200, examplePackument) + t.done() + }) +}) + +test('example', function (t) { + return common.npm(['outdated', '--json'], conf).spread((code, stdout, stderr) => { + t.is(code, 1, 'files ARE outdated!') + const result = JSON.parse(stdout.trim()) + t.comment(stderr.trim()) + // your assertions here + t.like(result, {example: {current: '1.2.3', wanted: '1.2.4', latest: '1.2.4'}}, 'got latest, not beta') + }) +}) + +test('cleanup', function (t) { + server.close() + cleanup() + t.done() +}) diff --git a/deps/npm/test/tap/override-bundled.js b/deps/npm/test/tap/override-bundled.js index cf6049a128..493ebf4a5d 100644 --- a/deps/npm/test/tap/override-bundled.js +++ b/deps/npm/test/tap/override-bundled.js @@ -15,7 +15,7 @@ var testtgz = testmod + '-1.0.0.tgz' var bundleupdatesrc = path.resolve(testmod, 'bundle-update') var bundleupdatetgz = bundleupdatesrc + '-1.0.0.tgz' var bundleupdateNEW = path.resolve(bundleupdatesrc, 'NEW') -var bundleupdateNEWpostinstall = path.resolve(testdir, 'node_modules', 'top-test', 'node_modules', 'bundle-update', 'NEW') +var bundleupdateNEWpostinstall = path.resolve(testdir, 'node_modules', 'bundle-update', 'NEW') var bundleupdatebad = path.resolve(testmod, 'node_modules', 'bundle-update') var bundlekeepsrc = path.resolve(testmod, 'bundle-keep') @@ -34,8 +34,7 @@ var bundledeepupdatesrc = path.resolve(testmod, 'bundle-deep-update') var bundledeepupdatetgz = bundledeepupdatesrc + '-1.0.0.tgz' var bundledeepupdate = path.resolve(bundledeep, 'node_modules', 'bundle-deep-update') var bundledeepupdateNEW = path.resolve(bundledeepupdatesrc, 'NEW') -var bundledeepupdateNEWpostinstall = path.resolve(testdir, 'node_modules', 'top-test', - 'node_modules', 'bundle-deep', 'node_modules', 'bundle-deep-update', 'NEW') +var bundledeepupdateNEWpostinstall = path.resolve(testdir, 'node_modules', 'bundle-deep-update', 'NEW') var testjson = { dependencies: {'top-test': 'file:' + testtgz} @@ -56,7 +55,6 @@ var bundlejson = { name: 'bundle-update', version: '1.0.0', files: ['OLD', 'NEW'] - } var bundlekeepjson = { @@ -65,6 +63,8 @@ var bundlekeepjson = { _requested: { rawSpec: bundlekeeptgz }, + _resolved: bundlekeeptgz, + _shasum: 'baadf00d', files: ['OLD', 'NEW'] } @@ -77,6 +77,8 @@ var bundledeepjson = { _requested: { rawSpec: bundledeeptgz }, + _resolved: bundlekeeptgz, + _shasum: 'deadbeef', files: ['OLD', 'NEW'] } diff --git a/deps/npm/test/tap/files-and-ignores.js b/deps/npm/test/tap/pack-files-and-ignores.js index 6d8b43e9d5..6d8b43e9d5 100644 --- a/deps/npm/test/tap/files-and-ignores.js +++ b/deps/npm/test/tap/pack-files-and-ignores.js diff --git a/deps/npm/test/tap/pack.js b/deps/npm/test/tap/pack.js new file mode 100644 index 0000000000..a0c326210e --- /dev/null +++ b/deps/npm/test/tap/pack.js @@ -0,0 +1,167 @@ +'use strict' + +const BB = require('bluebird') + +const test = require('tap').test +const common = require('../common-tap') +const fs = BB.promisifyAll(require('graceful-fs')) +const path = require('path') +const rimraf = BB.promisify(require('rimraf')) +const Tacks = require('tacks') + +const Dir = Tacks.Dir +const File = Tacks.File + +const testDir = path.join(__dirname, 'pkg') +const tmp = path.join(testDir, 'tmp') +const cache = path.join(testDir, 'cache') + +test('basic pack', (t) => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'generic-package', + version: '90000.100001.5' + }) + })) + return rimraf(testDir) + .then(() => fixture.create(testDir)) + .then(() => common.npm([ + 'pack', + '--loglevel', 'notice', + '--cache', cache, + '--tmp', tmp, + '--prefix', testDir, + '--no-global' + ], { + cwd: testDir + })) + .spread((code, stdout, stderr) => { + t.equal(code, 0, 'npm pack exited ok') + t.match(stderr, /notice\s+\d+[a-z]+\s+package\.json/gi, 'mentions package.json') + t.match(stdout, /generic-package-90000\.100001\.5\.tgz/ig, 'found pkg') + return fs.statAsync( + path.join(testDir, 'generic-package-90000.100001.5.tgz') + ) + }) + .then((stat) => t.ok(stat, 'tarball written to cwd')) + .then(() => rimraf(testDir)) +}) + +test('pack with bundled', (t) => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'generic-package', + version: '90000.100001.5', + dependencies: { + '@bundle/dep': '^1.0.0', + 'regular-dep': '^1.0.0' + }, + bundleDependencies: [ + '@bundle/dep', + 'regular-dep' + ] + }), + 'node_modules': new Dir({ + 'regular-dep': new Dir({ + 'package.json': new File({ + name: 'regular-dep', + version: '1.0.0' + }) + }), + '@bundle': new Dir({ + 'dep': new Dir({ + 'package.json': new File({ + name: '@bundle/dep', + version: '1.0.0' + }) + }) + }) + }) + })) + return rimraf(testDir) + .then(() => fixture.create(testDir)) + .then(() => common.npm([ + 'pack', + '--loglevel', 'notice', + '--cache', cache, + '--tmp', tmp, + '--prefix', testDir, + '--no-global' + ], { + cwd: testDir + })) + .spread((code, stdout, stderr) => { + t.equal(code, 0, 'npm pack exited ok') + t.match(stderr, /notice\s+\d+[a-z]+\s+package\.json/gi, 'mentions package.json') + t.match(stderr, /notice\s+regular-dep/, 'regular dep mentioned') + t.match(stderr, /notice\s+@bundle\/dep/, 'bundled dep mentioned') + }) + .then(() => rimraf(testDir)) +}) + +test('pack --dry-run', (t) => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'generic-package', + version: '90000.100001.5' + }) + })) + return rimraf(testDir) + .then(() => fixture.create(testDir)) + .then(() => common.npm([ + 'pack', + '--dry-run', + '--loglevel', 'notice', + '--cache', cache, + '--tmp', tmp, + '--prefix', testDir, + '--no-global' + ], { + cwd: testDir + })) + .spread((code, stdout, stderr) => { + t.equal(code, 0, 'npm pack exited ok') + t.match(stdout, /generic-package-90000\.100001\.5\.tgz/ig, 'found pkg') + return fs.statAsync( + path.join(testDir, 'generic-package-90000.100001.5.tgz') + ) + .then( + () => { throw new Error('should have failed') }, + (err) => t.equal(err.code, 'ENOENT', 'no tarball written!') + ) + }) + .then(() => rimraf(testDir)) +}) + +test('pack --json', (t) => { + const fixture = new Tacks(new Dir({ + 'package.json': new File({ + name: 'generic-package', + version: '90000.100001.5' + }) + })) + return rimraf(testDir) + .then(() => fixture.create(testDir)) + .then(() => common.npm([ + 'pack', + '--dry-run', + '--json', + '--loglevel', 'notice', + '--cache', cache, + '--tmp', tmp, + '--prefix', testDir, + '--no-global' + ], { + cwd: testDir + })) + .spread((code, stdout, stderr) => { + t.equal(code, 0, 'npm pack exited ok') + t.equal(stderr.trim(), '', 'no notice output') + t.similar(JSON.parse(stdout), [{ + filename: 'generic-package-90000.100001.5.tgz', + files: [{path: 'package.json'}], + entryCount: 1 + }], 'pack details output as valid json') + }) + .then(() => rimraf(testDir)) +}) diff --git a/deps/npm/test/tap/peer-deps.js b/deps/npm/test/tap/peer-deps.js index c319c32e48..b516818da1 100644 --- a/deps/npm/test/tap/peer-deps.js +++ b/deps/npm/test/tap/peer-deps.js @@ -8,7 +8,7 @@ var rimraf = require('rimraf') var test = require('tap').test var common = require('../common-tap.js') -var npm = npm = require('../../') +var npm = require('../../') var pkg = path.resolve(__dirname, 'peer-deps') diff --git a/deps/npm/test/tap/prepublish-only.js b/deps/npm/test/tap/prepublish-only.js index 3681c76897..0d2d31589d 100644 --- a/deps/npm/test/tap/prepublish-only.js +++ b/deps/npm/test/tap/prepublish-only.js @@ -6,6 +6,7 @@ var test = require('tap').test var Tacks = require('tacks') var File = Tacks.File var Dir = Tacks.Dir +var path = require('path') var common = require('../common-tap') @@ -57,7 +58,7 @@ var fixture = new Tacks(Dir({ }, scripts: { build: 'helper', - prepublishOnly: 'npm run build' + prepublishOnly: 'node ' + path.resolve(__dirname, '../../') + ' run build' } }) })) @@ -93,8 +94,8 @@ test('setup', function (t) { test('test', function (t) { server.filteringRequestBody(function () { return true }) - .put('/npm-test-prepublish-only', true) - .reply(201, {ok: true}) + .put('/npm-test-prepublish-only', true) + .reply(201, {ok: true}) common.npm( [ @@ -113,7 +114,7 @@ test('test', function (t) { var c = stdout.trim() var regex = new RegExp( '> npm-test-prepublish-only@1.2.5 prepublishOnly [^\\r\\n]+\\r?\\n' + - '> npm run build\\r?\\n' + + '> .* run build\\r?\\n' + '\\r?\\n' + '\\r?\\n' + '> npm-test-prepublish-only@1.2.5 build [^\\r\\n]+\\r?\\n' + diff --git a/deps/npm/test/tap/prune-dev-dep-with-bins.js b/deps/npm/test/tap/prune-dev-dep-with-bins.js index c22b6343ab..686b5d8d6d 100644 --- a/deps/npm/test/tap/prune-dev-dep-with-bins.js +++ b/deps/npm/test/tap/prune-dev-dep-with-bins.js @@ -50,7 +50,7 @@ var fixture = new Tacks( ') ELSE (\n' + '@SETLOCAL\n' + '@SET PATHEXT=%PATHEXT:;.JS;=;%\n' + - 'node "%~dp0\..\yes\yes.js" %*') + 'node "%~dp0\\..\\yes\\yes.js" %*') }) }), 'package.json': File({ diff --git a/deps/npm/test/tap/publish-config.js b/deps/npm/test/tap/publish-config.js index fb430af210..0566795dbe 100644 --- a/deps/npm/test/tap/publish-config.js +++ b/deps/npm/test/tap/publish-config.js @@ -19,7 +19,7 @@ fs.writeFileSync(pkg + '/package.json', JSON.stringify({ fs.writeFileSync(pkg + '/fixture_npmrc', '//localhost:1337/:email = fancy@feast.net\n' + '//localhost:1337/:username = fancy\n' + - '//localhost:1337/:_password = ' + new Buffer('feast').toString('base64')) + '//localhost:1337/:_password = ' + Buffer.from('feast').toString('base64')) test(function (t) { let child diff --git a/deps/npm/test/tap/publish-scoped.js b/deps/npm/test/tap/publish-scoped.js index c2a8301b77..b8fe0ae2f6 100644 --- a/deps/npm/test/tap/publish-scoped.js +++ b/deps/npm/test/tap/publish-scoped.js @@ -35,15 +35,15 @@ test('setup', function (t) { test('npm publish should honor scoping', function (t) { server.filteringRequestBody(verify) - .put('/@bigco%2fpublish-organized', true) - .reply(201, {ok: true}) + .put('/@bigco%2fpublish-organized', true) + .reply(201, {ok: true}) var configuration = [ 'progress=false', 'cache=' + path.join(pkg, 'cache'), 'registry=http://nonexistent.lvh.me', '//localhost:1337/:username=username', - '//localhost:1337/:_password=' + new Buffer('password').toString('base64'), + '//localhost:1337/:_password=' + Buffer.from('password').toString('base64'), '//localhost:1337/:email=' + 'ogd@aoaioxxysz.net', '@bigco:registry=' + common.registry ] diff --git a/deps/npm/test/tap/publish.js b/deps/npm/test/tap/publish.js new file mode 100644 index 0000000000..765cfb07c6 --- /dev/null +++ b/deps/npm/test/tap/publish.js @@ -0,0 +1,174 @@ +'use strict' + +const BB = require('bluebird') + +const common = require('../common-tap') +const fs = require('fs') +const mkdirp = require('mkdirp') +const mr = BB.promisify(require('npm-registry-mock')) +const path = require('path') +const rimraf = require('rimraf') +const test = require('tap').test + +const testDir = path.join(__dirname, 'publish_test_package') + +function setup () { + cleanup() + mkdirp.sync(path.join(testDir, 'cache')) + + fs.writeFileSync( + path.join(testDir, 'package.json'), + JSON.stringify({ + name: 'publish-organized', + version: '1.2.5' + }, null, 2), + 'utf8' + ) + + fs.writeFileSync( + path.join(testDir, 'index.js'), + 'hello', + 'utf8' + ) +} + +let port = common.port +function withServer (cb) { + return mr({port: port++, throwOnUnmatched: true}) + .tap(cb) + .then((server) => { + server.done() + return server.close() + }) +} + +test('basic npm publish', (t) => { + setup() + return withServer((server) => { + server.filteringRequestBody(verify) + .put('/publish-organized', true) + .reply(201, {ok: true}) + + return common.npm([ + 'publish', + '--no-color', + '--cache', path.join(testDir, 'cache'), + '--registry=' + common.registry.replace(common.port, server.port), + `--//localhost:${server.port}/:username=username`, + `--//localhost:${server.port}/:_password=` + Buffer.from('password').toString('base64'), + `--//localhost:${server.port}/:email=` + 'ogd@aoaioxxysz.net' + ], {'cwd': testDir}) + .spread((code, stdout, stderr) => { + t.comment(stdout) + t.comment(stderr) + t.is(code, 0, 'published without error') + }) + + function verify (body) { + t.doesNotThrow(() => { + const parsed = JSON.parse(body) + const current = parsed.versions['1.2.5'] + t.equal( + current._npmVersion, + require(path.resolve(__dirname, '../../package.json')).version, + 'npm version is correct' + ) + + t.equal( + current._nodeVersion, + process.versions.node, + 'node version is correct' + ) + }, 'converted body back into object') + + return true + } + }) +}) + +test('npm publish --dry-run', (t) => { + setup() + return common.npm([ + 'publish', + '--dry-run', + '--registry=https://example.registry/fake', + '--cache', path.join(testDir, 'cache'), + '--loglevel=notice', + '--no-color' + ], {'cwd': testDir}) + .spread((code, stdout, stderr) => { + t.comment(stdout) + t.comment(stderr) + t.is(code, 0, 'published without error') + t.match(stderr, /notice\s+\d+[a-z]+\s+package\.json/gi, 'mentions package.json') + t.match(stderr, /notice\s+\d+[a-z]+\s+index\.js/gi, 'mentions index.js') + }) +}) + +test('npm publish --json', (t) => { + setup() + return withServer((server) => { + server.filteringRequestBody(() => true) + .put('/publish-organized', true) + .reply(201, {ok: true}) + return common.npm([ + 'publish', + '--json', + '--registry', common.registry.replace(common.port, server.port), + '--cache', path.join(testDir, 'cache') + ], {'cwd': testDir}) + .spread((code, stdout, stderr) => { + t.comment(stdout) + t.comment(stderr) + t.is(code, 0, 'published without error') + t.similar(JSON.parse(stdout), { + name: 'publish-organized', + version: '1.2.5', + files: [ + {path: 'package.json'}, + {path: 'index.js'} + ], + entryCount: 2 + }, 'JSON output reflects package contents') + t.equal(stderr.trim(), '', 'nothing on stderr') + }) + }) +}) + +test('npm publish --dry-run --json', (t) => { + setup() + return common.npm([ + 'publish', + '--dry-run', + '--json', + '--registry=https://example.registry/fake', + '--cache', path.join(testDir, 'cache'), + '--loglevel=notice', + '--no-color' + ], {'cwd': testDir}) + .spread((code, stdout, stderr) => { + t.comment(stdout) + t.comment(stderr) + t.is(code, 0, 'published without error') + t.similar(JSON.parse(stdout), { + name: 'publish-organized', + version: '1.2.5', + files: [ + {path: 'package.json'}, + {path: 'index.js'} + ], + entryCount: 2 + }, 'JSON output reflects package contents') + t.equal(stderr.trim(), '', 'nothing on stderr') + }) +}) + +test('cleanup', (t) => { + cleanup() + t.end() +}) + +function cleanup () { + process.chdir(__dirname) + rimraf.sync(testDir) +} diff --git a/deps/npm/test/tap/repo.js b/deps/npm/test/tap/repo.js index e2751573d0..54907f620c 100644 --- a/deps/npm/test/tap/repo.js +++ b/deps/npm/test/tap/repo.js @@ -14,7 +14,7 @@ common.pendIfWindows('This is trickier to convert without opening new shells') test('setup', function (t) { var s = '#!/usr/bin/env bash\n' + - 'echo \"$@\" > ' + JSON.stringify(__dirname) + '/_output\n' + 'echo "$@" > ' + JSON.stringify(__dirname) + '/_output\n' fs.writeFileSync(fakeBrowser, s, 'ascii') fs.chmodSync(fakeBrowser, '0755') t.pass('made script') diff --git a/deps/npm/test/tap/retry-on-stale-cache.js b/deps/npm/test/tap/retry-on-stale-cache.js index df6d7c2db3..8aec35ed4f 100644 --- a/deps/npm/test/tap/retry-on-stale-cache.js +++ b/deps/npm/test/tap/retry-on-stale-cache.js @@ -3,7 +3,6 @@ var path = require('path') var mr = require('npm-registry-mock') var test = require('tap').test var common = require('../common-tap') -var extend = Object.assign || require('util')._extend var Tacks = require('tacks') var Dir = Tacks.Dir var File = Tacks.File @@ -23,7 +22,7 @@ var config = [ var fixture = new Tacks(Dir({ 'cache': Dir(), 'modules': Dir({ - 'good-night-0.1.0.tgz': File(new Buffer( + 'good-night-0.1.0.tgz': File(Buffer.from( '1f8b0800000000000003ed934f4bc43010c57beea7187a59056dd36eff80' + 'de85050541c1f3d8c634da4e4a925a8af8dd6db7bb8ba0e0c15559e9eff2' + '206f929909bc06f327143c6826f51f8d2267cf30c6d2388641c32c61ef75' + @@ -37,7 +36,7 @@ var fixture = new Tacks(Dir({ 'f6795d000c0000', 'hex' )), - 'good-night-1.0.0.tgz': File(new Buffer( + 'good-night-1.0.0.tgz': File(Buffer.from( '1f8b0800000000000003ed954d6bc24010863dfb2bb6b9a8503793b849a0' + 'eda5979efa052d484184252e495a331b76d78a94fef76e8cf683163cd42a' + '957d2e03796777268187543c7de299f0aba6d2472db1b5650020668cd81a' + @@ -79,9 +78,9 @@ var onlyOldMetadata = { } } -var oldAndNewMetadata = extend({}, onlyOldMetadata) +var oldAndNewMetadata = Object.assign({}, onlyOldMetadata) oldAndNewMetadata['dist-tags'] = { latest: '1.0.0' } -oldAndNewMetadata.versions = extend({ +oldAndNewMetadata.versions = Object.assign({ '1.0.0': { 'name': 'good-night', 'version': '1.0.0', diff --git a/deps/npm/test/tap/save-optional.js b/deps/npm/test/tap/save-optional.js new file mode 100644 index 0000000000..66e430dc78 --- /dev/null +++ b/deps/npm/test/tap/save-optional.js @@ -0,0 +1,81 @@ +'use strict' +const path = require('path') +const test = require('tap').test +const mr = require('npm-registry-mock') +const Tacks = require('tacks') +const fs = require('fs') +const File = Tacks.File +const Dir = Tacks.Dir +const common = require('../common-tap.js') + +const basedir = path.join(__dirname, path.basename(__filename, '.js')) +const testdir = path.join(basedir, 'testdir') +const cachedir = path.join(basedir, 'cache') +const globaldir = path.join(basedir, 'global') +const tmpdir = path.join(basedir, 'tmp') + +const conf = { + cwd: testdir, + stdio: [0, 1, 2], + env: Object.assign({}, process.env, { + npm_config_cache: cachedir, + npm_config_tmp: tmpdir, + npm_config_prefix: globaldir, + npm_config_registry: common.registry, + npm_config_loglevel: 'silly' + }) +} + +let server +const fixture = new Tacks(Dir({ + cache: Dir(), + global: Dir(), + tmp: Dir(), + testdir: Dir({ + example: Dir({ + 'package.json': File({ + name: 'example', + version: '1.0.0' + }) + }), + 'package.json': File({ + name: 'save-optional', + version: '1.0.0' + }) + }) +})) + +function setup () { + cleanup() + fixture.create(basedir) +} + +function cleanup () { + fixture.remove(basedir) +} + +test('setup', function (t) { + setup() + mr({port: common.port, throwOnUnmatched: true}, function (err, s) { + if (err) throw err + server = s + t.done() + }) +}) + +test('example', function (t) { + common.npm(['install', '-O', '--package-lock-only', 'file:example'], conf, function (err, code) { + if (err) throw err + t.is(code, 0, 'command ran ok') + const plock = JSON.parse(fs.readFileSync(`${testdir}/package-lock.json`)) + t.like(plock, { dependencies: { example: { optional: true } } }, 'optional status saved') + // your assertions here + t.done() + }) +}) + +test('cleanup', function (t) { + server.close() + cleanup() + t.done() +}) diff --git a/deps/npm/test/tap/scripts-whitespace-windows.js b/deps/npm/test/tap/scripts-whitespace-windows.js index 27a04601c7..4d1e53a8f5 100644 --- a/deps/npm/test/tap/scripts-whitespace-windows.js +++ b/deps/npm/test/tap/scripts-whitespace-windows.js @@ -21,7 +21,7 @@ var json = { description: 'a test', repository: 'git://github.com/robertkowalski/bogus', scripts: { - foo: 'foo --title \"Analysis of\" --recurse -d report src' + foo: 'foo --title "Analysis of" --recurse -d report src' }, dependencies: { 'scripts-whitespace-windows-dep': '0.0.1' @@ -35,8 +35,6 @@ var dependency = { bin: [ 'bin/foo' ] } -var extend = Object.assign || require('util')._extend - var foo = function () { /* #!/usr/bin/env node @@ -65,7 +63,7 @@ test('setup', function (t) { common.npm(['i', dep], { cwd: pkg, - env: extend({ + env: Object.assign({ npm_config_cache: cache, npm_config_tmp: tmp, npm_config_prefix: pkg, diff --git a/deps/npm/test/tap/search.js b/deps/npm/test/tap/search.js index 3568170de1..df7ff0fe37 100644 --- a/deps/npm/test/tap/search.js +++ b/deps/npm/test/tap/search.js @@ -164,9 +164,9 @@ test('no arguments provided should error', function (t) { t.equal(code, 1, 'search finished unsuccessfully') t.match( - stderr, - /search must be called with arguments/, - 'should have correct error message' + stderr, + /search must be called with arguments/, + 'should have correct error message' ) t.end() }) diff --git a/deps/npm/test/tap/shared-linked.js b/deps/npm/test/tap/shared-linked.js index 0e2b462789..3ee00e063d 100644 --- a/deps/npm/test/tap/shared-linked.js +++ b/deps/npm/test/tap/shared-linked.js @@ -7,7 +7,6 @@ var Symlink = Tacks.Symlink var Dir = Tacks.Dir var common = require('../common-tap.js') var mr = require('npm-registry-mock') -var extend = Object.assign || require('util')._extend var testdir = path.join(__dirname, path.basename(__filename, '.js')) var bugdir = path.join(testdir, 'modules', 'bug') @@ -122,7 +121,7 @@ test('setup', function (t) { test('shared-linked', function (t) { var options = { cwd: bugdir, - env: extend(extend({}, process.env), { + env: Object.assign({}, process.env, { npm_config_prefix: path.join(testdir, 'global') }) } diff --git a/deps/npm/test/tap/shrinkwrap-default-dev.js b/deps/npm/test/tap/shrinkwrap-default-dev.js index 5c8929a43d..48f9f2a90a 100644 --- a/deps/npm/test/tap/shrinkwrap-default-dev.js +++ b/deps/npm/test/tap/shrinkwrap-default-dev.js @@ -5,7 +5,6 @@ var fs = require('fs') var Tacks = require('tacks') var File = Tacks.File var Dir = Tacks.Dir -var extend = Object.assign || require('util')._extend var common = require('../common-tap.js') var basedir = path.join(__dirname, path.basename(__filename, '.js')) @@ -16,7 +15,7 @@ var tmpdir = path.join(basedir, 'tmp') var conf = { cwd: testdir, - env: extend(extend({}, process.env), { + env: Object.assign({}, process.env, { npm_config_cache: cachedir, npm_config_tmp: tmpdir, npm_config_prefix: globaldir, diff --git a/deps/npm/test/tap/shrinkwrap-lifecycle-cwd.js b/deps/npm/test/tap/shrinkwrap-lifecycle-cwd.js index 8d5210c404..bc9ab9cf11 100644 --- a/deps/npm/test/tap/shrinkwrap-lifecycle-cwd.js +++ b/deps/npm/test/tap/shrinkwrap-lifecycle-cwd.js @@ -5,7 +5,6 @@ var mr = require('npm-registry-mock') var Tacks = require('tacks') var File = Tacks.File var Dir = Tacks.Dir -var extend = Object.assign || require('util')._extend var common = require('../common-tap.js') var basedir = path.join(__dirname, path.basename(__filename, '.js')) @@ -17,7 +16,7 @@ var escapeArg = require('../../lib/utils/escape-arg.js') var conf = { cwd: testdir, - env: extend({ + env: Object.assign({ npm_config_cache: cachedir, npm_config_tmp: tmpdir, npm_config_prefix: globaldir, diff --git a/deps/npm/test/tap/shrinkwrap-optional-dependency.js b/deps/npm/test/tap/shrinkwrap-optional-dependency.js index 0373e89e62..5085dd0cbb 100644 --- a/deps/npm/test/tap/shrinkwrap-optional-dependency.js +++ b/deps/npm/test/tap/shrinkwrap-optional-dependency.js @@ -8,7 +8,7 @@ var rimraf = require('rimraf') var test = require('tap').test var common = require('../common-tap.js') -var npm = npm = require('../../') +var npm = require('../../') var pkg = path.resolve(__dirname, 'shrinkwrap-optional-dependency') diff --git a/deps/npm/test/tap/shrinkwrap-optional-platform.js b/deps/npm/test/tap/shrinkwrap-optional-platform.js index 50a1706868..b109d89578 100644 --- a/deps/npm/test/tap/shrinkwrap-optional-platform.js +++ b/deps/npm/test/tap/shrinkwrap-optional-platform.js @@ -4,7 +4,6 @@ var test = require('tap').test var Tacks = require('tacks') var File = Tacks.File var Dir = Tacks.Dir -var extend = Object.assign || require('util')._extend var common = require('../common-tap.js') var basedir = path.join(__dirname, path.basename(__filename, '.js')) @@ -15,7 +14,7 @@ var tmpdir = path.join(basedir, 'tmp') var conf = { cwd: testdir, - env: extend(extend({}, process.env), { + env: Object.assign({}, process.env, { npm_config_cache: cachedir, npm_config_tmp: tmpdir, npm_config_prefix: globaldir, diff --git a/deps/npm/test/tap/shrinkwrap-optional-property.js b/deps/npm/test/tap/shrinkwrap-optional-property.js index 19e55a45f8..ccff5a93e2 100644 --- a/deps/npm/test/tap/shrinkwrap-optional-property.js +++ b/deps/npm/test/tap/shrinkwrap-optional-property.js @@ -8,7 +8,7 @@ var rimraf = require('rimraf') var test = require('tap').test var common = require('../common-tap.js') -var npm = npm = require('../../') +var npm = require('../../') var pkg = path.resolve(__dirname, 'shrinkwrap-optional-dependency') diff --git a/deps/npm/test/tap/shrinkwrap-prod-dependency.js b/deps/npm/test/tap/shrinkwrap-prod-dependency.js index 023a3bf0b7..34e30d7c7a 100644 --- a/deps/npm/test/tap/shrinkwrap-prod-dependency.js +++ b/deps/npm/test/tap/shrinkwrap-prod-dependency.js @@ -7,7 +7,7 @@ var osenv = require('osenv') var rimraf = require('rimraf') var test = require('tap').test -var npm = npm = require('../../') +var npm = require('../../') var common = require('../common-tap.js') var pkg = path.resolve(__dirname, 'shrinkwrap-prod-dependency') diff --git a/deps/npm/test/tap/shrinkwrap-resolve-conflict.js b/deps/npm/test/tap/shrinkwrap-resolve-conflict.js new file mode 100644 index 0000000000..146d1191bf --- /dev/null +++ b/deps/npm/test/tap/shrinkwrap-resolve-conflict.js @@ -0,0 +1,117 @@ +'use strict' + +const BB = require('bluebird') + +const common = require('../common-tap.js') +const fs = BB.promisifyAll(require('fs')) +const path = require('path') +const rimraf = BB.promisify(require('rimraf')) +const test = require('tap').test +const Tacks = require('tacks') + +const File = Tacks.File +const Dir = Tacks.Dir + +const testDir = path.resolve(__dirname, path.basename(__filename, '.js')) +const modAdir = path.resolve(testDir, 'modA') +const modBdir = path.resolve(testDir, 'modB') +const modCdir = path.resolve(testDir, 'modC') + +test('conflicts in shrinkwrap are auto-resolved on install', (t) => { + const fixture = new Tacks(Dir({ + 'package.json': File({ + name: 'foo', + dependencies: { + modA: 'file://' + modAdir, + modB: 'file://' + modBdir + }, + devDependencies: { + modC: 'file://' + modCdir + } + }), + 'npm-shrinkwrap.json': File( + ` +{ + "name": "foo", + "requires": true, + "lockfileVersion": 1, + "dependencies": { +<<` + `<<` + `<<` + `< HEAD + "modA": { + "version": "file:modA" +||` + `||` + `||` + `| merged common ancestors + "modB": { + "version": "file:modB" +==` + `==` + `==` + `= + "modC": { + "version": "file:modC", + "dev": true +>>` + `>>` + `>>` + `> branch + } + } +} +`), + 'modA': Dir({ + 'package.json': File({ + name: 'modA', + version: '1.0.0' + }) + }), + 'modB': Dir({ + 'package.json': File({ + name: 'modB', + version: '1.0.0' + }) + }), + 'modC': Dir({ + 'package.json': File({ + name: 'modC', + version: '1.0.0' + }) + }) + })) + fixture.create(testDir) + function readJson (file) { + return fs.readFileAsync(path.join(testDir, file)).then(JSON.parse) + } + return BB.fromNode((cb) => { + common.npm([ + 'install', + '--loglevel', 'warn' + ], {cwd: testDir}, (err, code, out, stderr) => { + t.comment(stderr) + t.match(stderr, /warn.*conflict/gi, 'warns about a conflict') + cb(err || (code && new Error('non-zero exit code')) || null, out) + }) + }) + .then(() => BB.join( + readJson('npm-shrinkwrap.json'), + readJson('node_modules/modA/package.json'), + readJson('node_modules/modB/package.json'), + readJson('node_modules/modC/package.json'), + (lockfile, A, B, C) => { + t.deepEqual(lockfile, { + name: 'foo', + requires: true, + lockfileVersion: 1, + dependencies: { + modA: { + version: 'file:modA' + }, + modB: { + version: 'file:modB' + }, + modC: { + version: 'file:modC', + dev: true + } + } + }, 'resolved lockfile matches expectations') + t.equal(A.name, 'modA', 'installed modA') + t.equal(B.name, 'modB', 'installed modB') + t.equal(C.name, 'modC', 'installed modC') + } + )) +}) + +test('cleanup', () => rimraf(testDir)) diff --git a/deps/npm/test/tap/shrinkwrap-save-dev-with-existing-deps.js b/deps/npm/test/tap/shrinkwrap-save-dev-with-existing-deps.js index 507f2c56f8..5934a758da 100644 --- a/deps/npm/test/tap/shrinkwrap-save-dev-with-existing-deps.js +++ b/deps/npm/test/tap/shrinkwrap-save-dev-with-existing-deps.js @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ var fs = require('fs') var path = require('path') diff --git a/deps/npm/test/tap/shrinkwrap-save-with-existing-dev-deps.js b/deps/npm/test/tap/shrinkwrap-save-with-existing-dev-deps.js index fa8895577a..5f0eb07962 100644 --- a/deps/npm/test/tap/shrinkwrap-save-with-existing-dev-deps.js +++ b/deps/npm/test/tap/shrinkwrap-save-with-existing-dev-deps.js @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ var fs = require('fs') var path = require('path') diff --git a/deps/npm/test/tap/spec-local-specifiers.js b/deps/npm/test/tap/spec-local-specifiers.js index 8c8c565dc3..d149b7ea0e 100644 --- a/deps/npm/test/tap/spec-local-specifiers.js +++ b/deps/npm/test/tap/spec-local-specifiers.js @@ -365,7 +365,7 @@ testdirContent['install-behavior'] = Dir({ } }) }), - 'noext': File(new Buffer( + 'noext': File(Buffer.from( '1f8b08000000000000032b484cce4e4c4fd52f80d07a59c5f9790c540606' + '06066626260a20dadccc144c1b1841f86000923334363037343536343732' + '633000728c0c80f2d4760836505a5c925804740aa5e640bca200a78708a8' + @@ -373,7 +373,7 @@ testdirContent['install-behavior'] = Dir({ '1928d5720db41b47c1281805a36014501f00005012007200080000', 'hex' )), - 'tarball-1.0.0.tgz': File(new Buffer( + 'tarball-1.0.0.tgz': File(Buffer.from( '1f8b08000000000000032b484cce4e4c4fd52f80d07a59c5f9790c540606' + '06066626260a20dadccc144c1b1841f8606062a6c060686c606e686a6c68' + '666ec26000e480e5a9ed106ca0b4b824b108e8144acd817845014e0f1150' + diff --git a/deps/npm/test/tap/startstop.js b/deps/npm/test/tap/startstop.js index b17a303c82..0e9d2d9402 100644 --- a/deps/npm/test/tap/startstop.js +++ b/deps/npm/test/tap/startstop.js @@ -16,8 +16,8 @@ var json = { name: 'startstop', version: '1.2.3', scripts: { - start: 'node -e \"console.log(\'start\')\"', - stop: 'node -e \"console.log(\'stop\')\"' + start: 'node -e "console.log(\'start\')"', + stop: 'node -e "console.log(\'stop\')"' } } diff --git a/deps/npm/test/tap/symlink-cycle.js b/deps/npm/test/tap/symlink-cycle.js index 62aa8e0674..5bee2c5569 100644 --- a/deps/npm/test/tap/symlink-cycle.js +++ b/deps/npm/test/tap/symlink-cycle.js @@ -17,7 +17,7 @@ var cycleJSON = { description: '', main: 'index.js', scripts: { - test: 'echo \"Error: no test specified\" && exit 1' + test: 'echo "Error: no test specified" && exit 1' }, dependencies: { 'cycle': '*' diff --git a/deps/npm/test/tap/tagged-version-matching.js b/deps/npm/test/tap/tagged-version-matching.js index 9d3f5f38e9..55dfb7b7c4 100644 --- a/deps/npm/test/tap/tagged-version-matching.js +++ b/deps/npm/test/tap/tagged-version-matching.js @@ -5,7 +5,6 @@ var Tacks = require('tacks') var File = Tacks.File var Dir = Tacks.Dir var Symlink = Tacks.Symlink -var extend = Object.assign || require('util')._extend var common = require('../common-tap.js') var basedir = path.join(__dirname, path.basename(__filename, '.js')) @@ -16,7 +15,7 @@ var tmpdir = path.join(basedir, 'tmp') var conf = { cwd: testdir, - env: extend({ + env: Object.assign({ npm_config_cache: cachedir, npm_config_tmp: tmpdir, npm_config_prefix: globaldir, @@ -46,24 +45,6 @@ var fixture = new Tacks(Dir({ 'package.json': File({ _from: 'npm/example-gitdep', _id: 'gitdep@1.0.0', - _requested: { - raw: 'gitdep@git://github.com/npm/example-gitdep.git#da39a3ee5e6b4b0d3255bfef95601890afd80709', - scope: null, - escapedName: 'gitdep', - name: 'gitdep', - rawSpec: 'git://github.com/npm/example-gitdep.git#da39a3ee5e6b4b0d3255bfef95601890afd80709', - spec: 'git://github.com/npm/example-gitdep.git#da39a3ee5e6b4b0d3255bfef95601890afd80709', - type: 'hosted', - hosted: { - type: 'github', - ssh: 'git@github.com:npm/example-gitdep.git#da39a3ee5e6b4b0d3255bfef95601890afd80709', - sshUrl: 'git+ssh://git@github.com/npm/example-gitdep.git#da39a3ee5e6b4b0d3255bfef95601890afd80709', - httpsUrl: 'git+https://github.com/npm/example-gitdep.git#da39a3ee5e6b4b0d3255bfef95601890afd80709', - gitUrl: 'git://github.com/npm/example-gitdep.git#da39a3ee5e6b4b0d3255bfef95601890afd80709', - shortcut: 'github:npm/example-gitdep#da39a3ee5e6b4b0d3255bfef95601890afd80709', - directUrl: 'https://raw.githubusercontent.com/npm/example-gitdep/da39a3ee5e6b4b0d3255bfef95601890afd80709/package.json' - } - }, _resolved: 'github:npm/example-gitdep#da39a3ee5e6b4b0d3255bfef95601890afd80709', name: 'gitdep', version: '1.0.0' @@ -74,15 +55,7 @@ var fixture = new Tacks(Dir({ _from: 'tagdep@latest', _id: 'tagdep@1.0.0', _integrity: 'sha1-0EJSKmsdk39848LlrRg/hZQo2B8=', - _requested: { - raw: 'tagdep@https://registry.example.com/tagdep/-/tagdep-1.0.0.tgz', - scope: null, - escapedName: 'tagdep', - name: 'tagdep', - rawSpec: 'https://registry.example.com/tagdep/-/tagdep-1.0.0.tgz', - spec: 'https://registry.example.com/tagdep/-/tagdep-1.0.0.tgz', - type: 'remote' - }, + _resolved: 'https://registry.example.com/tagdep/-/tagdep-1.0.0.tgz', name: 'tagdep', version: '1.0.0' }) @@ -102,7 +75,7 @@ var fixture = new Tacks(Dir({ example: { version: 'file:example', requires: { - tagdep: '1.0.0', + tagdep: '^1.0.0', gitdep: 'github:npm/example-gitdep#da39a3ee5e6b4b0d3255bfef95601890afd80709' } }, diff --git a/deps/npm/test/tap/team.js b/deps/npm/test/tap/team.js index b13fa86e8b..38caadde53 100644 --- a/deps/npm/test/tap/team.js +++ b/deps/npm/test/tap/team.js @@ -37,6 +37,30 @@ test('team create basic', function (t) { }) }) +test('team create (allow optional @ prefix on scope)', function (t) { + var teamData = { + name: 'test', + scope_id: 1234, + created: '2015-07-23T18:07:49.959Z', + updated: '2015-07-23T18:07:49.959Z', + deleted: null + } + server.put('/-/org/myorg/team', JSON.stringify({ + name: teamData.name + })).reply(200, teamData) + common.npm([ + 'team', 'create', '@myorg:' + teamData.name, + '--registry', common.registry, + '--loglevel', 'silent' + ], {}, function (err, code, stdout, stderr) { + t.ifError(err, 'npm team') + t.equal(code, 0, 'exited OK') + t.equal(stderr, '', 'no error output') + t.same(JSON.parse(stdout), teamData) + t.end() + }) +}) + test('team destroy', function (t) { var teamData = { name: 'myteam', diff --git a/deps/npm/test/tap/test-run-ls.js b/deps/npm/test/tap/test-run-ls.js index ea495879f3..9475695cb6 100644 --- a/deps/npm/test/tap/test-run-ls.js +++ b/deps/npm/test/tap/test-run-ls.js @@ -3,7 +3,7 @@ var test = require('tap').test var path = require('path') var cwd = path.resolve(__dirname, '..', '..') var testscript = require('../../package.json').scripts.test -var tsregexp = testscript.replace(/([\[\.\*\]])/g, '\\$1') +var tsregexp = testscript.replace(/([[.*\]])/g, '\\$1') test('default', function (t) { common.npm(['run'], { cwd: cwd }, function (er, code, so) { diff --git a/deps/npm/test/tap/unit-deps-earliestInstallable.js b/deps/npm/test/tap/unit-deps-earliestInstallable.js index 538cfe6c09..8c5ca06ad8 100644 --- a/deps/npm/test/tap/unit-deps-earliestInstallable.js +++ b/deps/npm/test/tap/unit-deps-earliestInstallable.js @@ -2,6 +2,7 @@ var test = require('tap').test var requireInject = require('require-inject') var npa = require('npm-package-arg') +var log = require('npmlog') // we're just mocking to avoid having to call `npm.load` var deps = requireInject('../../lib/install/deps.js', { @@ -66,7 +67,7 @@ test('earliestInstallable should consider devDependencies', function (t) { dep2a.parent = dep1 dep2.parent = pkg - var earliest = earliestInstallable(dep1, dep1, dep2a.package) + var earliest = earliestInstallable(dep1, dep1, dep2a.package, log) t.isDeeply(earliest, dep1, 'should hoist package when an incompatible devDependency is present') t.end() }) @@ -107,7 +108,7 @@ test('earliestInstallable should reuse shared prod/dev deps when they are identi dep1.parent = pkg dep2.parent = pkg - var earliest = earliestInstallable(dep1, dep1, dep2.package) + var earliest = earliestInstallable(dep1, dep1, dep2.package, log) t.isDeeply(earliest, pkg, 'should reuse identical shared dev/prod deps when installing both') t.end() }) diff --git a/deps/npm/test/tap/unit-token-validate-cidr.js b/deps/npm/test/tap/unit-token-validate-cidr.js new file mode 100644 index 0000000000..db963c31f3 --- /dev/null +++ b/deps/npm/test/tap/unit-token-validate-cidr.js @@ -0,0 +1,19 @@ +'use strict' +const test = require('tap').test +const requireInject = require('require-inject') +const validateCIDRList = requireInject('../../lib/token.js', {'../../lib/npm.js': {}})._validateCIDRList + +test('validateCIDRList', (t) => { + t.plan(10) + const single = ['127.0.0.0/24'] + const double = ['127.0.0.0/24', '192.168.0.0/16'] + const ipv6 = '2620:0:2d0:200::7/32' + const ipv6Mixed = ['127.0.0/24', '2620:0:2d0:200::7/32', '192.168.0.0/16'] + t.doesNotThrow(() => t.isDeeply(validateCIDRList(single.join(',')), single), 'single string ipv4') + t.doesNotThrow(() => t.isDeeply(validateCIDRList(single), single), 'single array ipv4') + t.doesNotThrow(() => t.isDeeply(validateCIDRList(double.join(',')), double), 'double string ipv4') + t.doesNotThrow(() => t.isDeeply(validateCIDRList(double), double), 'double array ipv4') + t.throws(() => validateCIDRList(ipv6)) + t.throws(() => validateCIDRList(ipv6Mixed)) + t.done() +}) diff --git a/deps/npm/test/tap/unsupported.js b/deps/npm/test/tap/unsupported.js index 1a4ef61438..db604b3089 100644 --- a/deps/npm/test/tap/unsupported.js +++ b/deps/npm/test/tap/unsupported.js @@ -21,12 +21,15 @@ var versions = [ ['v2.3.1', true, true], ['v3.0.0', true, true], ['v4.5.0', true, true], - ['v4.8.4', false, false], + ['v4.8.4', false, true], ['v5.7.1', false, true], ['v6.8.1', false, false], - ['v7.0.0-beta23', false, false], - ['v7.2.3', false, false], - ['v8.4.0', false, false] + ['v7.0.0-beta23', false, true], + ['v7.2.3', false, true], + ['v8.4.0', false, false], + ['v9.3.0', false, false], + ['v10.0.0-0', false, false], + ['v11.0.0-0', false, false] ] test('versions', function (t) { diff --git a/deps/npm/test/tap/update-examples.js b/deps/npm/test/tap/update-examples.js index 532a67f386..8369d002fa 100644 --- a/deps/npm/test/tap/update-examples.js +++ b/deps/npm/test/tap/update-examples.js @@ -149,7 +149,7 @@ test('setup', function (t) { t.pass('mock registry active') npm.load({ cache: CACHE_DIR, registry: common.registry, - cwd: PKG_DIR }, function (err) { + cwd: PKG_DIR }, function (err) { t.ifError(err, 'started server') mockServer = server diff --git a/deps/npm/test/tap/upgrade-lifecycles.js b/deps/npm/test/tap/upgrade-lifecycles.js index f15fe0038e..0d0b8da616 100644 --- a/deps/npm/test/tap/upgrade-lifecycles.js +++ b/deps/npm/test/tap/upgrade-lifecycles.js @@ -4,7 +4,6 @@ var test = require('tap').test var Tacks = require('tacks') var File = Tacks.File var Dir = Tacks.Dir -var extend = Object.assign || require('util')._extend var common = require('../common-tap.js') var basedir = path.join(__dirname, path.basename(__filename, '.js')) @@ -15,7 +14,7 @@ var tmpdir = path.join(basedir, 'tmp') var conf = { cwd: testdir, - env: extend({ + env: Object.assign({ npm_config_cache: cachedir, npm_config_tmp: tmpdir, npm_config_prefix: globaldir, diff --git a/deps/npm/test/tap/version-consistent-newlines.js b/deps/npm/test/tap/version-consistent-newlines.js new file mode 100644 index 0000000000..11020b2a70 --- /dev/null +++ b/deps/npm/test/tap/version-consistent-newlines.js @@ -0,0 +1,91 @@ +'use strict' + +const common = require('../common-tap.js') +const test = require('tap').test +const npm = require('../../') +const osenv = require('osenv') +const path = require('path') +const fs = require('fs') +const mkdirp = require('mkdirp') +const rimraf = require('rimraf') +const requireInject = require('require-inject') + +const pkg = path.resolve(__dirname, 'version-no-git') +const cache = path.resolve(pkg, 'cache') +const gitDir = path.resolve(pkg, '.git') + +test('npm version does not alter the line endings in package.json (LF)', function (t) { + setup('\n') + + npm.load({cache: cache, registry: common.registry}, function () { + const version = requireInject('../../lib/version', { + which: function (cmd, cb) { + process.nextTick(function () { + cb(new Error('ENOGIT!')) + }) + } + }) + + version(['patch'], function (err) { + if (!t.error(err)) return t.end() + + const pkgPath = path.resolve(pkg, 'package.json') + const pkgStr = fs.readFileSync(pkgPath, 'utf8') + + t.match(pkgStr, '\n') + t.notMatch(pkgStr, '\r') + + t.end() + }) + }) +}) + +test('npm version does not alter the line endings in package.json (CRLF)', function (t) { + setup('\r\n') + + npm.load({cache: cache, registry: common.registry}, function () { + const version = requireInject('../../lib/version', { + which: function (cmd, cb) { + process.nextTick(function () { + cb(new Error('ENOGIT!')) + }) + } + }) + + version(['patch'], function (err) { + if (!t.error(err)) return t.end() + + const pkgPath = path.resolve(pkg, 'package.json') + const pkgStr = fs.readFileSync(pkgPath, 'utf8') + + t.match(pkgStr, '\r\n') + t.notMatch(pkgStr, /[^\r]\n/) + + t.end() + }) + }) +}) + +test('cleanup', function (t) { + process.chdir(osenv.tmpdir()) + + rimraf.sync(pkg) + t.end() +}) + +function setup (lineEnding) { + mkdirp.sync(pkg) + mkdirp.sync(cache) + mkdirp.sync(gitDir) + fs.writeFileSync( + path.resolve(pkg, 'package.json'), + JSON.stringify({ + author: 'Terin Stock', + name: 'version-no-git-test', + version: '0.0.0', + description: "Test for npm version if git binary doesn't exist" + }, null, 2).replace(/\n/g, lineEnding), + 'utf8' + ) + process.chdir(pkg) +} diff --git a/deps/npm/test/tap/view.js b/deps/npm/test/tap/view.js index 371e1d922d..30ccdb471c 100644 --- a/deps/npm/test/tap/view.js +++ b/deps/npm/test/tap/view.js @@ -111,8 +111,7 @@ test('npm view .', function (t) { ], { cwd: t2dir }, function (err, code, stdout) { t.ifError(err, 'view command finished successfully') t.equal(code, 0, 'exit ok') - var re = new RegExp("name: 'test-repo-url-https'") - t.similar(stdout, re) + t.matches(stdout, /test-repo-url-https/, 'has the right package') t.end() }) }) @@ -217,8 +216,7 @@ test('npm view <package name>', function (t) { ], { cwd: t2dir }, function (err, code, stdout) { t.ifError(err, 'view command finished successfully') t.equal(code, 0, 'exit ok') - var re = new RegExp("name: 'underscore'") - t.similar(stdout, re, 'should have name `underscore`') + t.matches(stdout, /underscore/, 'should have name `underscore`') t.end() }) }) @@ -232,8 +230,7 @@ test('npm view <package name> --global', function (t) { ], { cwd: t2dir }, function (err, code, stdout) { t.ifError(err, 'view command finished successfully') t.equal(code, 0, 'exit ok') - var re = new RegExp("name: 'underscore'") - t.similar(stdout, re, 'should have name `underscore`') + t.matches(stdout, /underscore/, 'should have name `underscore`') t.end() }) }) @@ -370,7 +367,7 @@ test('npm view with valid but non existent package name', function (t) { t.equal(code, 1, 'exit not ok') t.similar(stderr, - new RegExp("'valid-but-non-existent-package' is not in the npm registry\."), + new RegExp("'valid-but-non-existent-package' is not in the npm registry\\."), 'Package should NOT be found') t.similar(stderr, new RegExp('use the name yourself!'), |