1var fs = require('graceful-fs') 2var path = require('path') 3 4var mkdirp = require('mkdirp') 5var mr = require('npm-registry-mock') 6var osenv = require('osenv') 7var rimraf = require('rimraf') 8var test = require('tap').test 9 10var common = require('../common-tap.js') 11var server 12 13var pkg = path.resolve(__dirname, 'update-save') 14var cache = path.resolve(pkg, 'cache') 15 16var EXEC_OPTS = { 17 cwd: pkg, 18 stdio: 'ignore', 19 env: { 20 npm_config_registry: common.registry, 21 npm_config_loglevel: 'verbose', 22 npm_config_save_prefix: '^' 23 } 24} 25 26var json = { 27 name: 'update-save-example', 28 version: '1.2.3', 29 dependencies: { 30 mkdirp: '~0.3.0' 31 }, 32 devDependencies: { 33 underscore: '~1.3.1' 34 } 35} 36 37function clone (a) { 38 return extend({}, a) 39} 40 41function extend (a, b) { 42 for (var key in b) { a[key] = b[key] } 43 return a 44} 45 46test('setup', function (t) { 47 setup() 48 49 mr({ port: common.port }, function (er, s) { 50 t.ifError(er) 51 server = s 52 t.end() 53 }) 54}) 55 56test('update regular dependencies only', function (t) { 57 setup() 58 59 common.npm(['update', '--save'], EXEC_OPTS, function (err, code) { 60 t.ifError(err) 61 t.notOk(code, 'npm update exited with code 0') 62 63 var pkgdata = JSON.parse(fs.readFileSync(path.join(pkg, 'package.json'), 'utf8')) 64 t.deepEqual( 65 pkgdata.dependencies, 66 { mkdirp: '^0.3.5' }, 67 'only dependencies updated' 68 ) 69 t.deepEqual( 70 pkgdata.devDependencies, 71 json.devDependencies, 72 'dev dependencies should be untouched' 73 ) 74 t.deepEqual( 75 pkgdata.optionalDependencies, 76 json.optionalDependencies, 77 'optional dependencies should be untouched' 78 ) 79 80 t.end() 81 }) 82}) 83 84test('update devDependencies only', function (t) { 85 setup() 86 87 common.npm(['update', '--save-dev'], EXEC_OPTS, function (err, code) { 88 t.ifError(err) 89 t.notOk(code, 'npm update exited with code 0') 90 91 var pkgdata = JSON.parse(fs.readFileSync(path.join(pkg, 'package.json'), 'utf8')) 92 t.deepEqual( 93 pkgdata.dependencies, 94 json.dependencies, 95 'dependencies should be untouched' 96 ) 97 t.deepEqual( 98 pkgdata.devDependencies, 99 { underscore: '^1.3.3' }, 100 'dev dependencies should be updated' 101 ) 102 t.deepEqual( 103 pkgdata.optionalDependencies, 104 json.optionalDependencies, 105 'optional dependencies should be untouched' 106 ) 107 108 t.end() 109 }) 110}) 111 112test('update optionalDependencies only', function (t) { 113 setup({ optionalDependencies: { underscore: '~1.3.1' } }) 114 115 common.npm(['update', '--save-optional'], EXEC_OPTS, function (err, code) { 116 t.ifError(err) 117 t.notOk(code, 'npm update exited with code 0') 118 119 var pkgdata = JSON.parse(fs.readFileSync(path.join(pkg, 'package.json'), 'utf8')) 120 t.deepEqual( 121 pkgdata.dependencies, 122 json.dependencies, 123 'dependencies should be untouched' 124 ) 125 t.deepEqual( 126 pkgdata.devDependencies, 127 json.devDependencies, 128 'dev dependencies should be untouched' 129 ) 130 t.deepEqual( 131 pkgdata.optionalDependencies, 132 { underscore: '^1.3.3' }, 133 'optional dependencies should be updated' 134 ) 135 136 t.end() 137 }) 138}) 139 140test('optionalDependencies are merged into dependencies during --save', function (t) { 141 var cloned = setup({ optionalDependencies: { underscore: '~1.3.1' } }) 142 143 common.npm(['update', '--save'], EXEC_OPTS, function (err, code) { 144 t.ifError(err) 145 t.notOk(code, 'npm update exited with code 0') 146 147 var pkgdata = JSON.parse(fs.readFileSync(path.join(pkg, 'package.json'), 'utf8')) 148 t.deepEqual( 149 pkgdata.dependencies, 150 { mkdirp: '^0.3.5' }, 151 'dependencies should not include optional dependencies' 152 ) 153 t.deepEqual( 154 pkgdata.devDependencies, 155 cloned.devDependencies, 156 'dev dependencies should be untouched' 157 ) 158 t.deepEqual( 159 pkgdata.optionalDependencies, 160 cloned.optionalDependencies, 161 'optional dependencies should be untouched' 162 ) 163 164 t.end() 165 }) 166}) 167 168test('semver prefix is replaced with configured save-prefix', function (t) { 169 setup() 170 171 common.npm(['update', '--save', '--save-prefix', '~'], EXEC_OPTS, function (err, code) { 172 t.ifError(err) 173 t.notOk(code, 'npm update exited with code 0') 174 175 var pkgdata = JSON.parse(fs.readFileSync(path.join(pkg, 'package.json'), 'utf8')) 176 t.deepEqual( 177 pkgdata.dependencies, 178 { mkdirp: '~0.3.5' }, 179 'dependencies should be updated' 180 ) 181 t.deepEqual( 182 pkgdata.devDependencies, 183 json.devDependencies, 184 'dev dependencies should be untouched' 185 ) 186 t.deepEqual( 187 pkgdata.optionalDependencies, 188 json.optionalDependencies, 189 'optional dependencies should be updated' 190 ) 191 192 t.end() 193 }) 194}) 195 196test('cleanup', function (t) { 197 server.close() 198 cleanup() 199 t.end() 200}) 201 202function cleanup () { 203 process.chdir(osenv.tmpdir()) 204 rimraf.sync(pkg) 205} 206 207function setup (extendWith) { 208 cleanup() 209 mkdirp.sync(cache) 210 process.chdir(pkg) 211 212 var template = clone(json) 213 extend(template, extendWith) 214 fs.writeFileSync( 215 path.join(pkg, 'package.json'), 216 JSON.stringify(template, null, 2) 217 ) 218 return template 219} 220