diff options
Diffstat (limited to 'test/lib/npm.js')
-rw-r--r-- | test/lib/npm.js | 528 |
1 files changed, 261 insertions, 267 deletions
diff --git a/test/lib/npm.js b/test/lib/npm.js index 1ccd26e37..2a0c5a89d 100644 --- a/test/lib/npm.js +++ b/test/lib/npm.js @@ -1,7 +1,8 @@ const t = require('tap') +const { resolve, dirname } = require('path') -const npmlog = require('npmlog') -const { real: mockNpm } = require('../fixtures/mock-npm.js') +const { load: loadMockNpm } = require('../fixtures/mock-npm.js') +const mockGlobals = require('../fixtures/mock-globals') // delete this so that we don't have configs from the fact that it // is being run by 'npm test' @@ -15,7 +16,7 @@ for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e))) { // if this test is just run directly, which is also acceptable. if (event === 'test') { t.ok( - ['test', 'run-script'].some(i => i === event), + ['test', 'run-script'].some(i => i === process.env[env]), 'should match "npm test" or "npm run test"' ) } else { @@ -25,41 +26,14 @@ for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e))) { delete process.env[env] } -const { resolve, dirname } = require('path') - -const actualPlatform = process.platform -const beWindows = () => { - Object.defineProperty(process, 'platform', { - value: 'win32', - configurable: true, - }) -} -const bePosix = () => { - Object.defineProperty(process, 'platform', { - value: 'posix', - configurable: true, - }) -} -const argv = [...process.argv] - -t.afterEach(() => { +t.afterEach(async (t) => { for (const env of Object.keys(process.env).filter(e => /^npm_/.test(e))) { delete process.env[env] } - process.env.npm_config_cache = CACHE - process.argv = argv - Object.defineProperty(process, 'platform', { - value: actualPlatform, - configurable: true, - }) }) -const CACHE = t.testdir() -process.env.npm_config_cache = CACHE - t.test('not yet loaded', async t => { - const { Npm, logs } = mockNpm(t) - const npm = new Npm() + const { npm, logs } = await loadMockNpm(t, { load: false }) t.match(npm, { started: Number, command: null, @@ -79,8 +53,7 @@ t.test('not yet loaded', async t => { t.test('npm.load', async t => { t.test('load error', async t => { - const { Npm } = mockNpm(t) - const npm = new Npm() + const { npm } = await loadMockNpm(t, { load: false }) const loadError = new Error('load error') npm.config.load = async () => { throw loadError @@ -103,32 +76,28 @@ t.test('npm.load', async t => { }) t.test('basic loading', async t => { - const { Npm, logs } = mockNpm(t) - const npm = new Npm() - const dir = t.testdir({ - node_modules: {}, + const { npm, logs, prefix: dir, cache } = await loadMockNpm(t, { + testdir: { node_modules: {} }, }) - await npm.load() + t.equal(npm.loaded, true) t.equal(npm.config.loaded, true) t.equal(npm.config.get('force'), false) t.ok(npm.usage, 'has usage') - npm.config.set('prefix', dir) t.match(npm, { flatOptions: {}, }) - t.match(logs, [ - ['timing', 'npm:load', /Completed in [0-9.]+ms/], + t.match(logs.timing.filter(([p]) => p === 'npm:load'), [ + ['npm:load', /Completed in [0-9.]+ms/], ]) - bePosix() - t.equal(resolve(npm.cache), resolve(CACHE), 'cache is cache') + mockGlobals(t, { process: { platform: 'posix' } }) + t.equal(resolve(npm.cache), resolve(cache), 'cache is cache') const newCache = t.testdir() npm.cache = newCache t.equal(npm.config.get('cache'), newCache, 'cache setter sets config') t.equal(npm.cache, newCache, 'cache getter gets new config') - t.equal(npm.log, npmlog, 'npmlog getter') t.equal(npm.lockfileVersion, 2, 'lockfileVersion getter') t.equal(npm.prefix, npm.localPrefix, 'prefix is local prefix') t.not(npm.prefix, npm.globalPrefix, 'prefix is not global prefix') @@ -160,10 +129,9 @@ t.test('npm.load', async t => { t.equal(npm.bin, npm.globalBin, 'bin is global bin after prefix setter') t.not(npm.bin, npm.localBin, 'bin is not local bin after prefix setter') - beWindows() + mockGlobals(t, { process: { platform: 'win32' } }) t.equal(npm.bin, npm.globalBin, 'bin is global bin in windows mode') t.equal(npm.dir, npm.globalDir, 'dir is global dir in windows mode') - bePosix() const tmp = npm.tmp t.match(tmp, String, 'npm.tmp is a string') @@ -171,13 +139,12 @@ t.test('npm.load', async t => { }) t.test('forceful loading', async t => { - process.argv = [...process.argv, '--force', '--color', 'always'] - const { Npm, logs } = mockNpm(t) - const npm = new Npm() - await npm.load() - t.match(logs.filter(l => l[0] !== 'timing'), [ + mockGlobals(t, { + 'process.argv': [...process.argv, '--force', '--color', 'always'], + }) + const { logs } = await loadMockNpm(t) + t.match(logs.warn, [ [ - 'warn', 'using --force', 'Recommended protections disabled.', ], @@ -185,54 +152,42 @@ t.test('npm.load', async t => { }) t.test('node is a symlink', async t => { - const node = actualPlatform === 'win32' ? 'node.exe' : 'node' - const dir = t.testdir({ - '.npmrc': 'foo = bar', - bin: t.fixture('symlink', dirname(process.execPath)), + const node = process.platform === 'win32' ? 'node.exe' : 'node' + mockGlobals(t, { + 'process.argv': [ + node, + process.argv[1], + '--usage', + '--scope=foo', + 'token', + 'revoke', + 'blergggg', + ], }) - - const PATH = process.env.PATH || process.env.Path - process.env.PATH = resolve(dir, 'bin') - process.argv = [ - node, - process.argv[1], - '--prefix', dir, - '--userconfig', `${dir}/.npmrc`, - '--usage', - '--scope=foo', - 'token', - 'revoke', - 'blergggg', - ] - - t.teardown(() => { - process.env.PATH = PATH + const { npm, logs, outputs, prefix } = await loadMockNpm(t, { + testdir: { + bin: t.fixture('symlink', dirname(process.execPath)), + }, + globals: ({ prefix }) => ({ + 'process.env.PATH': resolve(prefix, 'bin'), + }), }) - const { Npm, logs, outputs } = mockNpm(t) - const npm = new Npm() - await npm.load() t.equal(npm.config.get('scope'), '@foo', 'added the @ sign to scope') - t.match(logs.filter(l => l[0] !== 'timing' || !/^config:/.test(l[1])), [ - [ - 'timing', - 'npm:load:whichnode', - /Completed in [0-9.]+ms/, - ], - [ - 'verbose', - 'node symlink', - resolve(dir, 'bin', node), - ], - [ - 'timing', - 'npm:load', - /Completed in [0-9.]+ms/, - ], + t.match([ + ...logs.timing.filter(([p]) => p === 'npm:load:whichnode'), + ...logs.verbose, + ...logs.timing.filter(([p]) => p === 'npm:load'), + ], [ + ['npm:load:whichnode', /Completed in [0-9.]+ms/], + ['node symlink', resolve(prefix, 'bin', node)], + ['logfile', /.*-debug-0.log/], + ['npm:load', /Completed in [0-9.]+ms/], ]) - t.equal(process.execPath, resolve(dir, 'bin', node)) + t.equal(process.execPath, resolve(prefix, 'bin', node)) outputs.length = 0 + logs.length = 0 await npm.exec('ll', []) t.equal(npm.command, 'll', 'command set to first npm command') @@ -271,33 +226,34 @@ t.test('npm.load', async t => { }) t.test('--no-workspaces with --workspace', async t => { - const dir = t.testdir({ - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - scripts: { test: 'echo test a' }, - }), + mockGlobals(t, { + 'process.argv': [ + process.execPath, + process.argv[1], + '--color', 'false', + '--workspaces', 'false', + '--workspace', 'a', + ], + }) + const { npm } = await loadMockNpm(t, { + load: false, + testdir: { + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + scripts: { test: 'echo test a' }, + }), + }, }, + 'package.json': JSON.stringify({ + name: 'root', + version: '1.0.0', + workspaces: ['./packages/*'], + }), }, - 'package.json': JSON.stringify({ - name: 'root', - version: '1.0.0', - workspaces: ['./packages/*'], - }), }) - process.argv = [ - process.execPath, - process.argv[1], - '--userconfig', resolve(dir, '.npmrc'), - '--color', 'false', - '--workspaces', 'false', - '--workspace', 'a', - ] - const { Npm } = mockNpm(t) - const npm = new Npm() - npm.localPrefix = dir await t.rejects( npm.exec('run', []), /Can not use --no-workspaces and --workspace at the same time/ @@ -305,47 +261,40 @@ t.test('npm.load', async t => { }) t.test('workspace-aware configs and commands', async t => { - const dir = t.testdir({ - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - scripts: { test: 'echo test a' }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - scripts: { test: 'echo test b' }, - }), + mockGlobals(t, { + 'process.argv': [ + process.execPath, + process.argv[1], + '--color', 'false', + '--workspaces', 'true', + ], + }) + const { npm, outputs } = await loadMockNpm(t, { + testdir: { + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + scripts: { test: 'echo test a' }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + scripts: { test: 'echo test b' }, + }), + }, }, + 'package.json': JSON.stringify({ + name: 'root', + version: '1.0.0', + workspaces: ['./packages/*'], + }), }, - 'package.json': JSON.stringify({ - name: 'root', - version: '1.0.0', - workspaces: ['./packages/*'], - }), - '.npmrc': '', }) - process.argv = [ - process.execPath, - process.argv[1], - '--userconfig', - resolve(dir, '.npmrc'), - '--color', - 'false', - '--workspaces', - 'true', - ] - - const { Npm, outputs } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.localPrefix = dir - // verify that calling the command with a short name still sets // the npm.command property to the full canonical name of the cmd. npm.command = null @@ -368,44 +317,42 @@ t.test('npm.load', async t => { }) t.test('workspaces in global mode', async t => { - const dir = t.testdir({ - packages: { - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - scripts: { test: 'echo test a' }, - }), - }, - b: { - 'package.json': JSON.stringify({ - name: 'b', - version: '1.0.0', - scripts: { test: 'echo test b' }, - }), + mockGlobals(t, { + 'process.argv': [ + process.execPath, + process.argv[1], + '--color', + 'false', + '--workspaces', + '--global', + 'true', + ], + }) + const { npm } = await loadMockNpm(t, { + testdir: { + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + version: '1.0.0', + scripts: { test: 'echo test a' }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + version: '1.0.0', + scripts: { test: 'echo test b' }, + }), + }, }, + 'package.json': JSON.stringify({ + name: 'root', + version: '1.0.0', + workspaces: ['./packages/*'], + }), }, - 'package.json': JSON.stringify({ - name: 'root', - version: '1.0.0', - workspaces: ['./packages/*'], - }), }) - process.argv = [ - process.execPath, - process.argv[1], - '--userconfig', - resolve(dir, '.npmrc'), - '--color', - 'false', - '--workspaces', - '--global', - 'true', - ] - const { Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() - npm.localPrefix = dir // verify that calling the command with a short name still sets // the npm.command property to the full canonical name of the cmd. npm.command = null @@ -418,109 +365,156 @@ t.test('npm.load', async t => { t.test('set process.title', async t => { t.test('basic title setting', async t => { - process.argv = [ - process.execPath, - process.argv[1], - '--usage', - '--scope=foo', - 'ls', - ] - const { Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() + mockGlobals(t, { + 'process.argv': [ + process.execPath, + process.argv[1], + '--usage', + '--scope=foo', + 'ls', + ], + }) + const { npm } = await loadMockNpm(t) t.equal(npm.title, 'npm ls') t.equal(process.title, 'npm ls') }) t.test('do not expose token being revoked', async t => { - process.argv = [ - process.execPath, - process.argv[1], - '--usage', - '--scope=foo', - 'token', - 'revoke', - 'deadbeefcafebad', - ] - const { Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() + mockGlobals(t, { + 'process.argv': [ + process.execPath, + process.argv[1], + '--usage', + '--scope=foo', + 'token', + 'revoke', + 'deadbeefcafebad', + ], + }) + const { npm } = await loadMockNpm(t) t.equal(npm.title, 'npm token revoke ***') t.equal(process.title, 'npm token revoke ***') }) t.test('do show *** unless a token is actually being revoked', async t => { - process.argv = [ - process.execPath, - process.argv[1], - '--usage', - '--scope=foo', - 'token', - 'revoke', - ] - const { Npm } = mockNpm(t) - const npm = new Npm() - await npm.load() + mockGlobals(t, { + 'process.argv': [ + process.execPath, + process.argv[1], + '--usage', + '--scope=foo', + 'token', + 'revoke', + ], + }) + const { npm } = await loadMockNpm(t) t.equal(npm.title, 'npm token revoke') t.equal(process.title, 'npm token revoke') }) }) -t.test('timings', t => { - const { Npm, logs } = mockNpm(t) - const npm = new Npm() - process.emit('time', 'foo') - process.emit('time', 'bar') - t.match(npm.timers.get('foo'), Number, 'foo timer is a number') - t.match(npm.timers.get('bar'), Number, 'foo timer is a number') - process.emit('timeEnd', 'foo') - process.emit('timeEnd', 'bar') - process.emit('timeEnd', 'baz') - t.match(logs, [ - ['timing', 'foo', /Completed in [0-9]+ms/], - ['timing', 'bar', /Completed in [0-9]+ms/], - [ - 'silly', +t.test('debug-log', async t => { + const { npm, debugFile } = await loadMockNpm(t, { load: false }) + + const log1 = ['silly', 'test', 'before load'] + const log2 = ['silly', 'test', 'after load'] + + process.emit('log', ...log1) + await npm.load() + process.emit('log', ...log2) + + const debug = await debugFile() + t.equal(npm.logFiles.length, 1, 'one debug file') + t.match(debug, log1.join(' '), 'before load appears') + t.match(debug, log2.join(' '), 'after load log appears') +}) + +t.test('timings', async t => { + t.test('gets/sets timers', async t => { + const { npm, logs } = await loadMockNpm(t, { load: false }) + process.emit('time', 'foo') + process.emit('time', 'bar') + t.match(npm.unfinishedTimers.get('foo'), Number, 'foo timer is a number') + t.match(npm.unfinishedTimers.get('bar'), Number, 'foo timer is a number') + process.emit('timeEnd', 'foo') + process.emit('timeEnd', 'bar') + process.emit('timeEnd', 'baz') + // npm timer is started by default + process.emit('timeEnd', 'npm') + t.match(logs.timing, [ + ['foo', /Completed in [0-9]+ms/], + ['bar', /Completed in [0-9]+ms/], + ['npm', /Completed in [0-9]+ms/], + ]) + t.match(logs.silly, [[ 'timing', "Tried to end timer that doesn't exist:", 'baz', - ], - ]) - t.notOk(npm.timers.has('foo'), 'foo timer is gone') - t.notOk(npm.timers.has('bar'), 'bar timer is gone') - t.match(npm.timings, { foo: Number, bar: Number }) - t.end() + ]]) + t.notOk(npm.unfinishedTimers.has('foo'), 'foo timer is gone') + t.notOk(npm.unfinishedTimers.has('bar'), 'bar timer is gone') + t.match(npm.finishedTimers, { foo: Number, bar: Number, npm: Number }) + t.end() + }) + + t.test('writes timings file', async t => { + const { npm, timingFile } = await loadMockNpm(t, { + config: { timing: true }, + }) + process.emit('time', 'foo') + process.emit('timeEnd', 'foo') + process.emit('time', 'bar') + npm.unload() + const timings = await timingFile() + t.match(timings, { + command: [], + logfile: String, + logfiles: [String], + version: String, + unfinished: { + bar: [Number, Number], + npm: [Number, Number], + }, + foo: Number, + 'npm:load': Number, + }) + }) + + t.test('does not write timings file with timers:false', async t => { + const { npm, timingFile } = await loadMockNpm(t, { + config: { false: true }, + }) + npm.unload() + await t.rejects(() => timingFile()) + }) }) -t.test('output clears progress and console.logs the message', t => { - const mock = mockNpm(t) - const { Npm, logs } = mock - const npm = new Npm() - npm.output = mock.npmOutput - const { log } = console - const { log: { clearProgress, showProgress } } = npm +t.test('output clears progress and console.logs the message', async t => { + t.plan(2) let showingProgress = true - npm.log.clearProgress = () => showingProgress = false - npm.log.showProgress = () => showingProgress = true - console.log = (...args) => { - t.equal(showingProgress, false, 'should not be showing progress right now') - logs.push(args) - } - t.teardown(() => { - console.log = log - npm.log.showProgress = showProgress - npm.log.clearProgress = clearProgress + const logs = [] + mockGlobals(t, { + 'console.log': (...args) => { + t.equal(showingProgress, false, 'should not be showing progress right now') + logs.push(args) + }, }) - - npm.output('hello') - t.strictSame(logs, [['hello']]) + const { npm } = await loadMockNpm(t, { + load: false, + mocks: { + npmlog: { + clearProgress: () => showingProgress = false, + showProgress: () => showingProgress = true, + }, + }, + }) + npm.originalOutput('hello') + t.match(logs, [['hello']]) t.end() }) t.test('unknown command', async t => { - const mock = mockNpm(t) - const { Npm } = mock - const npm = new Npm() + const { npm } = await loadMockNpm(t, { load: false }) await t.rejects( npm.cmd('thisisnotacommand'), { code: 'EUNKNOWNCOMMAND' } |