1var common = require('../common-tap.js') 2var test = require('tap').test 3var mkdirp = require('mkdirp') 4var mr = require('npm-registry-mock') 5var requireInject = require('require-inject') 6 7var PKG_DIR = common.pkg 8var CACHE_DIR = common.cache 9 10// ** constant templates for mocks ** 11var DEFAULT_PKG = { 12 'name': 'update-examples', 13 'version': '1.2.3', 14 'dependencies': { 15 'dep1': '*' 16 } 17} 18 19var DEP_PKG = { 20 name: 'dep1', 21 version: '1.1.1', 22 _from: '^1.1.1' 23} 24 25var INSTALLED = { 26 path: '/mock/root', 27 realpath: '/mock/root', 28 isLink: false, 29 package: DEFAULT_PKG, 30 children: [ 31 { 32 path: '/mock/root/node_modules/dep1', 33 realpath: '/mock/root/node_modules/dep1', 34 isLink: false, 35 package: DEP_PKG, 36 children: [] 37 } 38 ] 39} 40 41var DEP1_REGISTRY = { name: 'dep1', 42 'dist-tags': { latest: '1.2.2' }, 43 versions: { 44 '1.2.2': { version: '1.2.2' }, 45 '1.2.1': { version: '1.2.1' }, 46 '1.2.0': { version: '1.2.0' }, 47 '1.1.2': { version: '1.1.2' }, 48 '1.1.1': { version: '1.1.1' }, 49 '1.0.0': { version: '1.0.0' }, 50 '0.4.1': { version: '0.4.1' }, 51 '0.4.0': { version: '0.4.0' }, 52 '0.2.0': { version: '0.2.0' } 53 } 54} 55 56var registryMocks = { 57 'get': { 58 '/dep1': [200, DEP1_REGISTRY] 59 } 60} 61 62// ** dynamic mocks, cloned from templates and modified ** 63var mockDepJson = clone(DEP_PKG) 64var mockInstalled = clone(INSTALLED) 65var mockParentJson = clone(DEFAULT_PKG) 66 67// target 68var installAskedFor 69 70function clone (a) { 71 return extend({}, a) 72} 73 74function extend (a, b) { 75 for (var key in b) { 76 a[key] = b[key] 77 } 78 return a 79} 80 81const path = require('path') 82let cacheIteration = 0 83const isRoot = process.getuid && process.getuid() === 0 84const sudoUID = isRoot ? +process.env.SUDO_UID : null 85const sudoGID = isRoot ? +process.env.SUDO_GID : null 86const { chownSync } = require('fs') 87function resetPackage (options) { 88 CACHE_DIR = path.resolve(common.cache, '' + cacheIteration++) 89 npm.config.set('cache', CACHE_DIR) 90 mkdirp.sync(CACHE_DIR) 91 92 if (isRoot && sudoUID && sudoGID) { 93 chownSync(CACHE_DIR, sudoUID, sudoGID) 94 } 95 96 installAskedFor = undefined 97 98 mockParentJson = clone(DEFAULT_PKG) 99 mockInstalled = clone(INSTALLED) 100 mockDepJson = clone(DEP_PKG) 101 102 if (options.wanted) { 103 mockParentJson.dependencies.dep1 = options.wanted 104 mockInstalled.package.dependencies.dep1 = options.wanted 105 mockDepJson._from = options.wanted 106 } 107 108 if (options.installed) { 109 mockInstalled.package.dependencies.dep1 = options.installed 110 mockInstalled.children[0].package.version = options.installed 111 mockDepJson.version = options.installed 112 } 113} 114 115function mockReadPackageTree (dir, cb) { 116 cb(null, mockInstalled) 117} 118 119function mockReadJson (file, cb) { 120 cb(null, file.match(/dep1/) ? mockDepJson : mockParentJson) 121} 122 123function mockCommand (npm, name, fn) { 124 delete npm.commands[name] 125 npm.commands[name] = fn 126} 127 128function mockInstaller (where, dryrun, what) { 129 installAskedFor = what[0] 130} 131mockInstaller.prototype = {} 132mockInstaller.prototype.run = function (cb) { 133 return cb ? cb() : Promise.resolve() 134} 135 136var npm = requireInject.installGlobally('../../lib/npm.js', { 137 'read-package-tree': mockReadPackageTree, 138 'read-package-json': mockReadJson, 139 '../../lib/install': { 140 Installer: mockInstaller 141 } 142}) 143 144test('setup', function (t) { 145 t.plan(5) 146 process.chdir(PKG_DIR) 147 t.pass('made ' + PKG_DIR) 148 149 mr({ port: common.port, mocks: registryMocks }, function (er, server) { 150 t.pass('mock registry active') 151 npm.load({ 152 cache: CACHE_DIR, 153 registry: common.registry, 154 cwd: PKG_DIR 155 }, function (err) { 156 t.ifError(err, 'started server') 157 t.parent.teardown(() => server.close()) 158 159 t.pass('npm.load complete') 160 161 mockCommand(npm, 'install', function mockInstall (where, what, cb) { 162 installAskedFor = what 163 cb(null) 164 }) 165 166 t.pass('mocks configured') 167 t.end() 168 }) 169 }) 170}) 171 172test('update caret dependency to latest', function (t) { 173 resetPackage({ wanted: '^1.1.1' }) 174 175 npm.config.set('loglevel', 'silly') 176 npm.commands.update([], function (err) { 177 t.ifError(err) 178 t.equal(installAskedFor, 'dep1@1.2.2', 'should want to install dep@1.2.2') 179 t.end() 180 }) 181}) 182 183test('update tilde dependency to latest', function (t) { 184 resetPackage({ wanted: '~1.1.1' }) 185 186 npm.commands.update([], function (err) { 187 t.ifError(err) 188 t.equal(installAskedFor, 'dep1@1.1.2', 'should want to install dep@1.1.2') 189 t.end() 190 }) 191}) 192 193test('hold tilde dependency at wanted (#6441)', function (t) { 194 resetPackage({ wanted: '~1.1.2', installed: '1.1.2' }) 195 196 npm.commands.update([], function (err) { 197 t.ifError(err) 198 t.notOk(installAskedFor, 'should not want to install anything') 199 t.end() 200 }) 201}) 202 203test('update old caret dependency with no newer', function (t) { 204 resetPackage({ wanted: '^0.2.0', installed: '^0.2.0' }) 205 206 npm.commands.update([], function (err) { 207 t.ifError(err) 208 t.equal(installAskedFor, 'dep1@0.2.0', 'should want to install dep@0.2.0') 209 t.end() 210 }) 211}) 212 213test('update old caret dependency with newer', function (t) { 214 resetPackage({ wanted: '^0.4.0', installed: '^0.4.0' }) 215 216 npm.commands.update([], function (err) { 217 t.ifError(err) 218 t.equal(installAskedFor, 'dep1@0.4.1', 'should want to install dep@0.4.1') 219 t.end() 220 }) 221}) 222