• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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