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