From 996248ceb8bd01d02ab7c012bd58db9e0694a618 Mon Sep 17 00:00:00 2001 From: Gar Date: Fri, 28 May 2021 09:23:49 -0700 Subject: [PATCH] fix(libnpmexec): don't detach output from npm The npm output function refers to this.log. libnpmexec has that passed in, which decoupled the function from the npm object. This fixes it, and sets the tests up in a way where if the output function ever becomes detached from this.npm in the same way, tests will fail. --- lib/exec.js | 2 +- lib/init.js | 2 +- tap-snapshots/test/lib/init.js.test.cjs | 6 +-- test/fixtures/mock-npm.js | 65 ++++++++++++++++--------- test/lib/exec.js | 22 ++++----- test/lib/init.js | 12 ++--- 6 files changed, 61 insertions(+), 48 deletions(-) diff --git a/lib/exec.js b/lib/exec.js index f30746b8c50ed..8a87615d9749e 100644 --- a/lib/exec.js +++ b/lib/exec.js @@ -76,8 +76,8 @@ class Exec extends BaseCommand { localBin, log, globalBin, - output, } = this.npm + const output = (...outputArgs) => this.npm.output(...outputArgs) const scriptShell = this.npm.config.get('script-shell') || undefined const packages = this.npm.config.get('package') const yes = this.npm.config.get('yes') diff --git a/lib/init.js b/lib/init.js index bc809a15e49a9..fbdf4e0845301 100644 --- a/lib/init.js +++ b/lib/init.js @@ -113,8 +113,8 @@ class Init extends BaseCommand { localBin, log, globalBin, - output, } = this.npm + const output = (...outputArgs) => this.npm.output(...outputArgs) const locationMsg = await getLocationMsg({ color, path }) const runPath = path const scriptShell = this.npm.config.get('script-shell') || undefined diff --git a/tap-snapshots/test/lib/init.js.test.cjs b/tap-snapshots/test/lib/init.js.test.cjs index 043d8b641dcce..0e599ab887f73 100644 --- a/tap-snapshots/test/lib/init.js.test.cjs +++ b/tap-snapshots/test/lib/init.js.test.cjs @@ -6,13 +6,13 @@ */ 'use strict' exports[`test/lib/init.js TAP workspaces no args > should print helper info 1`] = ` - +Array [] ` exports[`test/lib/init.js TAP workspaces no args, existing folder > should print helper info 1`] = ` - +Array [] ` exports[`test/lib/init.js TAP workspaces with arg but missing workspace folder > should print helper info 1`] = ` - +Array [] ` diff --git a/test/fixtures/mock-npm.js b/test/fixtures/mock-npm.js index aa8d44020ee36..c972c35b31861 100644 --- a/test/fixtures/mock-npm.js +++ b/test/fixtures/mock-npm.js @@ -4,35 +4,54 @@ const realConfig = require('../../lib/utils/config') -const mockLog = { - clearProgress: () => {}, - disableProgress: () => {}, - enableProgress: () => {}, - http: () => {}, - info: () => {}, - levels: [], - notice: () => {}, - pause: () => {}, - silly: () => {}, - verbose: () => {}, - warn: () => {}, -} -const mockNpm = (base = {}) => { - const config = base.config || {} - const flatOptions = base.flatOptions || {} - return { - log: mockLog, - ...base, - flatOptions, - config: { +class MockNpm { + constructor (base = {}) { + this._mockOutputs = [] + this.isMockNpm = true + this.base = base + + const config = base.config || {} + + for (const attr in base) { + if (attr !== 'config') { + this[attr] = base[attr] + } + } + + this.flatOptions = base.flatOptions || {} + this.config = { // for now just set `find` to what config.find should return // this works cause `find` is not an existing config entry find: (k) => ({...realConfig.defaults, ...config})[k], get: (k) => ({...realConfig.defaults, ...config})[k], set: (k, v) => config[k] = v, list: [{ ...realConfig.defaults, ...config}] - }, + } + if (!this.log) { + this.log = { + clearProgress: () => {}, + disableProgress: () => {}, + enableProgress: () => {}, + http: () => {}, + info: () => {}, + levels: [], + notice: () => {}, + pause: () => {}, + silly: () => {}, + verbose: () => {}, + warn: () => {}, + } + } + } + + output(...msg) { + if (this.base.output) + return this.base.output(msg) + this._mockOutputs.push(msg) } } -module.exports = mockNpm +// TODO export MockNpm, and change tests to use new MockNpm() +module.exports = (base = {}) => { + return new MockNpm(base) +} diff --git a/test/lib/exec.js b/test/lib/exec.js index 33e30e24f84e0..4f8cc02fce7bd 100644 --- a/test/lib/exec.js +++ b/test/lib/exec.js @@ -1,8 +1,6 @@ const t = require('tap') const mockNpm = require('../fixtures/mock-npm') const { resolve, delimiter } = require('path') -const OUTPUT = [] -const output = (...msg) => OUTPUT.push(msg) const ARB_CTOR = [] const ARB_ACTUAL_TREE = {} @@ -36,6 +34,7 @@ const config = { package: [], 'script-shell': 'shell-cmd', } + const npm = mockNpm({ flatOptions, config, @@ -53,7 +52,6 @@ const npm = mockNpm({ LOG_WARN.push(args) }, }, - output, }) const RUN_SCRIPTS = [] @@ -225,7 +223,7 @@ t.test('npm exec , run interactive shell', t => { ARB_CTOR.length = 0 MKDIRPS.length = 0 ARB_REIFY.length = 0 - OUTPUT.length = 0 + npm._mockOutputs.length = 0 exec.exec([], er => { if (er) throw er @@ -256,7 +254,7 @@ t.test('npm exec , run interactive shell', t => { process.stdin.isTTY = true run(t, true, () => { t.strictSame(LOG_WARN, []) - t.strictSame(OUTPUT, [ + t.strictSame(npm._mockOutputs, [ [`\nEntering npm script environment at location:\n${process.cwd()}\nType 'exit' or ^D when finished\n`], ], 'printed message about interactive shell') t.end() @@ -270,7 +268,7 @@ t.test('npm exec , run interactive shell', t => { run(t, true, () => { t.strictSame(LOG_WARN, []) - t.strictSame(OUTPUT, [ + t.strictSame(npm._mockOutputs, [ [`\u001b[0m\u001b[0m\n\u001b[0mEntering npm script environment\u001b[0m\u001b[0m at location:\u001b[0m\n\u001b[0m\u001b[2m${process.cwd()}\u001b[22m\u001b[0m\u001b[1m\u001b[22m\n\u001b[1mType 'exit' or ^D when finished\u001b[22m\n\u001b[1m\u001b[22m`], ], 'printed message about interactive shell') t.end() @@ -282,7 +280,7 @@ t.test('npm exec , run interactive shell', t => { process.stdin.isTTY = false run(t, true, () => { t.strictSame(LOG_WARN, []) - t.strictSame(OUTPUT, [], 'no message about interactive shell') + t.strictSame(npm._mockOutputs, [], 'no message about interactive shell') t.end() }) }) @@ -294,7 +292,7 @@ t.test('npm exec , run interactive shell', t => { t.strictSame(LOG_WARN, [ ['exec', 'Interactive mode disabled in CI environment'], ]) - t.strictSame(OUTPUT, [], 'no message about interactive shell') + t.strictSame(npm._mockOutputs, [], 'no message about interactive shell') t.end() }) }) @@ -316,7 +314,7 @@ t.test('npm exec , run interactive shell', t => { ARB_CTOR.length = 0 MKDIRPS.length = 0 ARB_REIFY.length = 0 - OUTPUT.length = 0 + npm._mockOutputs.length = 0 RUN_SCRIPTS.length = 0 t.end() }) @@ -1195,7 +1193,7 @@ t.test('workspaces', t => { return rej(er) t.strictSame(LOG_WARN, []) - t.strictSame(OUTPUT, [ + t.strictSame(npm._mockOutputs, [ [`\nEntering npm script environment in workspace a@1.0.0 at location:\n${resolve(npm.localPrefix, 'packages/a')}\nType 'exit' or ^D when finished\n`], ], 'printed message about interactive shell') res() @@ -1203,14 +1201,14 @@ t.test('workspaces', t => { }) config.color = true - OUTPUT.length = 0 + npm._mockOutputs.length = 0 await new Promise((res, rej) => { exec.execWorkspaces([], ['a'], er => { if (er) return rej(er) t.strictSame(LOG_WARN, []) - t.strictSame(OUTPUT, [ + t.strictSame(npm._mockOutputs, [ [`\u001b[0m\u001b[0m\n\u001b[0mEntering npm script environment\u001b[0m\u001b[0m in workspace \u001b[32ma@1.0.0\u001b[39m at location:\u001b[0m\n\u001b[0m\u001b[2m${resolve(npm.localPrefix, 'packages/a')}\u001b[22m\u001b[0m\u001b[1m\u001b[22m\n\u001b[1mType 'exit' or ^D when finished\u001b[22m\n\u001b[1m\u001b[22m`], ], 'printed message about interactive shell') res() diff --git a/test/lib/init.js b/test/lib/init.js index 0964bb5cedde6..72a6d96dae86d 100644 --- a/test/lib/init.js +++ b/test/lib/init.js @@ -3,7 +3,6 @@ const { resolve } = require('path') const t = require('tap') const mockNpm = require('../fixtures/mock-npm') -let result = '' const npmLog = { disableProgress: () => null, enableProgress: () => null, @@ -19,9 +18,6 @@ const config = { const npm = mockNpm({ config, log: npmLog, - output: (...msg) => { - result += msg.join('\n') - }, }) const mocks = { '../../lib/utils/usage.js': () => 'usage instructions', @@ -33,11 +29,11 @@ const _consolelog = console.log const noop = () => {} t.afterEach(() => { - result = '' config.yes = true config.package = undefined npm.log = npmLog process.chdir(_cwd) + npm._mockOutputs.length = 0 console.log = _consolelog }) @@ -340,7 +336,7 @@ t.test('workspaces', t => { if (err) throw err - t.matchSnapshot(result, 'should print helper info') + t.matchSnapshot(npm._mockOutputs, 'should print helper info') t.end() }) }) @@ -369,7 +365,7 @@ t.test('workspaces', t => { if (err) throw err - t.matchSnapshot(result, 'should print helper info') + t.matchSnapshot(npm._mockOutputs, 'should print helper info') t.end() }) }) @@ -401,7 +397,7 @@ t.test('workspaces', t => { if (err) throw err - t.matchSnapshot(result, 'should print helper info') + t.matchSnapshot(npm._mockOutputs, 'should print helper info') t.end() }) })