1const t = require('tap') 2const common = require('../common-tap.js') 3const pkg = common.pkg 4 5const { writeFileSync, readFileSync, readlink } = require('fs') 6const readCmdShim = require('read-cmd-shim') 7const path = require('path') 8const readBinCb = process.platform === 'win32' ? readCmdShim : readlink 9const readBin = bin => new Promise((resolve, reject) => { 10 readBinCb(bin, (er, target) => { 11 if (er) { 12 reject(er) 13 } else { 14 resolve(path.resolve(path.dirname(bin), target)) 15 } 16 }) 17}) 18 19// verify that we can't overwrite bins that we shouldn't be able to 20 21const mkdirp = require('mkdirp').sync 22 23process.env.npm_config_prefix = pkg + '/global' 24process.env.npm_config_global = true 25 26const globalBin = process.platform === 'win32' 27 ? path.resolve(pkg, 'global') 28 : path.resolve(pkg, 'global/bin') 29 30const globalDir = process.platform === 'win32' 31 ? path.resolve(pkg, 'global/node_modules') 32 : path.resolve(pkg, 'global/lib/node_modules') 33 34const beep = path.resolve(globalBin, 'beep') 35const firstBin = path.resolve(globalDir, 'first/first.js') 36const secondBin = path.resolve(globalDir, 'second/second.js') 37 38t.test('setup', { bail: true }, t => { 39 // set up non-link bin in place 40 mkdirp(globalBin) 41 writeFileSync(beep, 'beep boop') 42 43 // create first package 44 mkdirp(pkg + '/first') 45 writeFileSync(pkg + '/first/package.json', JSON.stringify({ 46 name: 'first', 47 version: '1.0.0', 48 bin: { beep: 'first.js' } 49 })) 50 writeFileSync(pkg + '/first/first.js', `#!/usr/bin/env node 51 console.log('first')`) 52 53 // create second package 54 mkdirp(pkg + '/second') 55 writeFileSync(pkg + '/second/package.json', JSON.stringify({ 56 name: 'second', 57 version: '1.0.0', 58 bin: { beep: 'second.js' } 59 })) 60 writeFileSync(pkg + '/second/second.js', `#!/usr/bin/env node 61 console.log('second')`) 62 63 // pack both to install globally 64 return common.npm(['pack'], { cwd: pkg + '/first' }) 65 .then(() => common.npm(['pack'], { cwd: pkg + '/second' })) 66}) 67 68t.test('installing first fails, because pre-existing bin in place', t => { 69 return common.npm([ 70 'install', 71 pkg + '/first/first-1.0.0.tgz' 72 ]).then(([code, stdout, stderr]) => { 73 t.notEqual(code, 0) 74 t.match(stderr, 'EEXIST') 75 t.equal(readFileSync(beep, 'utf8'), 'beep boop') 76 }) 77}) 78 79t.test('installing first with --force succeeds', t => { 80 return common.npm([ 81 'install', 82 pkg + '/first/first-1.0.0.tgz', 83 '--force' 84 ]).then(() => { 85 return t.resolveMatch(readBin(beep), firstBin, 'bin written to first.js') 86 }) 87}) 88 89t.test('installing second fails, because bin links to other package', t => { 90 return common.npm([ 91 'install', 92 pkg + '/second/second-1.0.0.tgz' 93 ]).then(([code, stdout, stderr]) => { 94 t.notEqual(code, 0) 95 t.match(stderr, 'EEXIST') 96 return t.resolveMatch(readBin(beep), firstBin, 'bin still linked to first') 97 }) 98}) 99 100t.test('installing second with --force succeeds', t => { 101 return common.npm([ 102 'install', 103 pkg + '/second/second-1.0.0.tgz', 104 '--force' 105 ]).then(() => { 106 return t.resolveMatch(readBin(beep), secondBin, 'bin written to second.js') 107 }) 108}) 109