1var fs = require('graceful-fs') 2var path = require('path') 3 4var mkdirp = require('mkdirp') 5var test = require('tap').test 6var rimraf = require('rimraf') 7 8var common = require('../common-tap') 9 10var pkg = common.pkg 11var cache = common.cache 12var tmp = path.resolve(pkg, 'tmp') 13 14var opts = { cwd: pkg } 15 16var fullyPopulated = { 17 'name': 'runscript', 18 'version': '1.2.3', 19 'scripts': { 20 'start': 'node -e "console.log(process.argv[1] || \'start\')"', 21 'prewith-pre': 'node -e "console.log(process.argv[1] || \'pre\')"', 22 'with-pre': 'node -e "console.log(process.argv[1] || \'main\')"', 23 'with-post': 'node -e "console.log(process.argv[1] || \'main\')"', 24 'postwith-post': 'node -e "console.log(process.argv[1] || \'post\')"', 25 'prewith-both': 'node -e "console.log(process.argv[1] || \'pre\')"', 26 'with-both': 'node -e "console.log(process.argv[1] || \'main\')"', 27 'postwith-both': 'node -e "console.log(process.argv[1] || \'post\')"', 28 'stop': 'node -e "console.log(process.argv[1] || \'stop\')"', 29 'env-vars': 'node -e "console.log(process.env.run_script_foo_var)"', 30 'npm-env-vars': 'node -e "console.log(process.env.npm_run_script_foo_var)"', 31 'package-env-vars': 'node -e "console.log(process.env.run_script_foo_var)"', 32 'prefixed-package-env-vars': 'node -e "console.log(process.env.npm_package_run_script_foo_var)"' 33 }, 34 'run_script_foo_var': 'run_script_test_foo_val' 35} 36 37var lifecycleOnly = { 38 name: 'scripted', 39 version: '1.2.3', 40 scripts: { 41 'prestart': 'echo prestart' 42 } 43} 44 45var directOnly = { 46 name: 'scripted', 47 version: '1.2.3', 48 scripts: { 49 'whoa': 'echo whoa' 50 } 51} 52 53var both = { 54 name: 'scripted', 55 version: '1.2.3', 56 scripts: { 57 'prestart': 'echo prestart', 58 'whoa': 'echo whoa' 59 } 60} 61 62var preversionOnly = { 63 name: 'scripted', 64 version: '1.2.3', 65 scripts: { 66 'preversion': 'echo preversion' 67 } 68} 69 70var exitCode = { 71 name: 'scripted', 72 version: '1.2.3', 73 scripts: { 74 'start': 'node -e "process.exit(7)"' 75 } 76} 77 78var shell = { 79 name: 'scripted', 80 version: '1.2.3', 81 scripts: { 82 'start': 'echo foo' 83 } 84} 85 86function testOutput (t, command, er, code, stdout, stderr) { 87 var lines 88 89 if (er) throw er 90 91 if (stderr) { 92 throw new Error('npm ' + command + ' stderr: ' + stderr.toString()) 93 } 94 95 lines = stdout.trim().split('\n') 96 stdout = lines.filter(function (line) { 97 return line.trim() !== '' && line[0] !== '>' 98 }).join(';') 99 100 t.equal(stdout, command) 101 t.end() 102} 103 104function writeMetadata (object) { 105 fs.writeFileSync( 106 path.resolve(pkg, 'package.json'), 107 JSON.stringify(object, null, 2) + '\n' 108 ) 109} 110 111function cleanup () { 112 rimraf.sync(pkg) 113} 114 115test('setup', function (t) { 116 cleanup() 117 mkdirp.sync(cache) 118 mkdirp.sync(tmp) 119 writeMetadata(fullyPopulated) 120 t.end() 121}) 122 123test('npm run-script start', function (t) { 124 common.npm(['run-script', 'start'], opts, testOutput.bind(null, t, 'start')) 125}) 126 127test('npm run-script with args', function (t) { 128 common.npm(['run-script', 'start', '--', 'stop'], opts, testOutput.bind(null, t, 'stop')) 129}) 130 131test('npm run-script with args that contain spaces', function (t) { 132 common.npm(['run-script', 'start', '--', 'hello world'], opts, testOutput.bind(null, t, 'hello world')) 133}) 134 135test('npm run-script with args that contain single quotes', function (t) { 136 common.npm(['run-script', 'start', '--', 'they"re awesome'], opts, testOutput.bind(null, t, 'they"re awesome')) 137}) 138 139test('npm run-script with args that contain double quotes', function (t) { 140 common.npm(['run-script', 'start', '--', 'what"s "up"?'], opts, testOutput.bind(null, t, 'what"s "up"?')) 141}) 142 143test('npm run-script with args that contain ticks', function (t) { 144 common.npm(['run-script', 'start', '--', 'what\'s \'up\'?'], opts, testOutput.bind(null, t, 'what\'s \'up\'?')) 145}) 146 147test('npm run-script with pre script', function (t) { 148 common.npm(['run-script', 'with-post'], opts, testOutput.bind(null, t, 'main;post')) 149}) 150 151test('npm run-script with post script', function (t) { 152 common.npm(['run-script', 'with-pre'], opts, testOutput.bind(null, t, 'pre;main')) 153}) 154 155test('npm run-script with both pre and post script', function (t) { 156 common.npm(['run-script', 'with-both'], opts, testOutput.bind(null, t, 'pre;main;post')) 157}) 158 159test('npm run-script with both pre and post script and with args', function (t) { 160 common.npm(['run-script', 'with-both', '--', 'an arg'], opts, testOutput.bind(null, t, 'pre;an arg;post')) 161}) 162 163test('npm run-script explicitly call pre script with arg', function (t) { 164 common.npm(['run-script', 'prewith-pre', '--', 'an arg'], opts, testOutput.bind(null, t, 'an arg')) 165}) 166 167test('npm run-script test', function (t) { 168 common.npm(['run-script', 'test'], opts, function (er, code, stdout, stderr) { 169 t.ifError(er, 'npm run-script test ran without issue') 170 t.notOk(stderr, 'should not generate errors') 171 t.end() 172 }) 173}) 174 175test('npm run-script env', function (t) { 176 common.npm(['run-script', 'env'], opts, function (er, code, stdout, stderr) { 177 t.ifError(er, 'using default env script') 178 t.notOk(stderr, 'should not generate errors') 179 t.ok(stdout.indexOf('npm_config_init_version') > 0, 'expected values in var list') 180 t.end() 181 }) 182}) 183 184test('npm run-script nonexistent-script', function (t) { 185 common.npm(['run-script', 'nonexistent-script'], opts, function (er, code, stdout, stderr) { 186 t.ifError(er, 'npm run-script nonexistent-script did not cause npm to explode') 187 t.ok(stderr, 'should generate errors') 188 t.end() 189 }) 190}) 191 192test('npm run-script restart when there isn\'t restart', function (t) { 193 common.npm(['run-script', 'restart'], opts, testOutput.bind(null, t, 'stop;start')) 194}) 195 196test('npm run-script nonexistent-script with --if-present flag', function (t) { 197 common.npm(['run-script', '--if-present', 'nonexistent-script'], opts, function (er, code, stdout, stderr) { 198 t.ifError(er, 'npm run-script --if-present non-existent-script ran without issue') 199 t.notOk(stderr, 'should not generate errors') 200 t.end() 201 }) 202}) 203 204test('npm run-script env vars accessible', function (t) { 205 process.env.run_script_foo_var = 'run_script_test_foo_val' 206 common.npm(['run-script', 'env-vars'], { 207 cwd: pkg 208 }, function (err, code, stdout, stderr) { 209 t.ifError(err, 'ran run-script without crashing') 210 t.equal(code, 0, 'exited normally') 211 t.equal(stderr, '', 'no error output') 212 t.match(stdout, 213 new RegExp(process.env.run_script_foo_var), 214 'script had env access') 215 t.end() 216 }) 217}) 218 219test('npm run-script package.json vars injected', function (t) { 220 common.npm(['run-script', 'package-env-vars'], { 221 cwd: pkg 222 }, function (err, code, stdout, stderr) { 223 t.ifError(err, 'ran run-script without crashing') 224 t.equal(code, 0, 'exited normally') 225 t.equal(stderr, '', 'no error output') 226 t.match(stdout, 227 new RegExp(fullyPopulated.run_script_foo_var), 228 'script injected package.json value') 229 t.end() 230 }) 231}) 232 233test('npm run-script package.json vars injected with prefix', function (t) { 234 common.npm(['run-script', 'prefixed-package-env-vars'], { 235 cwd: pkg 236 }, function (err, code, stdout, stderr) { 237 t.ifError(err, 'ran run-script without crashing') 238 t.equal(code, 0, 'exited normally') 239 t.equal(stderr, '', 'no error output') 240 t.match(stdout, 241 new RegExp(fullyPopulated.run_script_foo_var), 242 'script injected npm_package-prefixed package.json value') 243 t.end() 244 }) 245}) 246 247test('npm run-script env vars stripped npm-prefixed', function (t) { 248 process.env.npm_run_script_foo_var = 'run_script_test_foo_val' 249 common.npm(['run-script', 'npm-env-vars'], { 250 cwd: pkg 251 }, function (err, code, stdout, stderr) { 252 t.ifError(err, 'ran run-script without crashing') 253 t.equal(code, 0, 'exited normally') 254 t.equal(stderr, '', 'no error output') 255 t.notMatch(stdout, 256 new RegExp(process.env.npm_run_script_foo_var), 257 'script stripped npm-prefixed env var') 258 t.end() 259 }) 260}) 261 262test('npm run-script no-params (lifecycle only)', function (t) { 263 var expected = [ 264 'Lifecycle scripts included in scripted:', 265 ' prestart', 266 ' echo prestart', 267 '' 268 ].join('\n') 269 270 writeMetadata(lifecycleOnly) 271 272 common.npm(['run-script'], opts, function (err, code, stdout, stderr) { 273 t.ifError(err, 'ran run-script without parameters without crashing') 274 t.notOk(code, 'npm exited without error code') 275 t.notOk(stderr, 'npm printed nothing to stderr') 276 t.equal(stdout, expected, 'got expected output') 277 t.end() 278 }) 279}) 280 281test('npm run-script no-params (preversion only)', function (t) { 282 var expected = [ 283 'Lifecycle scripts included in scripted:', 284 ' preversion', 285 ' echo preversion', 286 '' 287 ].join('\n') 288 289 writeMetadata(preversionOnly) 290 291 common.npm(['run-script'], opts, function (err, code, stdout, stderr) { 292 t.ifError(err, 'ran run-script without parameters without crashing') 293 t.notOk(code, 'npm exited without error code') 294 t.notOk(stderr, 'npm printed nothing to stderr') 295 t.equal(stdout, expected, 'got expected output') 296 t.end() 297 }) 298}) 299 300test('npm run-script no-params (direct only)', function (t) { 301 var expected = [ 302 'Scripts available in scripted via `npm run-script`:', 303 ' whoa', 304 ' echo whoa', 305 '' 306 ].join('\n') 307 308 writeMetadata(directOnly) 309 310 common.npm(['run-script'], opts, function (err, code, stdout, stderr) { 311 t.ifError(err, 'ran run-script without parameters without crashing') 312 t.notOk(code, 'npm exited without error code') 313 t.notOk(stderr, 'npm printed nothing to stderr') 314 t.equal(stdout, expected, 'got expected output') 315 t.end() 316 }) 317}) 318 319test('npm run-script script-shell config', function (t) { 320 writeMetadata(shell) 321 322 common.npm(['run-script', 'start', '--script-shell', 'echo'], opts, testOutput.bind(null, t, '-c echo foo')) 323}) 324 325test('npm run-script no-params (direct only)', function (t) { 326 var expected = [ 327 'Lifecycle scripts included in scripted:', 328 ' prestart', 329 ' echo prestart', 330 '', 331 'available via `npm run-script`:', 332 ' whoa', 333 ' echo whoa', 334 '' 335 ].join('\n') 336 337 writeMetadata(both) 338 339 common.npm(['run-script'], opts, function (err, code, stdout, stderr) { 340 t.ifError(err, 'ran run-script without parameters without crashing') 341 t.notOk(code, 'npm exited without error code') 342 t.notOk(stderr, 'npm printed nothing to stderr') 343 t.equal(stdout, expected, 'got expected output') 344 t.end() 345 }) 346}) 347 348test('npm run-script keep non-zero exit code', function (t) { 349 writeMetadata(exitCode) 350 351 common.npm(['run-script', 'start'], opts, function (err, code, stdout, stderr) { 352 t.ifError(err, 'ran run-script without parameters without crashing') 353 t.equal(code, 7, 'got expected exit code') 354 t.ok(stderr, 'should generate errors') 355 t.end() 356 }) 357}) 358 359test('npm run-script nonexistent script and display suggestions', function (t) { 360 writeMetadata(directOnly) 361 362 common.npm(['run-script', 'whoop'], opts, function (err, code, stdout, stderr) { 363 t.ifError(err, 'ran run-script without crashing') 364 t.equal(code, 1, 'got expected exit code') 365 t.has(stderr, 'Did you mean this?') 366 t.end() 367 }) 368}) 369 370test('cleanup', function (t) { 371 cleanup() 372 t.end() 373}) 374