1const { readFileSync, statSync } = require('fs') 2const { resolve } = require('path') 3const t = require('tap') 4const _mockNpm = require('../../fixtures/mock-npm') 5const mockGlobals = require('@npmcli/mock-globals') 6 7const mockNpm = async (t, opts = {}) => { 8 const res = await _mockNpm(t, { 9 ...opts, 10 command: 'version', 11 mocks: { 12 ...opts.mocks, 13 '{ROOT}/package.json': { version: '1.0.0' }, 14 }, 15 }) 16 return { 17 ...res, 18 result: () => res.outputs[0], 19 } 20} 21 22t.test('node@1', async t => { 23 mockGlobals(t, { 'process.versions': { node: '1.0.0' } }, { replace: true }) 24 25 t.test('no args', async t => { 26 const { version, result } = await mockNpm(t, { 27 prefixDir: { 28 'package.json': JSON.stringify({ 29 name: 'test-version-no-args', 30 version: '3.2.1', 31 }), 32 }, 33 }) 34 35 await version.exec([]) 36 37 t.strictSame( 38 result(), 39 [{ 40 'test-version-no-args': '3.2.1', 41 node: '1.0.0', 42 npm: '1.0.0', 43 }], 44 'should output expected values for various versions in npm' 45 ) 46 }) 47 48 t.test('too many args', async t => { 49 const { version } = await mockNpm(t) 50 await t.rejects( 51 version.exec(['foo', 'bar']), 52 /npm version/, 53 'should throw usage instructions error' 54 ) 55 }) 56 57 t.test('completion', async t => { 58 const { version } = await mockNpm(t) 59 const testComp = async (argv, expect) => { 60 const res = await version.completion({ conf: { argv: { remain: argv } } }) 61 t.strictSame(res, expect, argv.join(' ')) 62 } 63 64 await testComp( 65 ['npm', 'version'], 66 ['major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch', 'prerelease', 'from-git'] 67 ) 68 await testComp(['npm', 'version', 'major'], []) 69 }) 70 71 t.test('failure reading package.json', async t => { 72 const { version, result } = await mockNpm(t) 73 74 await version.exec([]) 75 76 t.strictSame( 77 result(), 78 [{ 79 npm: '1.0.0', 80 node: '1.0.0', 81 }], 82 'should not have package name on returning object' 83 ) 84 }) 85}) 86 87t.test('empty versions', async t => { 88 mockGlobals(t, { 'process.versions': {} }, { replace: true }) 89 90 t.test('--json option', async t => { 91 const { version, result } = await mockNpm(t, { 92 config: { json: true }, 93 }) 94 95 await version.exec([]) 96 t.same(result(), ['{\n "npm": "1.0.0"\n}'], 'should return json stringified result') 97 }) 98 99 t.test('with one arg', async t => { 100 const { version, result } = await mockNpm(t, { 101 mocks: { 102 libnpmversion: () => '4.0.0', 103 }, 104 }) 105 106 await version.exec(['major']) 107 t.same(result(), ['v4.0.0'], 'outputs the new version prefixed by the tagVersionPrefix') 108 }) 109 110 t.test('workspaces', async t => { 111 t.test('no args, all workspaces', async t => { 112 const { version, result } = await mockNpm(t, { 113 prefixDir: { 114 'package.json': JSON.stringify( 115 { 116 name: 'workspaces-test', 117 version: '1.0.0', 118 workspaces: ['workspace-a', 'workspace-b'], 119 }, 120 null, 121 2 122 ), 123 'workspace-a': { 124 'package.json': JSON.stringify({ 125 name: 'workspace-a', 126 version: '1.0.0', 127 }), 128 }, 129 'workspace-b': { 130 'package.json': JSON.stringify({ 131 name: 'workspace-b', 132 version: '1.0.0', 133 }), 134 }, 135 }, 136 config: { workspaces: true }, 137 }) 138 139 await version.exec([]) 140 t.same( 141 result(), 142 [ 143 { 144 'workspaces-test': '1.0.0', 145 'workspace-a': '1.0.0', 146 'workspace-b': '1.0.0', 147 npm: '1.0.0', 148 }, 149 ], 150 'outputs includes main package and workspace versions' 151 ) 152 }) 153 154 t.test('no args, single workspaces', async t => { 155 const { version, result } = await mockNpm(t, { 156 prefixDir: { 157 'package.json': JSON.stringify( 158 { 159 name: 'workspaces-test', 160 version: '1.0.0', 161 workspaces: ['workspace-a', 'workspace-b'], 162 }, 163 null, 164 2 165 ), 166 'workspace-a': { 167 'package.json': JSON.stringify({ 168 name: 'workspace-a', 169 version: '1.0.0', 170 }), 171 }, 172 'workspace-b': { 173 'package.json': JSON.stringify({ 174 name: 'workspace-b', 175 version: '1.0.0', 176 }), 177 }, 178 }, 179 config: { 180 workspace: 'workspace-a', 181 }, 182 }) 183 184 await version.exec([]) 185 t.same( 186 result(), 187 [ 188 { 189 'workspaces-test': '1.0.0', 190 'workspace-a': '1.0.0', 191 npm: '1.0.0', 192 }, 193 ], 194 'outputs includes main package and requested workspace versions' 195 ) 196 }) 197 198 t.test('no args, all workspaces, workspace with missing name or version', async t => { 199 const { version, result } = await mockNpm(t, { 200 prefixDir: { 201 'package.json': JSON.stringify( 202 { 203 name: 'workspaces-test', 204 version: '1.0.0', 205 workspaces: ['workspace-a', 'workspace-b', 'workspace-c'], 206 }, 207 null, 208 2 209 ), 210 'workspace-a': { 211 'package.json': JSON.stringify({ 212 name: 'workspace-a', 213 version: '1.0.0', 214 }), 215 }, 216 'workspace-b': { 217 'package.json': JSON.stringify({ 218 name: 'workspace-b', 219 }), 220 }, 221 'workspace-c': { 222 'package.json': JSON.stringify({ 223 version: '1.0.0', 224 }), 225 }, 226 }, 227 config: { workspaces: true }, 228 }) 229 230 await version.exec([]) 231 t.same( 232 result(), 233 [ 234 { 235 'workspaces-test': '1.0.0', 236 'workspace-a': '1.0.0', 237 npm: '1.0.0', 238 }, 239 ], 240 'outputs includes main package and valid workspace versions' 241 ) 242 }) 243 244 t.test('with one arg, all workspaces', async t => { 245 const { version, outputs, prefix } = await mockNpm(t, { 246 prefixDir: { 247 'package.json': JSON.stringify( 248 { 249 name: 'workspaces-test', 250 version: '1.0.0', 251 workspaces: ['workspace-a', 'workspace-b'], 252 }, 253 null, 254 2 255 ), 256 'workspace-a': { 257 'package.json': JSON.stringify({ 258 name: 'workspace-a', 259 version: '1.0.0', 260 }), 261 }, 262 'workspace-b': { 263 'package.json': JSON.stringify({ 264 name: 'workspace-b', 265 version: '1.0.0', 266 }), 267 }, 268 }, 269 config: { workspaces: true }, 270 }) 271 272 await version.exec(['major']) 273 t.same( 274 outputs.map(o => o[0]).slice(0, 4), 275 ['workspace-a', 'v2.0.0', 'workspace-b', 'v2.0.0'], 276 'outputs the new version for only the workspaces prefixed by the tagVersionPrefix' 277 ) 278 279 t.matchSnapshot(readFileSync(resolve(prefix, 'package-lock.json'), 'utf8')) 280 }) 281 282 t.test('with one arg, all workspaces, saves package.json', async t => { 283 const { version, outputs, prefix } = await mockNpm(t, { 284 prefixDir: { 285 'package.json': JSON.stringify( 286 { 287 name: 'workspaces-test', 288 version: '1.0.0', 289 workspaces: ['workspace-a', 'workspace-b'], 290 dependencies: { 291 'workspace-a': '^1.0.0', 292 'workspace-b': '^1.0.0', 293 }, 294 }, 295 null, 296 2 297 ), 298 'workspace-a': { 299 'package.json': JSON.stringify({ 300 name: 'workspace-a', 301 version: '1.0.0', 302 }), 303 }, 304 'workspace-b': { 305 'package.json': JSON.stringify({ 306 name: 'workspace-b', 307 version: '1.0.0', 308 }), 309 }, 310 }, 311 config: { 312 save: true, 313 workspaces: true, 314 }, 315 }) 316 317 await version.exec(['major']) 318 t.same( 319 outputs.map(o => o[0]).slice(0, 4), 320 ['workspace-a', 'v2.0.0', 'workspace-b', 'v2.0.0'], 321 'outputs the new version for only the workspaces prefixed by the tagVersionPrefix' 322 ) 323 324 t.matchSnapshot(readFileSync(resolve(prefix, 'package-lock.json'), 'utf8')) 325 }) 326 327 t.test('too many args', async t => { 328 const { version } = await mockNpm(t, { config: { workspaces: true } }) 329 330 await t.rejects( 331 version.exec(['foo', 'bar']), 332 /npm version/, 333 'should throw usage instructions error' 334 ) 335 }) 336 337 t.test('no workspaces-update', async t => { 338 const { version, outputs, prefix } = await mockNpm(t, { 339 prefixDir: { 340 'package.json': JSON.stringify( 341 { 342 name: 'workspaces-test', 343 version: '1.0.0', 344 workspaces: ['workspace-a', 'workspace-b'], 345 }, 346 null, 347 2 348 ), 349 'workspace-a': { 350 'package.json': JSON.stringify({ 351 name: 'workspace-a', 352 version: '1.0.0', 353 }), 354 }, 355 'workspace-b': { 356 'package.json': JSON.stringify({ 357 name: 'workspace-b', 358 version: '1.0.0', 359 }), 360 }, 361 }, 362 mocks: { 363 libnpmversion: (arg, opts) => { 364 return '2.0.0' 365 }, 366 }, 367 config: { 368 workspaces: true, 369 'workspaces-update': false, 370 }, 371 }) 372 373 await version.exec(['major']) 374 t.same( 375 outputs.map(o => o[0]).slice(0, 4), 376 ['workspace-a', 'v2.0.0', 'workspace-b', 'v2.0.0'], 377 'outputs the new version for only the workspaces prefixed by the tagVersionPrefix' 378 ) 379 380 t.throws( 381 () => statSync(resolve(prefix, 'package-lock.json')), 382 'should not have a lockfile since have not reified' 383 ) 384 }) 385 }) 386}) 387